Fixed multiple issues on object browser upload (#1955)
- Fixed issue with double slashes on upload manager - Fixed sub folders not uploading in the correct subpaths location - Fixed an issue upload when a file is already selected - Fixed an issue with create path button with paths finished on slash - Simplified path handling for object browser Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -27,7 +27,7 @@ import {
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import { connect } from "react-redux";
|
||||
import history from "../../../../../../history";
|
||||
import { decodeFileName, encodeFileName } from "../../../../../../common/utils";
|
||||
import { encodeFileName } from "../../../../../../common/utils";
|
||||
import { setModalErrorSnackMessage } from "../../../../../../actions";
|
||||
import { BucketObjectItem } from "./types";
|
||||
import { CreateNewPathIcon } from "../../../../../../icons";
|
||||
@@ -40,8 +40,7 @@ interface ICreatePath {
|
||||
folderName: string;
|
||||
onClose: () => any;
|
||||
existingFiles: BucketObjectItem[];
|
||||
detailsOpen: boolean;
|
||||
selectedInternalPaths: string | null;
|
||||
simplePath: string | null;
|
||||
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
|
||||
}
|
||||
|
||||
@@ -59,53 +58,31 @@ const CreatePathModal = ({
|
||||
setModalErrorSnackMessage,
|
||||
classes,
|
||||
existingFiles,
|
||||
detailsOpen,
|
||||
selectedInternalPaths,
|
||||
simplePath,
|
||||
}: ICreatePath) => {
|
||||
const [pathUrl, setPathUrl] = useState("");
|
||||
const [isFormValid, setIsFormValid] = useState<boolean>(false);
|
||||
const [currentPath, setCurrentPath] = useState(bucketName);
|
||||
|
||||
let currentPath = `${bucketName}/${decodeFileName(folderName)}`;
|
||||
useEffect(() => {
|
||||
if(simplePath) {
|
||||
const newPath = `${bucketName}${
|
||||
!bucketName.endsWith("/") && !simplePath.startsWith("/") ? "/" : ""
|
||||
}${simplePath}`;
|
||||
|
||||
if (selectedInternalPaths && detailsOpen) {
|
||||
const decodedPathFileName = decodeFileName(selectedInternalPaths).split(
|
||||
"/"
|
||||
);
|
||||
|
||||
if (decodedPathFileName) {
|
||||
decodedPathFileName.pop();
|
||||
const joinFileName = decodedPathFileName.join("/");
|
||||
const joinPaths = `${joinFileName}${
|
||||
joinFileName.endsWith("/") ? "" : "/"
|
||||
}`;
|
||||
currentPath = `${bucketName}/${joinPaths}`;
|
||||
setCurrentPath(newPath);
|
||||
}
|
||||
}
|
||||
}, [simplePath, bucketName]);
|
||||
|
||||
const resetForm = () => {
|
||||
setPathUrl("");
|
||||
};
|
||||
|
||||
const createProcess = () => {
|
||||
let folderPath = "";
|
||||
let folderPath = "/";
|
||||
|
||||
if (selectedInternalPaths && detailsOpen) {
|
||||
const decodedPathFileName = decodeFileName(selectedInternalPaths).split(
|
||||
"/"
|
||||
);
|
||||
|
||||
if (decodedPathFileName) {
|
||||
decodedPathFileName.pop();
|
||||
const joinFileName = decodedPathFileName.join("/");
|
||||
folderPath = `${joinFileName}${joinFileName.endsWith("/") ? "" : "/"}`;
|
||||
}
|
||||
} else {
|
||||
if (folderName !== "") {
|
||||
const decodedFolderName = decodeFileName(folderName);
|
||||
folderPath = decodedFolderName.endsWith("/")
|
||||
? decodedFolderName
|
||||
: `${decodedFolderName}/`;
|
||||
}
|
||||
if (simplePath) {
|
||||
folderPath = simplePath.endsWith("/") ? simplePath : `${simplePath}/`;
|
||||
}
|
||||
|
||||
const sharesName = (record: BucketObjectItem) =>
|
||||
@@ -118,8 +95,14 @@ const CreatePathModal = ({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanPathURL = pathUrl
|
||||
.split("/")
|
||||
.filter((splitItem) => splitItem.trim() !== "")
|
||||
.join("/");
|
||||
|
||||
const newPath = `/buckets/${bucketName}/browse/${encodeFileName(
|
||||
`${folderPath}${pathUrl}/`
|
||||
`${folderPath}${cleanPathURL}/`
|
||||
)}`;
|
||||
history.push(newPath);
|
||||
onClose();
|
||||
@@ -205,8 +188,7 @@ const CreatePathModal = ({
|
||||
};
|
||||
|
||||
const mapStateToProps = ({ objectBrowser }: AppState) => ({
|
||||
detailsOpen: objectBrowser.objectDetailsOpen,
|
||||
selectedInternalPaths: objectBrowser.selectedInternalPaths,
|
||||
simplePath: objectBrowser.simplePath,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
||||
@@ -65,6 +65,7 @@ import {
|
||||
setSearchObjects,
|
||||
setSelectedObjectView,
|
||||
setShowDeletedObjects,
|
||||
setSimplePathHandler,
|
||||
setVersionsModeEnabled,
|
||||
updateProgress,
|
||||
} from "../../../../ObjectBrowser/actions";
|
||||
@@ -221,14 +222,15 @@ interface IListObjectsProps {
|
||||
searchObjects: string;
|
||||
showDeleted: boolean;
|
||||
loading: boolean;
|
||||
setSnackBarMessage: typeof setSnackBarMessage;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
resetRewind: typeof resetRewind;
|
||||
loadingBucket: boolean;
|
||||
setBucketInfo: typeof setBucketInfo;
|
||||
bucketInfo: BucketInfo | null;
|
||||
versionsMode: boolean;
|
||||
detailsOpen: boolean;
|
||||
simplePath: string | null;
|
||||
setSnackBarMessage: typeof setSnackBarMessage;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
resetRewind: typeof resetRewind;
|
||||
setBucketInfo: typeof setBucketInfo;
|
||||
setBucketDetailsLoad: typeof setBucketDetailsLoad;
|
||||
setNewObject: typeof setNewObject;
|
||||
updateProgress: typeof updateProgress;
|
||||
@@ -245,6 +247,7 @@ interface IListObjectsProps {
|
||||
setLoadingObjectsList: typeof setLoadingObjectsList;
|
||||
failObject: typeof failObject;
|
||||
cancelObjectInList: typeof cancelObjectInList;
|
||||
setSimplePathHandler: typeof setSimplePathHandler;
|
||||
}
|
||||
|
||||
function useInterval(callback: any, delay: number) {
|
||||
@@ -294,6 +297,7 @@ const ListObjects = ({
|
||||
searchObjects,
|
||||
versionsMode,
|
||||
openList,
|
||||
simplePath,
|
||||
setVersionsModeEnabled,
|
||||
showDeleted,
|
||||
detailsOpen,
|
||||
@@ -306,6 +310,7 @@ const ListObjects = ({
|
||||
setLoadingObjectsList,
|
||||
failObject,
|
||||
cancelObjectInList,
|
||||
setSimplePathHandler,
|
||||
}: IListObjectsProps) => {
|
||||
const [records, setRecords] = useState<BucketObjectItem[]>([]);
|
||||
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
|
||||
@@ -482,9 +487,9 @@ const ListObjects = ({
|
||||
const decodedIPaths = decodeFileName(internalPaths);
|
||||
|
||||
if (decodedIPaths.endsWith("/") || decodedIPaths === "") {
|
||||
setLoadingObjectsList(true);
|
||||
setObjectDetailsView(false);
|
||||
setSearchObjects("");
|
||||
setSelectedObjectView(null);
|
||||
setSimplePathHandler(decodedIPaths === "" ? "/" : decodedIPaths);
|
||||
} else {
|
||||
setLoadingObjectInfo(true);
|
||||
setObjectDetailsView(true);
|
||||
@@ -492,19 +497,27 @@ const ListObjects = ({
|
||||
setSelectedObjectView(
|
||||
`${decodedIPaths ? `${encodeFileName(decodedIPaths)}` : ``}`
|
||||
);
|
||||
setSimplePathHandler(
|
||||
`${decodedIPaths.split("/").slice(0, -1).join("/")}/`
|
||||
);
|
||||
}
|
||||
}, [
|
||||
internalPaths,
|
||||
setSearchObjects,
|
||||
rewindDate,
|
||||
rewindEnabled,
|
||||
setLoadingObjectInfo,
|
||||
setLoadingVersions,
|
||||
setObjectDetailsView,
|
||||
setSelectedObjectView,
|
||||
setLoadingObjectsList,
|
||||
setSimplePathHandler,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setSearchObjects("");
|
||||
setLoadingObjectsList(true);
|
||||
setSelectedObjects([]);
|
||||
}, [simplePath, setSearchObjects, setLoadingObjectsList, setSelectedObjects]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
if (displayListObjects) {
|
||||
@@ -795,11 +808,8 @@ const ListObjects = ({
|
||||
const uploadObject = useCallback(
|
||||
(files: File[], folderPath: string): void => {
|
||||
let pathPrefix = "";
|
||||
if (internalPaths) {
|
||||
const decodedPath = decodeFileName(internalPaths);
|
||||
pathPrefix = decodedPath.endsWith("/")
|
||||
? decodedPath
|
||||
: decodedPath + "/";
|
||||
if (simplePath) {
|
||||
pathPrefix = simplePath.endsWith("/") ? simplePath : simplePath + "/";
|
||||
}
|
||||
|
||||
const upload = (
|
||||
@@ -812,13 +822,23 @@ const ListObjects = ({
|
||||
return new Promise((resolve, reject) => {
|
||||
let uploadUrl = `api/v1/buckets/${bucketName}/objects/upload`;
|
||||
const fileName = file.name;
|
||||
|
||||
const blobFile = new Blob([file], { type: file.type });
|
||||
|
||||
let encodedPath = "";
|
||||
const relativeFolderPath =
|
||||
get(file, "webkitRelativePath", "") !== ""
|
||||
? get(file, "webkitRelativePath", "")
|
||||
: folderPath;
|
||||
|
||||
const filePath = get(file, "path", "");
|
||||
const fileWebkitRelativePath = get(file, "webkitRelativePath", "");
|
||||
|
||||
let relativeFolderPath = folderPath;
|
||||
|
||||
// File was uploaded via drag & drop
|
||||
if (filePath !== "") {
|
||||
relativeFolderPath = filePath;
|
||||
} else if (fileWebkitRelativePath !== "") {
|
||||
// File was uploaded using upload button
|
||||
relativeFolderPath = fileWebkitRelativePath;
|
||||
}
|
||||
|
||||
if (path !== "" || relativeFolderPath !== "") {
|
||||
const finalFolderPath = relativeFolderPath
|
||||
@@ -826,9 +846,20 @@ const ListObjects = ({
|
||||
.slice(0, -1)
|
||||
.join("/");
|
||||
|
||||
const pathClean = path.endsWith("/") ? path.slice(0, -1) : path;
|
||||
|
||||
encodedPath = encodeFileName(
|
||||
`${path}${finalFolderPath}${
|
||||
!finalFolderPath.endsWith("/") ? "/" : ""
|
||||
`${pathClean}${
|
||||
!pathClean.endsWith("/") &&
|
||||
finalFolderPath !== "" &&
|
||||
!finalFolderPath.startsWith("/")
|
||||
? "/"
|
||||
: ""
|
||||
}${finalFolderPath}${
|
||||
!finalFolderPath.endsWith("/") ||
|
||||
(finalFolderPath.trim() === "" && !path.endsWith("/"))
|
||||
? "/"
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
@@ -947,6 +978,7 @@ const ListObjects = ({
|
||||
}
|
||||
// We force objects list reload after all promises were handled
|
||||
setLoadingObjectsList(true);
|
||||
setSelectedObjects([]);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -955,7 +987,6 @@ const ListObjects = ({
|
||||
[
|
||||
bucketName,
|
||||
completeObject,
|
||||
internalPaths,
|
||||
openList,
|
||||
setNewObject,
|
||||
setErrorSnackMessage,
|
||||
@@ -963,6 +994,7 @@ const ListObjects = ({
|
||||
setLoadingObjectsList,
|
||||
cancelObjectInList,
|
||||
failObject,
|
||||
simplePath,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1502,6 +1534,7 @@ const mapStateToProps = ({ objectBrowser, buckets }: AppState) => ({
|
||||
detailsOpen: objectBrowser.objectDetailsOpen,
|
||||
selectedInternalPaths: objectBrowser.selectedInternalPaths,
|
||||
loading: objectBrowser.loadingObjects,
|
||||
simplePath: objectBrowser.simplePath,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
@@ -1524,6 +1557,7 @@ const mapDispatchToProps = {
|
||||
setLoadingObjectInfo,
|
||||
setLoadingObjectsList,
|
||||
cancelObjectInList,
|
||||
setSimplePathHandler,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
REWIND_RESET_REWIND,
|
||||
REWIND_SET_ENABLE,
|
||||
BUCKET_BROWSER_SET_SELECTED_OBJECT,
|
||||
BUCKET_BROWSER_SET_SIMPLE_PATH,
|
||||
IFileItem,
|
||||
} from "./types";
|
||||
|
||||
@@ -199,3 +200,10 @@ export const setSelectedObjectView = (object: string | null) => {
|
||||
object,
|
||||
};
|
||||
};
|
||||
|
||||
export const setSimplePathHandler = (path: string | null) => {
|
||||
return {
|
||||
type: BUCKET_BROWSER_SET_SIMPLE_PATH,
|
||||
path,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
OBJECT_MANAGER_SET_LOADING,
|
||||
OBJECT_MANAGER_ERROR_IN_OBJECT,
|
||||
OBJECT_MANAGER_CANCEL_OBJECT,
|
||||
BUCKET_BROWSER_SET_SIMPLE_PATH,
|
||||
} from "./types";
|
||||
|
||||
const defaultRewind = {
|
||||
@@ -67,6 +68,7 @@ const initialState: ObjectBrowserState = {
|
||||
selectedVersion: "",
|
||||
showDeleted: false,
|
||||
selectedInternalPaths: null,
|
||||
simplePath: null,
|
||||
};
|
||||
|
||||
export function objectBrowserReducer(
|
||||
@@ -295,12 +297,20 @@ export function objectBrowserReducer(
|
||||
return {
|
||||
...state,
|
||||
objectDetailsOpen: action.status,
|
||||
selectedInternalPaths: action.status
|
||||
? state.selectedInternalPaths
|
||||
: null,
|
||||
};
|
||||
case BUCKET_BROWSER_SET_SELECTED_OBJECT:
|
||||
return {
|
||||
...state,
|
||||
selectedInternalPaths: action.object,
|
||||
};
|
||||
case BUCKET_BROWSER_SET_SIMPLE_PATH:
|
||||
return {
|
||||
...state,
|
||||
simplePath: action.path,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ export const BUCKET_BROWSER_OBJECT_DETAILS_STATE =
|
||||
"BUCKET_BROWSER/OBJECT_DETAILS_STATE";
|
||||
export const BUCKET_BROWSER_SET_SELECTED_OBJECT =
|
||||
"BUCKET_BROWSER/SET_SELECTED_OBJECT";
|
||||
export const BUCKET_BROWSER_SET_SIMPLE_PATH =
|
||||
"BUCKET_BROWSER/SET_SIMPLE_PATH";
|
||||
|
||||
export interface Route {
|
||||
route: string;
|
||||
@@ -74,6 +76,7 @@ export interface ObjectBrowserState {
|
||||
showDeleted: boolean;
|
||||
objectDetailsOpen: boolean;
|
||||
selectedInternalPaths: string | null;
|
||||
simplePath: string | null;
|
||||
}
|
||||
|
||||
export interface ObjectBrowserReducer {
|
||||
@@ -209,6 +212,11 @@ interface CancelObjectInManager {
|
||||
instanceID: string;
|
||||
}
|
||||
|
||||
interface SetBrowserPath {
|
||||
type: typeof BUCKET_BROWSER_SET_SIMPLE_PATH;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export type ObjectBrowserActionTypes =
|
||||
| RewindSetEnabled
|
||||
| RewindReset
|
||||
@@ -231,4 +239,5 @@ export type ObjectBrowserActionTypes =
|
||||
| SetObjectDetailsState
|
||||
| SetSelectedObject
|
||||
| SetObjectManagerLoading
|
||||
| CancelObjectInManager;
|
||||
| CancelObjectInManager
|
||||
| SetBrowserPath;
|
||||
|
||||
Reference in New Issue
Block a user