diff --git a/frontend/src/components/toolbar/gallery-files-toolbar.js b/frontend/src/components/toolbar/gallery-files-toolbar.js
new file mode 100644
index 0000000000..1dda3f3f98
--- /dev/null
+++ b/frontend/src/components/toolbar/gallery-files-toolbar.js
@@ -0,0 +1,89 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { gettext } from '../../utils/constants';
+import { EVENT_BUS_TYPE } from '../../metadata/constants';
+import RowUtils from '../../metadata/views/table/utils/row-utils';
+import { Dirent } from '../../models';
+import { useFileOperations } from '../../hooks/file-operations';
+
+const GalleryFilesToolbar = () => {
+ const [selectedRecordIds, setSelectedRecordIds] = useState([]);
+ const metadataRef = useRef([]);
+ const { handleDownload: handleDownloadAPI, handleCopy: handleCopyAPI } = useFileOperations();
+ const eventBus = window.sfMetadataContext && window.sfMetadataContext.eventBus;
+
+ const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow();
+ const canDuplicateRow = window.sfMetadataContext.canDuplicateRow();
+
+ useEffect(() => {
+ const unsubscribeSelectedFileIds = eventBus && eventBus.subscribe(EVENT_BUS_TYPE.SELECT_RECORDS, (ids, metadata) => {
+ metadataRef.current = metadata || [];
+ setSelectedRecordIds(ids);
+ });
+
+ return () => {
+ unsubscribeSelectedFileIds && unsubscribeSelectedFileIds();
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const records = useMemo(() => selectedRecordIds.map(id => RowUtils.getRecordById(id, metadataRef.current)).filter(Boolean) || [], [selectedRecordIds]);
+
+ const unSelect = useCallback(() => {
+ setSelectedRecordIds([]);
+ eventBus && eventBus.dispatch(EVENT_BUS_TYPE.UPDATE_SELECTED_RECORD_IDS, []);
+ eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
+ }, [eventBus]);
+
+ const handleDownload = useCallback(() => {
+ const list = records.map(record => {
+ const { _parent_dir: parentDir, _name: fileName } = record || {};
+ const name = parentDir === '/' ? fileName : `${parentDir}/${fileName}`;
+ return { name };
+ });
+ handleDownloadAPI('/', list);
+ }, [handleDownloadAPI, records]);
+
+ const deleteRecords = useCallback(() => {
+ eventBus && eventBus.dispatch(EVENT_BUS_TYPE.DELETE_RECORDS, selectedRecordIds, {
+ success_callback: () => {
+ eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
+ }
+ });
+ }, [eventBus, selectedRecordIds]);
+
+ const handleDuplicate = useCallback((destRepo, dirent, destPath, nodeParentPath, isByDialog) => {
+ eventBus && eventBus.dispatch(EVENT_BUS_TYPE.DUPLICATE_RECORD, selectedRecordIds[0],
+ destRepo, dirent, destPath, nodeParentPath, isByDialog);
+ }, [eventBus, selectedRecordIds]);
+
+ const handleCopy = useCallback(() => {
+ const { _parent_dir: parentDir, _name: fileName } = records[0] || {};
+ const dirent = new Dirent({ name: fileName });
+ handleCopyAPI(parentDir, dirent, false, handleDuplicate);
+ }, [records, handleCopyAPI, handleDuplicate]);
+
+ const length = selectedRecordIds.length;
+ return (
+
+
+
+ {length}{' '}{gettext('selected')}
+
+
+
+
+ {checkCanDeleteRow &&
+
+
+
+ }
+ {(canDuplicateRow && length === 1) &&
+
+
+
+ }
+
+ );
+};
+
+export default GalleryFilesToolbar;
diff --git a/frontend/src/components/toolbar/metadata-path-toolbar.js b/frontend/src/components/toolbar/metadata-path-toolbar.js
index 8f33b72698..dcb42cb485 100644
--- a/frontend/src/components/toolbar/metadata-path-toolbar.js
+++ b/frontend/src/components/toolbar/metadata-path-toolbar.js
@@ -1,21 +1,38 @@
-import React from 'react';
+import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { TAGS_MODE } from '../dir-view-mode/constants';
import { ALL_TAGS_ID } from '../../tag/constants';
+import { useMetadata } from '../../metadata/hooks';
+import { VIEW_TYPE } from '../../metadata/constants';
import AllTagsToolbar from './all-tags-toolbar';
import TagFilesToolbar from './tag-files-toolbar';
import TableFilesToolbar from './table-files-toolbar';
+import GalleryFilesToolbar from './gallery-files-toolbar';
+
+const MetadataPathToolbar = ({ repoID, repoInfo, mode, path, viewId }) => {
+ const { idViewMap } = useMetadata();
+ const view = useMemo(() => idViewMap[viewId], [viewId, idViewMap]);
+ const type = view?.type;
+
+ if (type === VIEW_TYPE.GALLERY) {
+ return (
+
+ );
+ }
+
+ if (type === VIEW_TYPE.TABLE) {
+ return (
+
+ );
+ }
-const MetadataPathToolbar = ({ repoID, repoInfo, mode, path }) => {
if (mode === TAGS_MODE) {
const isAllTagsView = path.split('/').pop() === ALL_TAGS_ID;
if (isAllTagsView) return ;
return ;
}
- return (
-
- );
+
};
MetadataPathToolbar.propTypes = {
diff --git a/frontend/src/metadata/constants/event-bus-type.js b/frontend/src/metadata/constants/event-bus-type.js
index a0f8e5eb17..18c944d2a4 100644
--- a/frontend/src/metadata/constants/event-bus-type.js
+++ b/frontend/src/metadata/constants/event-bus-type.js
@@ -42,6 +42,7 @@ export const EVENT_BUS_TYPE = {
SELECT_RECORDS: 'select_records',
TOGGLE_MOVE_DIALOG: 'toggle_move_dialog',
MOVE_RECORD: 'move_record',
+ DUPLICATE_RECORD: 'duplicate_record',
DELETE_RECORDS: 'delete_records',
UPDATE_RECORD_DETAILS: 'update_record_details',
UPDATE_FACE_RECOGNITION: 'update_face_recognition',
diff --git a/frontend/src/metadata/constants/view/gallery.js b/frontend/src/metadata/constants/view/gallery.js
index 80a7efa109..966b0a6c5b 100644
--- a/frontend/src/metadata/constants/view/gallery.js
+++ b/frontend/src/metadata/constants/view/gallery.js
@@ -18,3 +18,12 @@ export const GALLERY_DATE_MODE = {
export const STORAGE_GALLERY_DATE_MODE_KEY = 'gallery_date_mode';
export const STORAGE_GALLERY_ZOOM_GEAR_KEY = 'gallery_zoom_gear';
+
+export const GALLERY_OPERATION_KEYS = {
+ DOWNLOAD: 'download',
+ DELETE: 'delete',
+ DUPLICATE: 'duplicate',
+ REMOVE: 'remove',
+ SET_PEOPLE_PHOTO: 'set_people_photo',
+ ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups'
+};
diff --git a/frontend/src/metadata/hooks/metadata-view.js b/frontend/src/metadata/hooks/metadata-view.js
index 7b224a0fca..b3daee561d 100644
--- a/frontend/src/metadata/hooks/metadata-view.js
+++ b/frontend/src/metadata/hooks/metadata-view.js
@@ -633,6 +633,7 @@ export const MetadataViewProvider = ({
const unsubscribeLocalColumnChanged = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_COLUMN_DATA_CHANGED, updateLocalColumnData);
const unsubscribeUpdateSelectedRecordIds = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SELECTED_RECORD_IDS, updateSelectedRecordIds);
const unsubscribeMoveRecord = eventBus.subscribe(EVENT_BUS_TYPE.MOVE_RECORD, moveRecord);
+ const unsubscribeDuplicateRecord = eventBus.subscribe(EVENT_BUS_TYPE.DUPLICATE_RECORD, duplicateRecord);
const unsubscribeDeleteRecords = eventBus.subscribe(EVENT_BUS_TYPE.DELETE_RECORDS, deleteRecords);
const unsubscribeUpdateDetails = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_RECORD_DETAILS, updateRecordDetails);
const unsubscribeUpdateFaceRecognition = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_FACE_RECOGNITION, updateFaceRecognition);
@@ -661,6 +662,7 @@ export const MetadataViewProvider = ({
unsubscribeLocalColumnChanged();
unsubscribeUpdateSelectedRecordIds();
unsubscribeMoveRecord();
+ unsubscribeDuplicateRecord();
unsubscribeDeleteRecords();
unsubscribeUpdateDetails();
unsubscribeUpdateFaceRecognition();
diff --git a/frontend/src/metadata/views/gallery/content.js b/frontend/src/metadata/views/gallery/content.js
index bc09ebd055..2d8070787c 100644
--- a/frontend/src/metadata/views/gallery/content.js
+++ b/frontend/src/metadata/views/gallery/content.js
@@ -26,6 +26,7 @@ const Content = ({
const [isSelecting, setIsSelecting] = useState(false);
const [selectionStart, setSelectionStart] = useState(null);
+ const [selectionEnd, setSelectionEnd] = useState(null);
const selectedImageIds = useMemo(() => selectedImages.map(img => img.id), [selectedImages]);
@@ -50,6 +51,7 @@ const Content = ({
const selectionEnd = { x: e.clientX, y: e.clientY };
const selected = [];
+ setSelectionEnd(selectionEnd);
groups.forEach(group => {
group.children.forEach((row) => {
@@ -80,6 +82,7 @@ const Content = ({
e.preventDefault();
e.stopPropagation();
setIsSelecting(false);
+ setSelectionEnd(null);
}, []);
const renderDisplayGroup = useCallback((group) => {
@@ -185,12 +188,30 @@ const Content = ({
);
}, [overScan, mode, columns, rowHeight, onImageClick, onImageDoubleClick, onContextMenu, size, selectedImageIds, onDateTagClick]);
+ const renderSelectionBox = useCallback(() => {
+ if (!isSelecting) return null;
+ if (!selectionEnd) return null;
+
+ const containerBounds = containerRef.current.getBoundingClientRect();
+ const left = Math.min(selectionStart.x, selectionEnd.x) - containerBounds.left;
+ const top = Math.min(selectionStart.y, selectionEnd.y) - containerBounds.top;
+ const width = Math.abs(selectionStart.x - selectionEnd.x);
+ const height = Math.abs(selectionStart.y - selectionEnd.y);
+ return (
+
+
+ );
+ }, [isSelecting, selectionStart, selectionEnd]);
+
if (!Array.isArray(groups) || groups.length === 0) return ();
return (
{
return renderDisplayGroup(group);
})}
+ {renderSelectionBox()}
);
};
diff --git a/frontend/src/metadata/views/gallery/context-menu/index.js b/frontend/src/metadata/views/gallery/context-menu/index.js
index c361a46b66..861baba96c 100644
--- a/frontend/src/metadata/views/gallery/context-menu/index.js
+++ b/frontend/src/metadata/views/gallery/context-menu/index.js
@@ -6,15 +6,7 @@ import PeoplesDialog from '../../../components/dialog/peoples-dialog';
import { gettext } from '../../../../utils/constants';
import { Dirent } from '../../../../models';
import { useFileOperations } from '../../../../hooks/file-operations';
-
-const CONTEXT_MENU_KEY = {
- DOWNLOAD: 'download',
- DELETE: 'delete',
- DUPLICATE: 'duplicate',
- REMOVE: 'remove',
- SET_PEOPLE_PHOTO: 'set_people_photo',
- ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups',
-};
+import { GALLERY_OPERATION_KEYS } from '../../../constants';
const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveImage, onAddImage, onSetPeoplePhoto }) => {
const [isPeoplesDialogShow, setPeoplesDialogShow] = useState(false);
@@ -28,21 +20,21 @@ const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveIma
const canSetPeoplePhoto = window.sfMetadataContext.canSetPeoplePhoto();
const options = useMemo(() => {
- let validOptions = [{ value: CONTEXT_MENU_KEY.DOWNLOAD, label: gettext('Download') }];
+ let validOptions = [{ value: GALLERY_OPERATION_KEYS.DOWNLOAD, label: gettext('Download') }];
if (onDelete && checkCanDeleteRow) {
- validOptions.push({ value: CONTEXT_MENU_KEY.DELETE, label: selectedImages.length > 1 ? gettext('Delete') : gettext('Delete file') });
+ validOptions.push({ value: GALLERY_OPERATION_KEYS.DELETE, label: gettext('Delete') });
}
if (onDuplicate && canDuplicateRow && selectedImages.length === 1) {
- validOptions.push({ value: CONTEXT_MENU_KEY.DUPLICATE, label: gettext('Duplicate') });
+ validOptions.push({ value: GALLERY_OPERATION_KEYS.DUPLICATE, label: gettext('Copy') });
}
if (onRemoveImage && canRemovePhotoFromPeople) {
- validOptions.push({ value: CONTEXT_MENU_KEY.REMOVE, label: gettext('Remove from this group') });
+ validOptions.push({ value: GALLERY_OPERATION_KEYS.REMOVE, label: gettext('Remove from this group') });
}
if (onAddImage && canAddPhotoToPeople) {
- validOptions.push({ value: CONTEXT_MENU_KEY.ADD_PHOTO_TO_GROUPS, label: gettext('Add to groups') });
+ validOptions.push({ value: GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS, label: gettext('Add to groups') });
}
if (onSetPeoplePhoto && canSetPeoplePhoto) {
- validOptions.push({ value: CONTEXT_MENU_KEY.SET_PEOPLE_PHOTO, label: gettext('Set as cover photo') });
+ validOptions.push({ value: GALLERY_OPERATION_KEYS.SET_PEOPLE_PHOTO, label: gettext('Set as cover photo') });
}
return validOptions;
}, [checkCanDeleteRow, canDuplicateRow, canRemovePhotoFromPeople, canAddPhotoToPeople, selectedImages, onDuplicate, onDelete, onRemoveImage, onAddImage, canSetPeoplePhoto, onSetPeoplePhoto]);
@@ -70,22 +62,22 @@ const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveIma
const handleOptionClick = useCallback(option => {
switch (option.value) {
- case CONTEXT_MENU_KEY.DOWNLOAD:
+ case GALLERY_OPERATION_KEYS.DOWNLOAD:
handleDownload();
break;
- case CONTEXT_MENU_KEY.DELETE:
+ case GALLERY_OPERATION_KEYS.DELETE:
onDelete(selectedImages);
break;
- case CONTEXT_MENU_KEY.DUPLICATE:
+ case GALLERY_OPERATION_KEYS.DUPLICATE:
handleCopy();
break;
- case CONTEXT_MENU_KEY.REMOVE:
+ case GALLERY_OPERATION_KEYS.REMOVE:
onRemoveImage(selectedImages);
break;
- case CONTEXT_MENU_KEY.ADD_PHOTO_TO_GROUPS:
+ case GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS:
setPeoplesDialogShow(true);
break;
- case CONTEXT_MENU_KEY.SET_PEOPLE_PHOTO:
+ case GALLERY_OPERATION_KEYS.SET_PEOPLE_PHOTO:
onSetPeoplePhoto(selectedImages[0]);
break;
default:
diff --git a/frontend/src/metadata/views/gallery/index.css b/frontend/src/metadata/views/gallery/index.css
index 7065e31665..c3e66f3910 100644
--- a/frontend/src/metadata/views/gallery/index.css
+++ b/frontend/src/metadata/views/gallery/index.css
@@ -99,3 +99,9 @@
justify-content: center;
flex-shrink: 0;
}
+
+.selection-box {
+ position: absolute;
+ background-color: rgba(0, 120, 215, 0.3);
+ border: 1px solid rgba(0, 120, 215, 0.8);
+}
diff --git a/frontend/src/metadata/views/gallery/main.js b/frontend/src/metadata/views/gallery/main.js
index 2f086ce8ad..9423db1c11 100644
--- a/frontend/src/metadata/views/gallery/main.js
+++ b/frontend/src/metadata/views/gallery/main.js
@@ -35,7 +35,7 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
const scrollContainer = useRef(null);
const lastState = useRef({ scrollPos: 0 });
- const { repoID, updateCurrentDirent } = useMetadataView();
+ const { repoID, updateCurrentDirent, updateSelectedRecordIds } = useMetadataView();
const repoInfo = window.sfMetadataContext.getSetting('repoInfo');
const canPreview = window.sfMetadataContext.canPreview();
@@ -191,12 +191,19 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
});
}, [metadata, updateCurrentDirent]);
+ const updateSelectedImages = useCallback((selectedImages) => {
+ const ids = selectedImages.map(item => item.id);
+ updateSelectedRecordIds(ids);
+ }, [updateSelectedRecordIds]);
+
const handleClick = useCallback((event, image) => {
if (event.metaKey || event.ctrlKey) {
- setSelectedImages(prev =>
- prev.includes(image) ? prev.filter(img => img !== image) : [...prev, image]
- );
+ const updatedSelectedImages = selectedImages.includes(image)
+ ? selectedImages.filter(img => img !== image)
+ : [...selectedImages, image];
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(image);
+ updateSelectedImages(updatedSelectedImages);
return;
}
if (event.shiftKey && lastSelectedImage) {
@@ -205,14 +212,18 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
const start = Math.min(lastSelectedIndex, currentIndex);
const end = Math.max(lastSelectedIndex, currentIndex);
const range = images.slice(start, end + 1);
- setSelectedImages(prev => Array.from(new Set([...prev, ...range])));
+ const updatedSelectedImages = Array.from(new Set([...selectedImages, ...range]));
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(null);
+ updateSelectedImages(updatedSelectedImages);
return;
}
- setSelectedImages([image]);
+ const updatedSelectedImages = [image];
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(image);
setLastSelectedImage(image);
- }, [images, updateSelectedImage, lastSelectedImage]);
+ updateSelectedImages(updatedSelectedImages);
+ }, [images, selectedImages, updateSelectedImage, lastSelectedImage, updateSelectedImages]);
const handleDoubleClick = useCallback((event, image) => {
event.preventDefault();
@@ -231,28 +242,40 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
const index = images.findIndex(item => item.id === image.id);
if (isNaN(index) || index === -1) return;
- setSelectedImages(prev => prev.length < 2 ? [image] : [...prev]);
- }, [images]);
+ const updatedSelectedImages = selectedImages.length < 2 ? [image] : [...selectedImages];
+ setSelectedImages(updatedSelectedImages);
+ updateSelectedImages(updatedSelectedImages);
+ }, [images, selectedImages, updateSelectedImages]);
const moveToPrevImage = useCallback(() => {
const imageItemsLength = images.length;
const selectedImage = images[(imageIndex + imageItemsLength - 1) % imageItemsLength];
setImageIndex((prevState) => (prevState + imageItemsLength - 1) % imageItemsLength);
- setSelectedImages([selectedImage]);
+ const updatedSelectedImages = [selectedImage];
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(selectedImage);
- }, [images, imageIndex, updateSelectedImage]);
+ updateSelectedImages(updatedSelectedImages);
+ }, [images, imageIndex, updateSelectedImage, updateSelectedImages]);
const moveToNextImage = useCallback(() => {
const imageItemsLength = images.length;
const selectedImage = images[(imageIndex + 1) % imageItemsLength];
setImageIndex((prevState) => (prevState + 1) % imageItemsLength);
- setSelectedImages([selectedImage]);
+ const updatedSelectedImages = [selectedImage];
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(selectedImage);
- }, [images, imageIndex, updateSelectedImage]);
+ updateSelectedImages(updatedSelectedImages);
+ }, [images, imageIndex, updateSelectedImage, updateSelectedImages]);
const handleImageSelection = useCallback((selectedImages) => {
setSelectedImages(selectedImages);
- }, []);
+ updateSelectedImages(selectedImages);
+ }, [updateSelectedImages]);
+
+ const selectNone = useCallback(() => {
+ setSelectedImages([]);
+ updateSelectedImages([]);
+ }, [updateSelectedImages]);
const closeImagePopup = useCallback(() => {
setIsImagePopupOpen(false);
@@ -264,26 +287,29 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
success_callback: () => {
updateCurrentDirent();
setSelectedImages([]);
+ updateSelectedImages([]);
}
});
- }, [onDelete, updateCurrentDirent]);
+ }, [onDelete, updateCurrentDirent, updateSelectedImages]);
const handleRemoveSelectedImages = useCallback((selectedImages) => {
if (!selectedImages.length) return;
onRemoveImage && onRemoveImage(selectedImages, () => {
updateCurrentDirent();
setSelectedImages([]);
+ updateSelectedImages([]);
});
- }, [onRemoveImage, updateCurrentDirent]);
+ }, [onRemoveImage, updateCurrentDirent, updateSelectedImages]);
const handleMakeSelectedAsCoverPhoto = useCallback((selectedImage) => {
onSetPeoplePhoto(selectedImage, {
success_callback: () => {
updateCurrentDirent();
setSelectedImages([]);
+ updateSelectedImages([]);
}
});
- }, [onSetPeoplePhoto, updateCurrentDirent]);
+ }, [onSetPeoplePhoto, updateCurrentDirent, updateSelectedImages]);
const handleClickOutside = useCallback((event) => {
const className = getEventClassName(event);
@@ -306,6 +332,7 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
if (newImageItems.length === 0) {
setSelectedImages([]);
+ updateSelectedImages([]);
setIsImagePopupOpen(false);
setImageIndex(0);
} else {
@@ -314,9 +341,11 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
setImageIndex(newIndex);
}
- setSelectedImages(newSelectedImage ? [newSelectedImage] : []);
+ const updatedSelectedImages = newSelectedImage ? [newSelectedImage] : [];
+ setSelectedImages(updatedSelectedImages);
updateSelectedImage(newSelectedImage);
- }, [selectedImages, images, onDelete, updateSelectedImage]);
+ updateSelectedImages(updatedSelectedImages);
+ }, [selectedImages, images, onDelete, updateSelectedImage, updateSelectedImages]);
const handleDateTagClick = useCallback((event, groupName) => {
event.preventDefault();
@@ -348,6 +377,7 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
EVENT_BUS_TYPE.SWITCH_GALLERY_GROUP_BY,
(mode) => {
setSelectedImages([]);
+ updateSelectedImages([]);
setMode(mode);
lastState.current = { ...lastState.current, mode };
window.sfMetadataContext.localStorage.setItem(STORAGE_GALLERY_DATE_MODE_KEY, mode);
@@ -378,9 +408,12 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
setZoomGear(zoomGear);
});
+ const unsubscribeSelectNone = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SELECT_NONE, selectNone);
+
return () => {
container && resizeObserver.unobserve(container);
modifyGalleryZoomGearSubscribe();
+ unsubscribeSelectNone();
switchGalleryModeSubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/frontend/src/pages/lib-content-view/lib-content-view.js b/frontend/src/pages/lib-content-view/lib-content-view.js
index 82e2d04d69..c30aead4a9 100644
--- a/frontend/src/pages/lib-content-view/lib-content-view.js
+++ b/frontend/src/pages/lib-content-view/lib-content-view.js
@@ -2311,7 +2311,7 @@ class LibContentView extends React.Component {
render() {
const { repoID } = this.props;
let { currentRepoInfo, userPerm, isCopyMoveProgressDialogShow, isDeleteFolderDialogOpen, errorMsg,
- path, usedRepoTags, isDirentSelected, currentMode, currentNode } = this.state;
+ path, usedRepoTags, isDirentSelected, currentMode, currentNode, viewId } = this.state;
if (this.state.libNeedDecrypt) {
return (
@@ -2417,7 +2417,7 @@ class LibContentView extends React.Component {
})}>
{isDirentSelected ? (
currentMode === TAGS_MODE || currentMode === METADATA_MODE ? (
-
+
) : (