Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: metadata op api #7204

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 145 additions & 19 deletions frontend/src/metadata/hooks/metadata-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ import toaster from '../../components/toast';
import Context from '../context';
import Store from '../store';
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 { useCollaborators } from './collaborators';
import { getRowById } from '../utils/table';
import { getFileNameFromRecord, getParentDirFromRecord } from '../utils/cell';
import { gettext } from '../../utils/constants';

const MetadataViewContext = React.createContext(null);

export const MetadataViewProvider = ({
children,
repoID,
viewID,
renameFileCallback,
deleteFilesCallback,
...params
}) => {
const [isLoading, setLoading] = useState(true);
Expand Down Expand Up @@ -48,32 +53,142 @@ export const MetadataViewProvider = ({
}, []);

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) => {
window.sfMetadataStore.modifySorts(sorts, displaySorts);
}, []);
storeRef.current.modifySorts(sorts, displaySorts);
}, [storeRef]);

const modifyGroupbys = useCallback((groupbys) => {
window.sfMetadataStore.modifyGroupbys(groupbys);
}, []);
storeRef.current.modifyGroupbys(groupbys);
}, [storeRef]);

const modifyHiddenColumns = useCallback((hiddenColumns) => {
window.sfMetadataStore.modifyHiddenColumns(hiddenColumns);
}, []);

const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
window.sfMetadataStore.modifyColumnOrder(sourceColumnKey, targetColumnKey);
}, []);
storeRef.current.modifyHiddenColumns(hiddenColumns);
}, [storeRef]);

const modifySettings = useCallback((settings) => {
window.sfMetadataStore.modifySettings(settings);
}, []);
storeRef.current.modifySettings(settings);
}, [storeRef]);

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
useEffect(() => {
Expand Down Expand Up @@ -137,11 +252,22 @@ export const MetadataViewProvider = ({
metadata,
store: storeRef.current,
isDirentDetailShow: params.isDirentDetailShow,
deleteFilesCallback: params.deleteFilesCallback,
renameFileCallback: params.renameFileCallback,
updateCurrentDirent: params.updateCurrentDirent,
closeDirentDetail: params.closeDirentDetail,
showDirentDetail: params.showDirentDetail,
deleteFilesCallback: deleteFilesCallback,
renameFileCallback: renameFileCallback,
modifySettings,
modifyRecords,
deleteRecords,
modifyRecord,
renameColumn,
deleteColumn,
modifyColumnOrder,
modifyColumnData,
modifyColumnWidth,
insertColumn,
updateFileTags,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
onDeletePeoplePhotos && onDeletePeoplePhotos(people._id, ids);
}, [metadata, onClose, people, onDeletePeoplePhotos]);

const handelDelete = useCallback((deletedImages, callback) => {
const handelDelete = useCallback((deletedImages, { success_callback } = {}) => {
if (!deletedImages.length) return;
let recordIds = [];
let paths = [];
Expand All @@ -88,7 +88,6 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
}
});
window.sfMetadataContext.batchDeleteFiles(repoID, paths).then(res => {
callback && callback();
deletedByIds(recordIds);
deleteFilesCallback(paths, fileNames);
let msg = fileNames.length > 1
Expand All @@ -97,6 +96,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos }) => {
msg = msg.replace('{name}', fileNames[0])
.replace('{n}', fileNames.length - 1);
toaster.success(msg);
success_callback && success_callback();
}).catch(error => {
toaster.danger(gettext('Failed to delete records'));
});
Expand Down
28 changes: 4 additions & 24 deletions frontend/src/metadata/views/gallery/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import toaster from '../../../components/toast';
import Main from './main';
import { useMetadataView } from '../../hooks/metadata-view';
import { Utils } from '../../../utils/utils';
import { gettext } from '../../../utils/constants';
import { PER_LOAD_NUMBER } from '../../constants';

import './index.css';

const Gallery = () => {
const [isLoadingMore, setLoadingMore] = useState(false);

const { metadata, store, deleteFilesCallback } = useMetadataView();
const { metadata, store, deleteRecords } = useMetadataView();

const onLoadMore = useCallback(async () => {
if (isLoadingMore) return;
Expand All @@ -30,36 +29,17 @@ const Gallery = () => {

}, [isLoadingMore, metadata, store]);

const handleDelete = useCallback((deletedImages, callback) => {
const handleDelete = useCallback((deletedImages, { success_callback } = {}) => {
if (!deletedImages.length) return;
let recordsIds = [];
let paths = [];
let fileNames = [];
deletedImages.forEach((record) => {
const { path: parentDir, name } = record || {};
if (parentDir && name) {
const path = Utils.joinPath(parentDir, name);
recordsIds.push(record.id);
paths.push(path);
fileNames.push(name);
}
});
store.deleteRecords(recordsIds, {
fail_callback: (error) => {
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]);
deleteRecords(recordsIds, { success_callback });
}, [deleteRecords]);

return (
<div className="sf-metadata-container">
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/metadata/views/gallery/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,11 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore }) => {

const handleDeleteSelectedImages = useCallback((selectedImages) => {
if (!selectedImages.length) return;
onDelete(selectedImages, () => {
updateCurrentDirent();
setSelectedImages([]);
onDelete(selectedImages, {
success_callback: () => {
updateCurrentDirent();
setSelectedImages([]);
}
});
}, [onDelete, updateCurrentDirent]);

Expand Down
19 changes: 14 additions & 5 deletions frontend/src/metadata/views/kanban/boards/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ImagePreviewer from '../../../components/cell-formatter/image-previewer';
import ContextMenu from '../context-menu';

import './index.css';
import { getRowById } from '../../../utils/table';

const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings }) => {
const [haveFreezed, setHaveFreezed] = useState(false);
Expand Down Expand Up @@ -192,9 +193,9 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings
setImagePreviewerVisible(false);
}, []);

const onSelectCard = useCallback((record) => {
const handelUpdateCurrentDirent = useCallback((record) => {
if (!record) return;
const recordId = getRecordIdFromRecord(record);
if (selectedCard === recordId) return;
const name = getFileNameFromRecord(record);
const path = getParentDirFromRecord(record);
const isDir = checkIsDir(record);
Expand All @@ -206,9 +207,15 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings
file_tags: []
});
setSelectedCard(recordId);
}, [updateCurrentDirent]);

const onSelectCard = useCallback((record) => {
const recordId = getRecordIdFromRecord(record);
if (selectedCard === recordId) return;
handelUpdateCurrentDirent(record);
onCloseSettings();
showDirentDetail();
}, [selectedCard, onCloseSettings, showDirentDetail, updateCurrentDirent]);
}, [selectedCard, onCloseSettings, showDirentDetail, handelUpdateCurrentDirent]);

const handleClickOutside = useCallback((event) => {
if (isDragging) return;
Expand All @@ -222,8 +229,10 @@ const Boards = ({ modifyRecord, deleteRecords, modifyColumnData, onCloseSettings

const onContextMenu = useCallback((event, recordId) => {
event.preventDefault();
setSelectedCard(recordId);
}, []);
if (selectedCard === recordId) return;
const record = getRowById(metadata, recordId);
handelUpdateCurrentDirent(record);
}, [metadata, selectedCard, handelUpdateCurrentDirent]);

const onDeleteRecords = useCallback((recordIds) => {
deleteRecords(recordIds, {
Expand Down
Loading
Loading