,
+ hidden: false
+ },
+ {
+ title: "Toolbar Action",
+ key: "custom-tb-action",
+ onClick: handleCustomAction,
+ showToolbar: true,
+ showMenu: false,
+ multiple: false,
+ applyTo: [''],
+ icon:
,
+ hidden: false
+ },
+ ],
+ }}
files={files}
fileUploadConfig={fileUploadConfig}
isLoading={isLoading}
onCreateFolder={handleCreateFolder}
onFileUploading={handleFileUploading}
onFileUploaded={handleFileUploaded}
- onCut={handleCut}
- onCopy={handleCopy}
- onPaste={handlePaste}
- onRename={handleRename}
onDownload={handleDownload}
- onDelete={handleDelete}
onLayoutChange={handleLayoutChange}
onRefresh={handleRefresh}
onFileOpen={handleFileOpen}
diff --git a/frontend/src/FileManager/FileList/FileItem.jsx b/frontend/src/FileManager/FileList/FileItem.jsx
index 679dd10..75cb4fc 100644
--- a/frontend/src/FileManager/FileList/FileItem.jsx
+++ b/frontend/src/FileManager/FileList/FileItem.jsx
@@ -5,6 +5,7 @@ import CreateFolderAction from "../Actions/CreateFolder/CreateFolder.action";
import RenameAction from "../Actions/Rename/Rename.action";
import { getDataSize } from "../../utils/getDataSize";
import { formatDate } from "../../utils/formatDate";
+import { getActionByKey } from "../../utils/getActionByKey";
import { useFileNavigation } from "../../contexts/FileNavigationContext";
import { useSelection } from "../../contexts/SelectionContext";
import { useClipBoard } from "../../contexts/ClipboardContext";
@@ -16,10 +17,9 @@ const dragIconSize = 50;
const FileItem = ({
index,
file,
+ actions,
onCreateFolder,
- onRename,
enableFilePreview,
- onFileOpen,
filesViewRef,
selectedFileIndexes,
triggerAction,
@@ -46,7 +46,8 @@ const FileItem = ({
clipBoard.files.find((f) => f.name === file.name && f.path === file.path);
const handleFileAccess = () => {
- onFileOpen(file);
+ const openAction = getActionByKey(actions, "open");
+ openAction.onClick(file);
if (file.isDirectory) {
setCurrentPath(file.path);
setSelectedFiles([]);
@@ -234,7 +235,7 @@ const FileItem = ({
)}
diff --git a/frontend/src/FileManager/FileList/FileList.jsx b/frontend/src/FileManager/FileList/FileList.jsx
index bb2bc33..06177aa 100644
--- a/frontend/src/FileManager/FileList/FileList.jsx
+++ b/frontend/src/FileManager/FileList/FileList.jsx
@@ -10,11 +10,10 @@ import "./FileList.scss";
const FileList = ({
onCreateFolder,
- onRename,
- onFileOpen,
onRefresh,
enableFilePreview,
triggerAction,
+ actions
}) => {
const { currentPathFiles } = useFileNavigation();
const filesViewRef = useRef(null);
@@ -31,7 +30,7 @@ const FileList = ({
selectedFileIndexes,
clickPosition,
isSelectionCtx,
- } = useFileList(onRefresh, enableFilePreview, triggerAction);
+ } = useFileList(onRefresh, enableFilePreview, triggerAction, actions);
const contextMenuRef = useDetectOutsideClick(() => setVisible(false));
@@ -51,9 +50,8 @@ const FileList = ({
key={index}
index={index}
file={file}
+ actions={actions}
onCreateFolder={onCreateFolder}
- onRename={onRename}
- onFileOpen={onFileOpen}
enableFilePreview={enableFilePreview}
triggerAction={triggerAction}
filesViewRef={filesViewRef}
@@ -71,7 +69,7 @@ const FileList = ({
{
+const useFileList = (onRefresh, enableFilePreview, triggerAction, actions) => {
const [selectedFileIndexes, setSelectedFileIndexes] = useState([]);
const [visible, setVisible] = useState(false);
const [isSelectionCtx, setIsSelectionCtx] = useState(false);
@@ -25,8 +25,8 @@ const useFileList = (onRefresh, enableFilePreview, triggerAction) => {
useFileNavigation();
const { activeLayout, setActiveLayout } = useLayout();
- // Context Menu
const handleFileOpen = () => {
+ // Context Menu
if (lastSelectedFile.isDirectory) {
setCurrentPath(lastSelectedFile.path);
setSelectedFileIndexes([]);
@@ -133,51 +133,103 @@ const useFileList = (onRefresh, enableFilePreview, triggerAction) => {
},
];
- const selecCtxItems = [
- {
- title: "Open",
- icon: lastSelectedFile?.isDirectory ? : ,
- onClick: handleFileOpen,
- divider: true,
- },
- {
- title: "Cut",
- icon: ,
- onClick: () => handleMoveOrCopyItems(true),
- },
- {
- title: "Copy",
- icon: ,
- onClick: () => handleMoveOrCopyItems(false),
- divider: !lastSelectedFile?.isDirectory,
- },
- {
- title: "Paste",
- icon: ,
- onClick: handleFilePasting,
- className: `${clipBoard ? "" : "disable-paste"}`,
- hidden: !lastSelectedFile?.isDirectory,
- divider: true,
- },
- {
- title: "Rename",
- icon: ,
- onClick: handleRenaming,
- hidden: selectedFiles.length > 1,
- },
- {
- title: "Download",
- icon: ,
- onClick: handleDownloadItems,
- hidden: lastSelectedFile?.isDirectory,
- },
- {
- title: "Delete",
- icon: ,
- onClick: handleDelete,
- },
- ];
- //
+ const selecCtxItems = () => {
+ return actions
+ .filter((item) => item.showMenu)
+ .map((item) => {
+ switch (item.key) {
+ case "open": {
+ return {
+ ...item,
+ onClick: (args) => {
+ handleFileOpen(args);
+ item.onClick(args);
+ },
+ icon: item.icon || lastSelectedFile?.isDirectory ? : ,
+ divider: true,
+ }
+ }
+ case "cut": {
+ return {
+ ...item,
+ onClick: () => {
+ item.onClick();
+ handleMoveOrCopyItems(true);
+ },
+ icon: item.icon || ,
+ hidden: selectedFiles.length > 1,
+ }
+ }
+ case "copy": {
+ return {
+ ...item,
+ onClick: (args) => {
+ item.onClick(args);
+ handleMoveOrCopyItems(false);
+ },
+ icon: item.icon || ,
+ divider: !lastSelectedFile?.isDirectory,
+ }
+ }
+ case "paste": {
+ return {
+ ...item,
+ onClick: (args) => {
+ item.onClick(args);
+ handleFilePasting(args);
+ },
+ icon: item.icon || ,
+ className: `${clipBoard ? "" : "disable-paste"}`,
+ hidden: !lastSelectedFile?.isDirectory,
+ divider: !lastSelectedFile?.isDirectory,
+ }
+ }
+ case "rename": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: (args) => {
+ item.onClick(args);
+ handleRenaming(args);
+ },
+ hidden: selectedFiles.length > 1,
+ }
+ }
+ case "download": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: (args) => {
+ item.onClick(args);
+ handleDownloadItems(args);
+ },
+ hidden: lastSelectedFile?.isDirectory,
+ }
+ }
+ case "delete": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: () => {
+ item.onClick();
+ handleDelete();
+ },
+ hidden: lastSelectedFile?.isDirectory,
+ }
+ }
+ default: {
+ return {
+ ...item,
+ onClick: () => {
+ item.onClick(item.multiple ? selectedFiles : selectedFiles?.[0]);
+ setVisible(false);
+ },
+ hidden: item.hidden || (!item.multiple && selectedFiles.length > 1),
+ }
+ }
+ }
+ });
+}
const handleFolderCreating = () => {
setCurrentPathFiles((prev) => {
diff --git a/frontend/src/FileManager/FileManager.jsx b/frontend/src/FileManager/FileManager.jsx
index 1fca34e..c10f018 100644
--- a/frontend/src/FileManager/FileManager.jsx
+++ b/frontend/src/FileManager/FileManager.jsx
@@ -12,22 +12,78 @@ import { LayoutProvider } from "../contexts/LayoutContext";
import { useTriggerAction } from "../hooks/useTriggerAction";
import { useColumnResize } from "../hooks/useColumnResize";
import PropTypes from "prop-types";
+import { getActionByKey } from "../utils/getActionByKey";
import { dateStringValidator, urlValidator } from "../validators/propValidators";
import "./FileManager.scss";
+const defaultActions = [
+ {
+ title: "Open",
+ key: "open",
+ onClick: () => {},
+ showToolbar: false,
+ showMenu: true,
+ icon: null,
+ },
+ {
+ title: "Copy",
+ key: "copy",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: true,
+ icon: null,
+ },
+ {
+ title: "Cut",
+ key: "cut",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: false,
+ icon: null,
+ },
+ {
+ title: "Paste",
+ key: "paste",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: true,
+ icon: null,
+ },
+ {
+ title: "Rename",
+ key: "rename",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: true,
+ icon: null,
+ },
+ {
+ title: "Delete",
+ key: "delete",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: true,
+ icon: null,
+ },
+ {
+ title: "Download",
+ key: "download",
+ onClick: () => {},
+ showToolbar: true,
+ showMenu: true,
+ icon: null,
+ },
+];
+
const FileManager = ({
files,
+ config,
fileUploadConfig,
isLoading,
onCreateFolder,
onFileUploading = () => {},
onFileUploaded = () => {},
- onCut,
- onCopy,
- onPaste,
- onRename,
onDownload,
- onDelete = () => null,
onLayoutChange = () => {},
onRefresh,
onFileOpen = () => {},
@@ -55,18 +111,29 @@ const FileManager = ({
width,
};
+ const getActions = () => {
+ const resultActions = new Map(defaultActions.map(item => [item.key, item]));
+ if (config?.actions) {
+ config.actions.forEach(item =>
+ resultActions.set(item.key, { ...resultActions.get(item.key), ...item })
+ );
+ }
+ return [...resultActions.values()];
+ }
+
return (
e.preventDefault()} style={customStyles}>
-
+
@@ -87,9 +154,8 @@ const FileManager = ({
{
@@ -34,23 +35,107 @@ const Toolbar = ({
const toolbarLeftItems = [
{
icon: ,
- text: "New folder",
+ title: "New folder",
permission: allowCreateFolder,
onClick: () => triggerAction.show("createFolder"),
},
{
icon: ,
- text: "Upload",
+ title: "Upload",
permission: allowUploadFile,
onClick: () => triggerAction.show("uploadFile"),
},
{
icon: ,
- text: "Paste",
+ title: "Paste",
permission: !!clipBoard,
onClick: handleFilePasting,
},
];
+ const selectedToolbarActions = () => {
+ return actions
+ .filter((item) => item.showToolbar)
+ .map((item) => {
+ switch (item.key) {
+ case "cut": {
+ return {
+ ...item,
+ onClick: () => {
+ item.onClick();
+ handleCutCopy(true);
+ },
+ icon: item.icon || ,
+ hidden: selectedFiles.length > 1,
+ }
+ }
+ case "copy": {
+ return {
+ ...item,
+ onClick: (args) => {
+ item.onClick(args);
+ handleCutCopy(false);
+ },
+ icon: item.icon || ,
+ }
+ }
+ case "paste": {
+ return {
+ ...item,
+ onClick: (args) => {
+ item.onClick(args);
+ handleFilePasting(args);
+ },
+ icon: item.icon || ,
+ className: `${clipBoard ? "" : "disable-paste"}`,
+ hidden: clipBoard?.files?.length === 0,
+ }
+ }
+ case "rename": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: (args) => {
+ console.log(args);
+ item.onClick(args);
+ triggerAction.show("rename")
+ },
+ hidden: selectedFiles.length > 1,
+ }
+ }
+ case "download": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: (args) => {
+ item.onClick(args);
+ handleDownloadItems(args);
+ },
+ hidden: selectedFiles.isDirectory,
+ }
+ }
+ case "delete": {
+ return {
+ ...item,
+ icon: item.icon || ,
+ onClick: () => {
+ item.onClick();
+ triggerAction.show("delete")
+ },
+ hidden: selectedFiles.isDirectory,
+ }
+ }
+ default: {
+ return {
+ ...item,
+ onClick: () => {
+ item.onClick(item.multiple ? selectedFiles : selectedFiles?.[0]);
+ },
+ hidden: item.hidden || (!item.multiple && selectedFiles.length > 1),
+ }
+ }
+ }
+ });
+ }
const toolbarRightItems = [
{
@@ -83,10 +168,14 @@ const Toolbar = ({
-
+ {selectedToolbarActions().map((item) => (
+
+ ))}
+ {/*
- )}
-
+ */}
diff --git a/frontend/src/contexts/ClipboardContext.jsx b/frontend/src/contexts/ClipboardContext.jsx
index 24e2792..e7a1d4a 100644
--- a/frontend/src/contexts/ClipboardContext.jsx
+++ b/frontend/src/contexts/ClipboardContext.jsx
@@ -1,10 +1,11 @@
import { createContext, useContext, useState } from "react";
import { useSelection } from "./SelectionContext";
import { validateApiCallback } from "../utils/validateApiCallback";
+import { getActionByKey } from "../utils/getActionByKey";
const ClipBoardContext = createContext();
-export const ClipBoardProvider = ({ children, onPaste, onCut, onCopy }) => {
+export const ClipBoardProvider = ({ children, actions }) => {
const [clipBoard, setClipBoard] = useState(null);
const { selectedFiles, setSelectedFiles } = useSelection();
@@ -15,8 +16,10 @@ export const ClipBoardProvider = ({ children, onPaste, onCut, onCopy }) => {
});
if (isMoving) {
+ const onCut = getActionByKey(actions, "cut").onClick;
!!onCut && onCut(selectedFiles);
} else {
+ const onCopy = getActionByKey(actions, "copy").onClick;
!!onCopy && onCopy(selectedFiles);
}
};
@@ -27,6 +30,7 @@ export const ClipBoardProvider = ({ children, onPaste, onCut, onCopy }) => {
const copiedFiles = clipBoard.files;
const operationType = clipBoard.isMoving ? "move" : "copy";
+ const onPaste = getActionByKey(actions, "paste").onClick;
validateApiCallback(onPaste, "onPaste", copiedFiles, destinationFolder, operationType);
diff --git a/frontend/src/utils/getActionByKey.js b/frontend/src/utils/getActionByKey.js
new file mode 100644
index 0000000..bd8903a
--- /dev/null
+++ b/frontend/src/utils/getActionByKey.js
@@ -0,0 +1,2 @@
+export const getActionByKey = (actions, key) =>
+ actions.find((item) => item.key === key);
\ No newline at end of file