mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-08 02:10:24 +00:00
refactor: metadata op api
This commit is contained in:
@@ -4,9 +4,12 @@ import toaster from '../../components/toast';
|
|||||||
import Context from '../context';
|
import Context from '../context';
|
||||||
import Store from '../store';
|
import Store from '../store';
|
||||||
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER } from '../constants';
|
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER } from '../constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils, validateName } from '../../utils/utils';
|
||||||
import { useMetadata } from './metadata';
|
import { useMetadata } from './metadata';
|
||||||
import { useCollaborators } from './collaborators';
|
import { useCollaborators } from './collaborators';
|
||||||
|
import { getRowById } from '../utils/table';
|
||||||
|
import { getFileNameFromRecord, getParentDirFromRecord } from '../utils/cell';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
|
||||||
const MetadataViewContext = React.createContext(null);
|
const MetadataViewContext = React.createContext(null);
|
||||||
|
|
||||||
@@ -14,6 +17,8 @@ export const MetadataViewProvider = ({
|
|||||||
children,
|
children,
|
||||||
repoID,
|
repoID,
|
||||||
viewID,
|
viewID,
|
||||||
|
renameFileCallback,
|
||||||
|
deleteFilesCallback,
|
||||||
...params
|
...params
|
||||||
}) => {
|
}) => {
|
||||||
const [isLoading, setLoading] = useState(true);
|
const [isLoading, setLoading] = useState(true);
|
||||||
@@ -48,32 +53,142 @@ export const MetadataViewProvider = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const modifyFilters = useCallback((filters, filterConjunction, basicFilters) => {
|
const modifyFilters = useCallback((filters, filterConjunction, basicFilters) => {
|
||||||
window.sfMetadataStore.modifyFilters(filterConjunction, filters, basicFilters);
|
storeRef.current.modifyFilters(filterConjunction, filters, basicFilters);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
const modifySorts = useCallback((sorts, displaySorts = false) => {
|
const modifySorts = useCallback((sorts, displaySorts = false) => {
|
||||||
window.sfMetadataStore.modifySorts(sorts, displaySorts);
|
storeRef.current.modifySorts(sorts, displaySorts);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
const modifyGroupbys = useCallback((groupbys) => {
|
const modifyGroupbys = useCallback((groupbys) => {
|
||||||
window.sfMetadataStore.modifyGroupbys(groupbys);
|
storeRef.current.modifyGroupbys(groupbys);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
const modifyHiddenColumns = useCallback((hiddenColumns) => {
|
const modifyHiddenColumns = useCallback((hiddenColumns) => {
|
||||||
window.sfMetadataStore.modifyHiddenColumns(hiddenColumns);
|
storeRef.current.modifyHiddenColumns(hiddenColumns);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
|
||||||
window.sfMetadataStore.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const modifySettings = useCallback((settings) => {
|
const modifySettings = useCallback((settings) => {
|
||||||
window.sfMetadataStore.modifySettings(settings);
|
storeRef.current.modifySettings(settings);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
const updateLocalRecord = useCallback((recordId, update) => {
|
const updateLocalRecord = useCallback((recordId, update) => {
|
||||||
window.sfMetadataStore.modifyLocalRecord(recordId, update);
|
storeRef.current.modifyLocalRecord(recordId, update);
|
||||||
}, []);
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const modifyRecords = (rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste = false, { success_callback, fail_callback } = {}) => {
|
||||||
|
const isRename = storeRef.current.checkIsRenameFileOperator(rowIds, idOriginalRowUpdates);
|
||||||
|
let newName = null;
|
||||||
|
if (isRename) {
|
||||||
|
const rowId = rowIds[0];
|
||||||
|
const row = getRowById(metadata, rowId);
|
||||||
|
const rowUpdates = idOriginalRowUpdates[rowId];
|
||||||
|
const { _parent_dir, _name } = row;
|
||||||
|
newName = getFileNameFromRecord(rowUpdates);
|
||||||
|
const { isValid, errMessage } = validateName(newName);
|
||||||
|
if (!isValid) {
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newName === _name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (storeRef.current.checkDuplicatedName(newName, _parent_dir)) {
|
||||||
|
let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.');
|
||||||
|
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storeRef.current.modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste, isRename, {
|
||||||
|
fail_callback: (error) => {
|
||||||
|
fail_callback && fail_callback(error);
|
||||||
|
error && toaster.danger(error);
|
||||||
|
},
|
||||||
|
success_callback: (operation) => {
|
||||||
|
if (operation.is_rename) {
|
||||||
|
const rowId = operation.row_ids[0];
|
||||||
|
const row = getRowById(metadata, rowId);
|
||||||
|
const rowUpdates = operation.id_original_row_updates[rowId];
|
||||||
|
const oldRow = operation.id_original_old_row_data[rowId];
|
||||||
|
const parentDir = getParentDirFromRecord(row);
|
||||||
|
const oldName = getFileNameFromRecord(oldRow);
|
||||||
|
const path = Utils.joinPath(parentDir, oldName);
|
||||||
|
const newName = getFileNameFromRecord(rowUpdates);
|
||||||
|
renameFileCallback(path, newName);
|
||||||
|
}
|
||||||
|
success_callback && success_callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteRecords = (recordsIds, { success_callback, fail_callback } = {}) => {
|
||||||
|
if (!Array.isArray(recordsIds) || recordsIds.length === 0) return;
|
||||||
|
let paths = [];
|
||||||
|
let fileNames = [];
|
||||||
|
recordsIds.forEach((recordId) => {
|
||||||
|
const record = getRowById(metadata, recordId);
|
||||||
|
const { _parent_dir, _name } = record || {};
|
||||||
|
if (_parent_dir && _name) {
|
||||||
|
const path = Utils.joinPath(_parent_dir, _name);
|
||||||
|
paths.push(path);
|
||||||
|
fileNames.push(_name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
storeRef.current.deleteRecords(recordsIds, {
|
||||||
|
fail_callback: (error) => {
|
||||||
|
fail_callback && fail_callback(error);
|
||||||
|
error && toaster.danger(error);
|
||||||
|
},
|
||||||
|
success_callback: () => {
|
||||||
|
deleteFilesCallback(paths, fileNames);
|
||||||
|
let msg = fileNames.length > 1
|
||||||
|
? gettext('Successfully deleted {name} and {n} other items')
|
||||||
|
: gettext('Successfully deleted {name}');
|
||||||
|
msg = msg.replace('{name}', fileNames[0])
|
||||||
|
.replace('{n}', fileNames.length - 1);
|
||||||
|
toaster.success(msg);
|
||||||
|
success_callback && success_callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const modifyRecord = (rowId, updates, oldRowData, originalUpdates, originalOldRowData, isCopyPaste, { success_callback, fail_callback } = {}) => {
|
||||||
|
const rowIds = [rowId];
|
||||||
|
const idRowUpdates = { [rowId]: updates };
|
||||||
|
const idOriginalRowUpdates = { [rowId]: originalUpdates };
|
||||||
|
const idOldRowData = { [rowId]: oldRowData };
|
||||||
|
const idOriginalOldRowData = { [rowId]: originalOldRowData };
|
||||||
|
modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste, { success_callback, fail_callback });
|
||||||
|
};
|
||||||
|
|
||||||
|
const renameColumn = useCallback((columnKey, newName, oldName) => {
|
||||||
|
storeRef.current.renameColumn(columnKey, newName, oldName);
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const deleteColumn = useCallback((columnKey, oldColumn) => {
|
||||||
|
storeRef.current.deleteColumn(columnKey, oldColumn);
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const modifyColumnData = useCallback((columnKey, newData, oldData, { optionModifyType } = {}) => {
|
||||||
|
storeRef.current.modifyColumnData(columnKey, newData, oldData, { optionModifyType });
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const modifyColumnWidth = useCallback((columnKey, newWidth) => {
|
||||||
|
storeRef.current.modifyColumnWidth(columnKey, newWidth);
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
||||||
|
storeRef.current.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const insertColumn = useCallback((name, type, { key, data }) => {
|
||||||
|
storeRef.current.insertColumn(name, type, { key, data });
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
|
const updateFileTags = useCallback((data) => {
|
||||||
|
storeRef.current.updateFileTags(data);
|
||||||
|
}, [storeRef]);
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,11 +252,22 @@ export const MetadataViewProvider = ({
|
|||||||
metadata,
|
metadata,
|
||||||
store: storeRef.current,
|
store: storeRef.current,
|
||||||
isDirentDetailShow: params.isDirentDetailShow,
|
isDirentDetailShow: params.isDirentDetailShow,
|
||||||
deleteFilesCallback: params.deleteFilesCallback,
|
|
||||||
renameFileCallback: params.renameFileCallback,
|
|
||||||
updateCurrentDirent: params.updateCurrentDirent,
|
updateCurrentDirent: params.updateCurrentDirent,
|
||||||
closeDirentDetail: params.closeDirentDetail,
|
closeDirentDetail: params.closeDirentDetail,
|
||||||
showDirentDetail: params.showDirentDetail,
|
showDirentDetail: params.showDirentDetail,
|
||||||
|
deleteFilesCallback: deleteFilesCallback,
|
||||||
|
renameFileCallback: renameFileCallback,
|
||||||
|
modifySettings,
|
||||||
|
modifyRecords,
|
||||||
|
deleteRecords,
|
||||||
|
modifyRecord,
|
||||||
|
renameColumn,
|
||||||
|
deleteColumn,
|
||||||
|
modifyColumnOrder,
|
||||||
|
modifyColumnData,
|
||||||
|
modifyColumnWidth,
|
||||||
|
insertColumn,
|
||||||
|
updateFileTags,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@@ -73,7 +73,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
|
|||||||
onDeletePeoplePhotos && onDeletePeoplePhotos(people._id, ids);
|
onDeletePeoplePhotos && onDeletePeoplePhotos(people._id, ids);
|
||||||
}, [metadata, onClose, people, onDeletePeoplePhotos]);
|
}, [metadata, onClose, people, onDeletePeoplePhotos]);
|
||||||
|
|
||||||
const handelDelete = useCallback((deletedImages, callback) => {
|
const handelDelete = useCallback((deletedImages, { success_callback } = {}) => {
|
||||||
if (!deletedImages.length) return;
|
if (!deletedImages.length) return;
|
||||||
let recordIds = [];
|
let recordIds = [];
|
||||||
let paths = [];
|
let paths = [];
|
||||||
@@ -88,7 +88,6 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.sfMetadataContext.batchDeleteFiles(repoID, paths).then(res => {
|
window.sfMetadataContext.batchDeleteFiles(repoID, paths).then(res => {
|
||||||
callback && callback();
|
|
||||||
deletedByIds(recordIds);
|
deletedByIds(recordIds);
|
||||||
deleteFilesCallback(paths, fileNames);
|
deleteFilesCallback(paths, fileNames);
|
||||||
let msg = fileNames.length > 1
|
let msg = fileNames.length > 1
|
||||||
@@ -97,6 +96,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
|
|||||||
msg = msg.replace('{name}', fileNames[0])
|
msg = msg.replace('{name}', fileNames[0])
|
||||||
.replace('{n}', fileNames.length - 1);
|
.replace('{n}', fileNames.length - 1);
|
||||||
toaster.success(msg);
|
toaster.success(msg);
|
||||||
|
success_callback && success_callback();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
toaster.danger(gettext('Failed to delete records'));
|
toaster.danger(gettext('Failed to delete records'));
|
||||||
});
|
});
|
||||||
|
@@ -3,7 +3,6 @@ import toaster from '../../../components/toast';
|
|||||||
import Main from './main';
|
import Main from './main';
|
||||||
import { useMetadataView } from '../../hooks/metadata-view';
|
import { useMetadataView } from '../../hooks/metadata-view';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import { gettext } from '../../../utils/constants';
|
|
||||||
import { PER_LOAD_NUMBER } from '../../constants';
|
import { PER_LOAD_NUMBER } from '../../constants';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
@@ -11,7 +10,7 @@ import './index.css';
|
|||||||
const Gallery = () => {
|
const Gallery = () => {
|
||||||
const [isLoadingMore, setLoadingMore] = useState(false);
|
const [isLoadingMore, setLoadingMore] = useState(false);
|
||||||
|
|
||||||
const { metadata, store, deleteFilesCallback } = useMetadataView();
|
const { metadata, store, deleteRecords } = useMetadataView();
|
||||||
|
|
||||||
const onLoadMore = useCallback(async () => {
|
const onLoadMore = useCallback(async () => {
|
||||||
if (isLoadingMore) return;
|
if (isLoadingMore) return;
|
||||||
@@ -30,36 +29,17 @@ const Gallery = () => {
|
|||||||
|
|
||||||
}, [isLoadingMore, metadata, store]);
|
}, [isLoadingMore, metadata, store]);
|
||||||
|
|
||||||
const handleDelete = useCallback((deletedImages, callback) => {
|
const handleDelete = useCallback((deletedImages, { success_callback } = {}) => {
|
||||||
if (!deletedImages.length) return;
|
if (!deletedImages.length) return;
|
||||||
let recordsIds = [];
|
let recordsIds = [];
|
||||||
let paths = [];
|
|
||||||
let fileNames = [];
|
|
||||||
deletedImages.forEach((record) => {
|
deletedImages.forEach((record) => {
|
||||||
const { path: parentDir, name } = record || {};
|
const { path: parentDir, name } = record || {};
|
||||||
if (parentDir && name) {
|
if (parentDir && name) {
|
||||||
const path = Utils.joinPath(parentDir, name);
|
|
||||||
recordsIds.push(record.id);
|
recordsIds.push(record.id);
|
||||||
paths.push(path);
|
|
||||||
fileNames.push(name);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
store.deleteRecords(recordsIds, {
|
deleteRecords(recordsIds, { success_callback });
|
||||||
fail_callback: (error) => {
|
}, [deleteRecords]);
|
||||||
toaster.danger(error);
|
|
||||||
},
|
|
||||||
success_callback: () => {
|
|
||||||
callback && callback();
|
|
||||||
deleteFilesCallback(paths, fileNames);
|
|
||||||
let msg = fileNames.length > 1
|
|
||||||
? gettext('Successfully deleted {name} and {n} other items')
|
|
||||||
: gettext('Successfully deleted {name}');
|
|
||||||
msg = msg.replace('{name}', fileNames[0])
|
|
||||||
.replace('{n}', fileNames.length - 1);
|
|
||||||
toaster.success(msg);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, [store, deleteFilesCallback]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sf-metadata-container">
|
<div className="sf-metadata-container">
|
||||||
|
@@ -292,9 +292,11 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore }) => {
|
|||||||
|
|
||||||
const handleDeleteSelectedImages = useCallback((selectedImages) => {
|
const handleDeleteSelectedImages = useCallback((selectedImages) => {
|
||||||
if (!selectedImages.length) return;
|
if (!selectedImages.length) return;
|
||||||
onDelete(selectedImages, () => {
|
onDelete(selectedImages, {
|
||||||
updateCurrentDirent();
|
success_callback: () => {
|
||||||
setSelectedImages([]);
|
updateCurrentDirent();
|
||||||
|
setSelectedImages([]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, [onDelete, updateCurrentDirent]);
|
}, [onDelete, updateCurrentDirent]);
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@ import EmptyTip from '../../../../components/empty-tip';
|
|||||||
import Board from './board';
|
import Board from './board';
|
||||||
import ImagePreviewer from '../../../components/cell-formatter/image-previewer';
|
import ImagePreviewer from '../../../components/cell-formatter/image-previewer';
|
||||||
import ContextMenu from '../context-menu';
|
import ContextMenu from '../context-menu';
|
||||||
|
import { getRowById } from '../../../utils/table';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -192,9 +193,9 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings
|
|||||||
setImagePreviewerVisible(false);
|
setImagePreviewerVisible(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSelectCard = useCallback((record) => {
|
const handelUpdateCurrentDirent = useCallback((record) => {
|
||||||
|
if (!record) return;
|
||||||
const recordId = getRecordIdFromRecord(record);
|
const recordId = getRecordIdFromRecord(record);
|
||||||
if (selectedCard === recordId) return;
|
|
||||||
const name = getFileNameFromRecord(record);
|
const name = getFileNameFromRecord(record);
|
||||||
const path = getParentDirFromRecord(record);
|
const path = getParentDirFromRecord(record);
|
||||||
const isDir = checkIsDir(record);
|
const isDir = checkIsDir(record);
|
||||||
@@ -206,9 +207,15 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings
|
|||||||
file_tags: []
|
file_tags: []
|
||||||
});
|
});
|
||||||
setSelectedCard(recordId);
|
setSelectedCard(recordId);
|
||||||
|
}, [updateCurrentDirent]);
|
||||||
|
|
||||||
|
const onSelectCard = useCallback((record) => {
|
||||||
|
const recordId = getRecordIdFromRecord(record);
|
||||||
|
if (selectedCard === recordId) return;
|
||||||
|
handelUpdateCurrentDirent(record);
|
||||||
onCloseSettings();
|
onCloseSettings();
|
||||||
showDirentDetail();
|
showDirentDetail();
|
||||||
}, [selectedCard, onCloseSettings, showDirentDetail, updateCurrentDirent]);
|
}, [selectedCard, onCloseSettings, showDirentDetail, handelUpdateCurrentDirent]);
|
||||||
|
|
||||||
const handleClickOutside = useCallback((event) => {
|
const handleClickOutside = useCallback((event) => {
|
||||||
if (isDragging) return;
|
if (isDragging) return;
|
||||||
@@ -222,8 +229,10 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings
|
|||||||
|
|
||||||
const onContextMenu = useCallback((event, recordId) => {
|
const onContextMenu = useCallback((event, recordId) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setSelectedCard(recordId);
|
if (selectedCard === recordId) return;
|
||||||
}, []);
|
const record = getRowById(metadata, recordId);
|
||||||
|
handelUpdateCurrentDirent(record);
|
||||||
|
}, [metadata, selectedCard, handelUpdateCurrentDirent]);
|
||||||
|
|
||||||
const onDeleteRecords = useCallback((recordIds) => {
|
const onDeleteRecords = useCallback((recordIds) => {
|
||||||
deleteRecords(recordIds, {
|
deleteRecords(recordIds, {
|
||||||
|
@@ -1,112 +1,31 @@
|
|||||||
import React, { useState, useMemo, useEffect, useCallback } from 'react';
|
import React, { useState, useMemo, useEffect, useCallback } from 'react';
|
||||||
import { useMetadataView } from '../../hooks/metadata-view';
|
import { useMetadataView } from '../../hooks/metadata-view';
|
||||||
import { EVENT_BUS_TYPE } from '../../constants';
|
import { EVENT_BUS_TYPE } from '../../constants';
|
||||||
import toaster from '../../../components/toast';
|
|
||||||
import Boards from './boards';
|
import Boards from './boards';
|
||||||
import Settings from './settings';
|
import Settings from './settings';
|
||||||
import { getRowById } from '../../utils/table';
|
|
||||||
import { getFileNameFromRecord, getParentDirFromRecord } from '../../utils/cell';
|
|
||||||
import { Utils, validateName } from '../../../utils/utils';
|
|
||||||
import { gettext } from '../../../utils/constants';
|
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const Kanban = () => {
|
const Kanban = () => {
|
||||||
const [isShowSettings, setShowSettings] = useState(false);
|
const [isShowSettings, setShowSettings] = useState(false);
|
||||||
|
|
||||||
const { metadata, store, renameFileCallback, deleteFilesCallback } = useMetadataView();
|
const {
|
||||||
|
metadata,
|
||||||
|
modifySettings,
|
||||||
|
modifyRecord: modifyRecordAPI,
|
||||||
|
deleteRecords,
|
||||||
|
modifyColumnData,
|
||||||
|
} = useMetadataView();
|
||||||
|
|
||||||
const columns = useMemo(() => metadata.view.columns, [metadata.view.columns]);
|
const columns = useMemo(() => metadata.view.columns, [metadata.view.columns]);
|
||||||
|
|
||||||
const modifyRecord = useCallback((rowId, updates, oldRowData, originalUpdates, originalOldRowData, { success_callback }) => {
|
const modifyRecord = useCallback((rowId, updates, oldRowData, originalUpdates, originalOldRowData, { success_callback } = {}) => {
|
||||||
const rowIds = [rowId];
|
modifyRecordAPI(rowId, updates, oldRowData, originalUpdates, originalOldRowData, false, { success_callback: () => {
|
||||||
const idRowUpdates = { [rowId]: updates };
|
success_callback && success_callback();
|
||||||
const idOriginalRowUpdates = { [rowId]: originalUpdates };
|
const eventBus = window.sfMetadataContext.eventBus;
|
||||||
const idOldRowData = { [rowId]: oldRowData };
|
eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_DETAIL_CHANGED, rowId, updates);
|
||||||
const idOriginalOldRowData = { [rowId]: originalOldRowData };
|
} });
|
||||||
const isRename = store.checkIsRenameFileOperator(rowIds, idOriginalRowUpdates);
|
}, [modifyRecordAPI]);
|
||||||
let newName = null;
|
|
||||||
if (isRename) {
|
|
||||||
const rowId = rowIds[0];
|
|
||||||
const row = getRowById(metadata, rowId);
|
|
||||||
const rowUpdates = idOriginalRowUpdates[rowId];
|
|
||||||
const { _parent_dir, _name } = row;
|
|
||||||
newName = getFileNameFromRecord(rowUpdates);
|
|
||||||
const { isValid, errMessage } = validateName(newName);
|
|
||||||
if (!isValid) {
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (newName === _name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (store.checkDuplicatedName(newName, _parent_dir)) {
|
|
||||||
let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.');
|
|
||||||
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store.modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, false, isRename, {
|
|
||||||
fail_callback: (error) => {
|
|
||||||
error && toaster.danger(error);
|
|
||||||
},
|
|
||||||
success_callback: (operation) => {
|
|
||||||
if (operation.is_rename) {
|
|
||||||
const rowId = operation.row_ids[0];
|
|
||||||
const row = getRowById(metadata, rowId);
|
|
||||||
const rowUpdates = operation.id_original_row_updates[rowId];
|
|
||||||
const oldRow = operation.id_original_old_row_data[rowId];
|
|
||||||
const parentDir = getParentDirFromRecord(row);
|
|
||||||
const oldName = getFileNameFromRecord(oldRow);
|
|
||||||
const path = Utils.joinPath(parentDir, oldName);
|
|
||||||
const newName = getFileNameFromRecord(rowUpdates);
|
|
||||||
renameFileCallback(path, newName);
|
|
||||||
success_callback && success_callback();
|
|
||||||
}
|
|
||||||
const eventBus = window.sfMetadataContext.eventBus;
|
|
||||||
eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_DETAIL_CHANGED, rowId, updates);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, [store, metadata, renameFileCallback]);
|
|
||||||
|
|
||||||
const deleteRecords = useCallback((recordsIds, { success_callback }) => {
|
|
||||||
if (!Array.isArray(recordsIds) || recordsIds.length === 0) return;
|
|
||||||
let paths = [];
|
|
||||||
let fileNames = [];
|
|
||||||
recordsIds.forEach((recordId) => {
|
|
||||||
const record = getRowById(metadata, recordId);
|
|
||||||
const { _parent_dir, _name } = record || {};
|
|
||||||
if (_parent_dir && _name) {
|
|
||||||
const path = Utils.joinPath(_parent_dir, _name);
|
|
||||||
paths.push(path);
|
|
||||||
fileNames.push(_name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
store.deleteRecords(recordsIds, {
|
|
||||||
fail_callback: (error) => {
|
|
||||||
toaster.danger(error);
|
|
||||||
},
|
|
||||||
success_callback: () => {
|
|
||||||
deleteFilesCallback(paths, fileNames);
|
|
||||||
let msg = fileNames.length > 1
|
|
||||||
? gettext('Successfully deleted {name} and {n} other items')
|
|
||||||
: gettext('Successfully deleted {name}');
|
|
||||||
msg = msg.replace('{name}', fileNames[0])
|
|
||||||
.replace('{n}', fileNames.length - 1);
|
|
||||||
toaster.success(msg);
|
|
||||||
success_callback && success_callback();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, [metadata, store, deleteFilesCallback]);
|
|
||||||
|
|
||||||
const modifySettings = useCallback((newSettings) => {
|
|
||||||
store.modifySettings(newSettings);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const modifyColumnData = useCallback((columnKey, newData, oldData, { optionModifyType } = {}) => {
|
|
||||||
store.modifyColumnData(columnKey, newData, oldData, { optionModifyType });
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const closeSettings = useCallback(() => {
|
const closeSettings = useCallback(() => {
|
||||||
setShowSettings(false);
|
setShowSettings(false);
|
||||||
|
@@ -3,10 +3,8 @@ import { toKeyCode } from 'is-hotkey';
|
|||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
import TableMain from './table-main';
|
import TableMain from './table-main';
|
||||||
import { useMetadataView } from '../../hooks/metadata-view';
|
import { useMetadataView } from '../../hooks/metadata-view';
|
||||||
import { Utils, validateName } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import { isModZ, isModShiftZ } from '../../utils/hotkey';
|
import { isModZ, isModShiftZ } from '../../utils/hotkey';
|
||||||
import { gettext } from '../../../utils/constants';
|
|
||||||
import { getFileNameFromRecord, getParentDirFromRecord } from '../../utils/cell';
|
|
||||||
import { getValidGroupbys } from '../../utils/group';
|
import { getValidGroupbys } from '../../utils/group';
|
||||||
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, MAX_LOAD_NUMBER } from '../../constants';
|
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, MAX_LOAD_NUMBER } from '../../constants';
|
||||||
|
|
||||||
@@ -14,7 +12,21 @@ import './index.css';
|
|||||||
|
|
||||||
const Table = () => {
|
const Table = () => {
|
||||||
const [isLoadingMore, setLoadingMore] = useState(false);
|
const [isLoadingMore, setLoadingMore] = useState(false);
|
||||||
const { isLoading, metadata, store, renameFileCallback, deleteFilesCallback } = useMetadataView();
|
const {
|
||||||
|
isLoading,
|
||||||
|
metadata,
|
||||||
|
store,
|
||||||
|
modifyRecords,
|
||||||
|
deleteRecords,
|
||||||
|
modifyRecord,
|
||||||
|
renameColumn,
|
||||||
|
deleteColumn,
|
||||||
|
modifyColumnData,
|
||||||
|
modifyColumnOrder,
|
||||||
|
modifyColumnWidth,
|
||||||
|
insertColumn,
|
||||||
|
updateFileTags
|
||||||
|
} = useMetadataView();
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
|
|
||||||
const canModify = useMemo(() => window.sfMetadataContext.canModify(), []);
|
const canModify = useMemo(() => window.sfMetadataContext.canModify(), []);
|
||||||
@@ -91,87 +103,6 @@ const Table = () => {
|
|||||||
}
|
}
|
||||||
}, [metadata, store]);
|
}, [metadata, store]);
|
||||||
|
|
||||||
const modifyRecords = (rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste = false) => {
|
|
||||||
const isRename = store.checkIsRenameFileOperator(rowIds, idOriginalRowUpdates);
|
|
||||||
let newName = null;
|
|
||||||
if (isRename) {
|
|
||||||
const rowId = rowIds[0];
|
|
||||||
const row = recordGetterById(rowId);
|
|
||||||
const rowUpdates = idOriginalRowUpdates[rowId];
|
|
||||||
const { _parent_dir, _name } = row;
|
|
||||||
newName = getFileNameFromRecord(rowUpdates);
|
|
||||||
const { isValid, errMessage } = validateName(newName);
|
|
||||||
if (!isValid) {
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (newName === _name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (store.checkDuplicatedName(newName, _parent_dir)) {
|
|
||||||
let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.');
|
|
||||||
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store.modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste, isRename, {
|
|
||||||
fail_callback: (error) => {
|
|
||||||
error && toaster.danger(error);
|
|
||||||
},
|
|
||||||
success_callback: (operation) => {
|
|
||||||
if (operation.is_rename) {
|
|
||||||
const rowId = operation.row_ids[0];
|
|
||||||
const row = recordGetterById(rowId);
|
|
||||||
const rowUpdates = operation.id_original_row_updates[rowId];
|
|
||||||
const oldRow = operation.id_original_old_row_data[rowId];
|
|
||||||
const parentDir = getParentDirFromRecord(row);
|
|
||||||
const oldName = getFileNameFromRecord(oldRow);
|
|
||||||
const path = Utils.joinPath(parentDir, oldName);
|
|
||||||
const newName = getFileNameFromRecord(rowUpdates);
|
|
||||||
renameFileCallback(path, newName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteRecords = (recordsIds) => {
|
|
||||||
let paths = [];
|
|
||||||
let fileNames = [];
|
|
||||||
recordsIds.forEach((recordId) => {
|
|
||||||
const record = recordGetterById(recordId);
|
|
||||||
const { _parent_dir, _name } = record || {};
|
|
||||||
if (_parent_dir && _name) {
|
|
||||||
const path = Utils.joinPath(_parent_dir, _name);
|
|
||||||
paths.push(path);
|
|
||||||
fileNames.push(_name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
store.deleteRecords(recordsIds, {
|
|
||||||
fail_callback: (error) => {
|
|
||||||
toaster.danger(error);
|
|
||||||
},
|
|
||||||
success_callback: () => {
|
|
||||||
deleteFilesCallback(paths, fileNames);
|
|
||||||
let msg = fileNames.length > 1
|
|
||||||
? gettext('Successfully deleted {name} and {n} other items')
|
|
||||||
: gettext('Successfully deleted {name}');
|
|
||||||
msg = msg.replace('{name}', fileNames[0])
|
|
||||||
.replace('{n}', fileNames.length - 1);
|
|
||||||
toaster.success(msg);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const modifyRecord = (rowId, updates, oldRowData, originalUpdates, originalOldRowData) => {
|
|
||||||
const rowIds = [rowId];
|
|
||||||
const idRowUpdates = { [rowId]: updates };
|
|
||||||
const idOriginalRowUpdates = { [rowId]: originalUpdates };
|
|
||||||
const idOldRowData = { [rowId]: oldRowData };
|
|
||||||
const idOriginalOldRowData = { [rowId]: originalOldRowData };
|
|
||||||
modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAdjacentRowsIds = useCallback((rowIds) => {
|
const getAdjacentRowsIds = useCallback((rowIds) => {
|
||||||
const rowIdsLen = metadata.row_ids.length;
|
const rowIdsLen = metadata.row_ids.length;
|
||||||
let rowIdsInOrder = [];
|
let rowIdsInOrder = [];
|
||||||
@@ -192,34 +123,6 @@ const Table = () => {
|
|||||||
return { rowIdsInOrder, upperRowIds, belowRowIds };
|
return { rowIdsInOrder, upperRowIds, belowRowIds };
|
||||||
}, [metadata]);
|
}, [metadata]);
|
||||||
|
|
||||||
const renameColumn = useCallback((columnKey, newName, oldName) => {
|
|
||||||
store.renameColumn(columnKey, newName, oldName);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const deleteColumn = useCallback((columnKey, oldColumn) => {
|
|
||||||
store.deleteColumn(columnKey, oldColumn);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const modifyColumnData = useCallback((columnKey, newData, oldData, { optionModifyType } = {}) => {
|
|
||||||
store.modifyColumnData(columnKey, newData, oldData, { optionModifyType });
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const modifyColumnWidth = useCallback((columnKey, newWidth) => {
|
|
||||||
store.modifyColumnWidth(columnKey, newWidth);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
|
||||||
store.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const updateFileTags = useCallback((data) => {
|
|
||||||
store.updateFileTags(data);
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const insertColumn = useCallback((name, type, { key, data }) => {
|
|
||||||
store.insertColumn(name, type, { key, data });
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const recordGetterById = useCallback((recordId) => {
|
const recordGetterById = useCallback((recordId) => {
|
||||||
return metadata.id_row_map[recordId];
|
return metadata.id_row_map[recordId];
|
||||||
}, [metadata]);
|
}, [metadata]);
|
||||||
|
Reference in New Issue
Block a user