Skip to content

Commit

Permalink
Feature/tags view file operations (#7464)
Browse files Browse the repository at this point in the history
* add basic file operations

* add tag view toolbar operations

* add share and rename

* optimize

* optimize

* update codes

---------

Co-authored-by: zhouwenxuan <[email protected]>
Co-authored-by: renjie-run <[email protected]>
  • Loading branch information
3 people authored Feb 25, 2025
1 parent 49896f5 commit 30d0a34
Show file tree
Hide file tree
Showing 14 changed files with 889 additions and 97 deletions.
6 changes: 6 additions & 0 deletions frontend/src/components/dir-view-mode/dir-column-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const propTypes = {
eventBus: PropTypes.object,
updateCurrentDirent: PropTypes.func.isRequired,
updateCurrentPath: PropTypes.func,
toggleShowDirentToolbar: PropTypes.func,
};

class DirColumnView extends React.Component {
Expand Down Expand Up @@ -225,6 +226,11 @@ class DirColumnView extends React.Component {
renameFileCallback={this.props.renameFileCallback}
updateCurrentDirent={this.props.updateCurrentDirent}
updateCurrentPath={this.props.updateCurrentPath}
moveFileCallback={this.props.moveFileCallback}
copyFileCallback={this.props.copyFileCallback}
convertFileCallback={this.props.convertFileCallback}
addFolderCallback={this.props.onAddFolder}
toggleShowDirentToolbar={this.props.toggleShowDirentToolbar}
/>
)}
{currentMode === LIST_MODE && (
Expand Down
143 changes: 143 additions & 0 deletions frontend/src/components/toolbar/tag-files-toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
import { gettext } from '../../utils/constants';
import { EVENT_BUS_TYPE } from '../../metadata/constants';
import TextTranslation from '../../utils/text-translation';
import { getFileById, getFileName, getTagFileOperationList } from '../../tag/utils/file';

const TagFilesToolbar = ({ currentRepoInfo }) => {
const [selectedFileIds, setSelectedFileIds] = useState([]);
const tagFilesRef = useRef([]);

const canModify = window.sfTagsDataContext && window.sfTagsDataContext.canModify();
const eventBus = window.sfTagsDataContext && window.sfTagsDataContext.eventBus;

const selectedFilesLen = useMemo(() => {
return selectedFileIds.length;
}, [selectedFileIds]);

const unSelect = useCallback(() => {
setSelectedFileIds([]);
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.UNSELECT_TAG_FILES);
}, [eventBus]);

const moveTagFile = useCallback(() => {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.MOVE_TAG_FILE);
}, [eventBus]);

const copyTagFile = useCallback(() => {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.COPY_TAG_FILE);
}, [eventBus]);

const deleteTagFiles = useCallback(() => {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.DELETE_TAG_FILES);
}, [eventBus]);

const downloadTagFiles = useCallback(() => {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.DOWNLOAD_TAG_FILES);
}, [eventBus]);

const getMenuList = useCallback(() => {
if (selectedFilesLen > 1) return [];
const fileId = selectedFileIds[0];
const file = getFileById(tagFilesRef.current, fileId);
const fileName = getFileName(file);
const allOperations = getTagFileOperationList(fileName, currentRepoInfo, canModify);
const excludesOperations = ['Move', 'Copy', 'Delete', 'Download'];
const validOperations = allOperations.filter((item) => {
return excludesOperations.indexOf(item.key) == -1;
});
return validOperations;
}, [canModify, currentRepoInfo, selectedFileIds, selectedFilesLen]);

const onMenuItemClick = useCallback((operation) => {
switch (operation) {
case TextTranslation.SHARE.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.SHARE_TAG_FILE);
break;
case TextTranslation.RENAME.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_RENAME_DIALOG);
break;
case TextTranslation.HISTORY.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.FILE_HISTORY);
break;
case TextTranslation.ACCESS_LOG.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.FILE_ACCESS_LOG);
break;
case TextTranslation.OPEN_VIA_CLIENT.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.OPEN_VIA_CLIENT);
break;
case TextTranslation.CONVERT_TO_SDOC.key:
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.CONVERT_FILE, 'sdoc');
break;
case TextTranslation.CONVERT_TO_MARKDOWN.key: {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.CONVERT_FILE, 'markdown');
break;
}
case TextTranslation.CONVERT_TO_DOCX.key: {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.CONVERT_FILE, 'docx');
break;
}
case TextTranslation.EXPORT_DOCX.key: {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.EXPORT_DOCX);
break;
}
case TextTranslation.EXPORT_SDOC.key: {
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.EXPORT_SDOC);
break;
}
default:
break;
}
}, [eventBus]);

useEffect(() => {
const unsubscribeSelectedFileIds = eventBus && eventBus.subscribe(EVENT_BUS_TYPE.SELECT_TAG_FILES, (ids, tagFiles) => {
tagFilesRef.current = tagFiles || [];
setSelectedFileIds(ids);
});

return () => {
unsubscribeSelectedFileIds && unsubscribeSelectedFileIds();
};
}, []);

return (
<div className="selected-dirents-toolbar">
<span className="cur-view-path-btn px-2" onClick={unSelect}>
<span className="sf3-font-x-01 sf3-font mr-2" aria-label={gettext('Unselect')} title={gettext('Unselect')}></span>
<span>{selectedFilesLen}{' '}{gettext('selected')}</span>
</span>
{(selectedFilesLen === 1 && canModify) &&
<>
<span className="cur-view-path-btn" onClick={moveTagFile}>
<span className="sf3-font-move1 sf3-font" aria-label={gettext('Move')} title={gettext('Move')}></span>
</span>
<span className="cur-view-path-btn" onClick={copyTagFile}>
<span className="sf3-font-copy1 sf3-font" aria-label={gettext('Copy')} title={gettext('Copy')}></span>
</span>
</>
}
{canModify &&
<>
<span className="cur-view-path-btn" onClick={deleteTagFiles}>
<span className="sf3-font-delete1 sf3-font" aria-label={gettext('Delete')} title={gettext('Delete')}></span>
</span>
<span className="cur-view-path-btn" onClick={downloadTagFiles}>
<span className="sf3-font-download1 sf3-font" aria-label={gettext('Download')} title={gettext('Download')}></span>
</span>
</>
}
{selectedFilesLen === 1 &&
<ItemDropdownMenu
item={{}}
toggleClass={'cur-view-path-btn sf3-font-more-vertical sf3-font'}
onMenuItemClick={onMenuItemClick}
getMenuList={getMenuList}
/>
}
</div>
);
};

export default TagFilesToolbar;
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ const FileNameEditor = React.forwardRef((props, ref) => {
const fileType = getFileType();
const repoID = window.sfMetadataContext.getSetting('repoID');
const repoInfo = window.sfMetadataContext.getSetting('repoInfo');
const canDelete = window.sfMetadataContext.checkCanDeleteRow();

if (fileType === 'image') {
return (
<ImagePreviewer {...props} repoID={repoID} repoInfo={repoInfo} closeImagePopup={props.onCommitCancel} />
<ImagePreviewer {...props} repoID={repoID} repoInfo={repoInfo} closeImagePopup={props.onCommitCancel} canDelete={canDelete} />
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Utils } from '../../../utils/utils';
import { siteRoot, thumbnailSizeForOriginal, fileServerRoot, thumbnailDefaultSize } from '../../../utils/constants';
import { getFileNameFromRecord, getParentDirFromRecord, getRecordIdFromRecord } from '../../utils/cell';

const ImagePreviewer = ({ record, table, repoID, repoInfo, closeImagePopup, deleteRecords }) => {
const ImagePreviewer = ({ record, table, repoID, repoInfo, closeImagePopup, deleteRecords, canDelete }) => {
const [imageIndex, setImageIndex] = useState(0);
const [imageItems, setImageItems] = useState([]);

Expand Down Expand Up @@ -95,8 +95,6 @@ const ImagePreviewer = ({ record, table, repoID, repoInfo, closeImagePopup, dele
}
};

const canDelete = window.sfMetadataContext.checkCanDeleteRow();

return (
<ModalPortal>
<ImageDialog
Expand All @@ -119,6 +117,7 @@ ImagePreviewer.propTypes = {
repoInfo: PropTypes.object,
closeImagePopup: PropTypes.func,
deleteRecords: PropTypes.func,
canDelete: PropTypes.bool,
};

export default ImagePreviewer;
20 changes: 20 additions & 0 deletions frontend/src/metadata/constants/event-bus-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,24 @@ export const EVENT_BUS_TYPE = {
// map
MODIFY_MAP_TYPE: 'modify_map_type',
MAP_VIEW: 'map_view',

// tag file
MOVE_TAG_FILE: 'move_tag_file',
COPY_TAG_FILE: 'copy_tag_file',
RENAME_TAG_FILE: 'rename_tag_file',
TOGGLE_RENAME_DIALOG: 'toggle_rename_dialog',
SHARE_TAG_FILE: 'share_tag_file',
TOGGLE_ZIP_DIALOG: 'toggle_zip_dialog',
DOWNLOAD_TAG_FILES: 'download_tag_files',
DELETE_TAG_FILES: 'delete_tag_files',
SELECT_TAG_FILES: 'select_tag_files',
UNSELECT_TAG_FILES: 'unselect_tag_files',

// file
FILE_HISTORY: 'file_history',
FILE_ACCESS_LOG: 'file_access_log',
OPEN_VIA_CLIENT: 'open_via_client',
CONVERT_FILE: 'convert_file',
EXPORT_DOCX: 'export_docx',
EXPORT_SDOC: 'export_sdoc',
};
Loading

0 comments on commit 30d0a34

Please sign in to comment.