mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-26 15:26:19 +00:00
Face recognition top toolbar (#8180)
* [metadata] 'face recognition' view: add a top toolbar for the selected photo(s) * [metadata] 'face recognition' view: update for 'add photos to group' * [metadata] 'face recognition' view: update for the top toolbar
This commit is contained in:
@@ -0,0 +1,125 @@
|
|||||||
|
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, GALLERY_OPERATION_KEYS } from '../../metadata/constants';
|
||||||
|
import { useFileOperations } from '../../hooks/file-operations';
|
||||||
|
|
||||||
|
const FaceRecognitionFilesToolbar = () => {
|
||||||
|
const [selectedRecordIds, setSelectedRecordIds] = useState([]);
|
||||||
|
const [selectedRecords, setSelectedRecords] = useState([]);
|
||||||
|
const [isSomeone, setIsSomeone] = useState(false);
|
||||||
|
const menuRef = useRef(null);
|
||||||
|
const { handleDownload: handleDownloadAPI } = useFileOperations();
|
||||||
|
const eventBus = window.sfMetadataContext && window.sfMetadataContext.eventBus;
|
||||||
|
|
||||||
|
const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow();
|
||||||
|
const canRemovePhotoFromPeople = window.sfMetadataContext.canRemovePhotoFromPeople();
|
||||||
|
const canAddPhotoToPeople = window.sfMetadataContext.canAddPhotoToPeople();
|
||||||
|
const canSetPeoplePhoto = window.sfMetadataContext.canSetPeoplePhoto();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribeSelectedFileIds = eventBus && eventBus.subscribe(EVENT_BUS_TYPE.SELECT_RECORDS, (ids, metadata, selectedRecords, isSomeone) => {
|
||||||
|
setSelectedRecordIds(ids);
|
||||||
|
setSelectedRecords(selectedRecords);
|
||||||
|
setIsSomeone(isSomeone);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeSelectedFileIds && unsubscribeSelectedFileIds();
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
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 = selectedRecords.map(record => {
|
||||||
|
const { parentDir, name: fileName } = record || {};
|
||||||
|
const name = parentDir === '/' ? fileName : `${parentDir}/${fileName}`;
|
||||||
|
return { name };
|
||||||
|
});
|
||||||
|
handleDownloadAPI('/', list);
|
||||||
|
}, [selectedRecords, handleDownloadAPI]);
|
||||||
|
|
||||||
|
const deleteRecords = useCallback(() => {
|
||||||
|
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.DELETE_FACE_RECOGNITION_RECORDS, selectedRecords, {
|
||||||
|
success_callback: () => {
|
||||||
|
eventBus.dispatch(EVENT_BUS_TYPE.SELECT_NONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [eventBus, selectedRecords]);
|
||||||
|
|
||||||
|
const opList = useMemo(() => {
|
||||||
|
const list = [];
|
||||||
|
if (isSomeone && canRemovePhotoFromPeople) {
|
||||||
|
list.push({
|
||||||
|
key: GALLERY_OPERATION_KEYS.REMOVE_PHOTO_FROM_CURRENT_SET,
|
||||||
|
value: gettext('Remove from this group')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!isSomeone && canAddPhotoToPeople) {
|
||||||
|
list.push({
|
||||||
|
key: GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS,
|
||||||
|
value: gettext('Add to groups')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (canSetPeoplePhoto && selectedRecordIds.length == 1) {
|
||||||
|
list.push({
|
||||||
|
key: GALLERY_OPERATION_KEYS.SET_PHOTO_AS_COVER,
|
||||||
|
value: gettext('Set as cover photo')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}, [isSomeone, selectedRecordIds, canRemovePhotoFromPeople, canAddPhotoToPeople, canSetPeoplePhoto]);
|
||||||
|
|
||||||
|
const getMenuList = useCallback(() => {
|
||||||
|
return opList;
|
||||||
|
}, [opList]);
|
||||||
|
|
||||||
|
const onMenuItemClick = useCallback((operation) => {
|
||||||
|
switch (operation) {
|
||||||
|
case GALLERY_OPERATION_KEYS.REMOVE_PHOTO_FROM_CURRENT_SET:
|
||||||
|
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.REMOVE_PHOTOS_FROM_CURRENT_SET, selectedRecords);
|
||||||
|
break;
|
||||||
|
case GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS:
|
||||||
|
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.ADD_PHOTO_TO_GROUPS);
|
||||||
|
break;
|
||||||
|
case GALLERY_OPERATION_KEYS.SET_PHOTO_AS_COVER:
|
||||||
|
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.SET_PHOTO_AS_COVER, selectedRecords[0]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, [eventBus, selectedRecords]);
|
||||||
|
|
||||||
|
const length = selectedRecordIds.length;
|
||||||
|
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>{length}{' '}{gettext('selected')}</span>
|
||||||
|
</span>
|
||||||
|
<span className="cur-view-path-btn" onClick={handleDownload}>
|
||||||
|
<span className="sf3-font-download1 sf3-font" aria-label={gettext('Download')} title={gettext('Download')}></span>
|
||||||
|
</span>
|
||||||
|
{checkCanDeleteRow &&
|
||||||
|
<span className="cur-view-path-btn" onClick={deleteRecords}>
|
||||||
|
<span className="sf3-font-delete1 sf3-font" aria-label={gettext('Delete')} title={gettext('Delete')}></span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
<ItemDropdownMenu
|
||||||
|
ref={menuRef}
|
||||||
|
item={{}}
|
||||||
|
toggleClass="cur-view-path-btn sf3-font-more sf3-font"
|
||||||
|
onMenuItemClick={onMenuItemClick}
|
||||||
|
getMenuList={getMenuList}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FaceRecognitionFilesToolbar;
|
@@ -8,6 +8,7 @@ import AllTagsToolbar from './all-tags-toolbar';
|
|||||||
import TagFilesToolbar from './tag-files-toolbar';
|
import TagFilesToolbar from './tag-files-toolbar';
|
||||||
import TableFilesToolbar from './table-files-toolbar';
|
import TableFilesToolbar from './table-files-toolbar';
|
||||||
import GalleryFilesToolbar from './gallery-files-toolbar';
|
import GalleryFilesToolbar from './gallery-files-toolbar';
|
||||||
|
import FaceRecognitionFilesToolbar from './face-recognition-files-toolbar';
|
||||||
|
|
||||||
const MetadataPathToolbar = ({ repoID, repoInfo, mode, path, viewId }) => {
|
const MetadataPathToolbar = ({ repoID, repoInfo, mode, path, viewId }) => {
|
||||||
const { idViewMap } = useMetadata();
|
const { idViewMap } = useMetadata();
|
||||||
@@ -20,6 +21,10 @@ const MetadataPathToolbar = ({ repoID, repoInfo, mode, path, viewId }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === VIEW_TYPE.FACE_RECOGNITION) {
|
||||||
|
return <FaceRecognitionFilesToolbar />;
|
||||||
|
}
|
||||||
|
|
||||||
if (type === VIEW_TYPE.TABLE) {
|
if (type === VIEW_TYPE.TABLE) {
|
||||||
return (
|
return (
|
||||||
<TableFilesToolbar repoID={repoID} />
|
<TableFilesToolbar repoID={repoID} />
|
||||||
|
@@ -85,6 +85,12 @@ export const EVENT_BUS_TYPE = {
|
|||||||
MODIFY_GALLERY_ZOOM_GEAR: 'modify_gallery_zoom_gear',
|
MODIFY_GALLERY_ZOOM_GEAR: 'modify_gallery_zoom_gear',
|
||||||
SWITCH_GALLERY_GROUP_BY: 'switch_gallery_group_by',
|
SWITCH_GALLERY_GROUP_BY: 'switch_gallery_group_by',
|
||||||
|
|
||||||
|
// face recognition
|
||||||
|
DELETE_FACE_RECOGNITION_RECORDS: 'delete_face_recognition_records',
|
||||||
|
REMOVE_PHOTOS_FROM_CURRENT_SET: 'remove_photos_from_current_set',
|
||||||
|
SET_PHOTO_AS_COVER: 'set_photo_as_cover',
|
||||||
|
ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups',
|
||||||
|
|
||||||
// kanban
|
// kanban
|
||||||
TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings',
|
TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings',
|
||||||
OPEN_KANBAN_SETTINGS: 'open_kanban_settings',
|
OPEN_KANBAN_SETTINGS: 'open_kanban_settings',
|
||||||
|
@@ -22,8 +22,8 @@ export const STORAGE_GALLERY_ZOOM_GEAR_KEY = 'gallery_zoom_gear';
|
|||||||
export const GALLERY_OPERATION_KEYS = {
|
export const GALLERY_OPERATION_KEYS = {
|
||||||
DOWNLOAD: 'download',
|
DOWNLOAD: 'download',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete',
|
||||||
DUPLICATE: 'duplicate',
|
COPY: 'copy',
|
||||||
REMOVE: 'remove',
|
REMOVE_PHOTO_FROM_CURRENT_SET: 'remove_photo_from_current_set',
|
||||||
SET_PEOPLE_PHOTO: 'set_people_photo',
|
SET_PHOTO_AS_COVER: 'set_photo_as_cover',
|
||||||
ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups'
|
ADD_PHOTO_TO_GROUPS: 'add_photo_to_groups'
|
||||||
};
|
};
|
||||||
|
@@ -296,10 +296,14 @@ export const MetadataViewProvider = ({
|
|||||||
storeRef.current.updateFileTags(data);
|
storeRef.current.updateFileTags(data);
|
||||||
}, [storeRef, modifyLocalFileTags]);
|
}, [storeRef, modifyLocalFileTags]);
|
||||||
|
|
||||||
const updateSelectedRecordIds = useCallback((ids) => {
|
const updateSelectedRecordIds = useCallback((ids, records, isSomeone) => {
|
||||||
toggleShowDirentToolbar(ids.length > 0);
|
toggleShowDirentToolbar(ids.length > 0);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (records != undefined) {
|
||||||
|
window.sfMetadataContext && window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_RECORDS, ids, metadata, records, isSomeone);
|
||||||
|
} else {
|
||||||
window.sfMetadataContext && window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_RECORDS, ids, metadata);
|
window.sfMetadataContext && window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SELECT_RECORDS, ids, metadata);
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}, [metadata, toggleShowDirentToolbar]);
|
}, [metadata, toggleShowDirentToolbar]);
|
||||||
|
|
||||||
|
@@ -237,12 +237,14 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onAddPeople
|
|||||||
const eventBus = window?.sfMetadataContext?.eventBus;
|
const eventBus = window?.sfMetadataContext?.eventBus;
|
||||||
if (!eventBus) return;
|
if (!eventBus) return;
|
||||||
const unsubscribeViewChange = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange);
|
const unsubscribeViewChange = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange);
|
||||||
|
const unsubscribeDeleteRecords = eventBus.subscribe(EVENT_BUS_TYPE.DELETE_FACE_RECOGNITION_RECORDS, handleDelete);
|
||||||
const localRecordChangedSubscribe = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, onRecordChange);
|
const localRecordChangedSubscribe = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, onRecordChange);
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribeViewChange && unsubscribeViewChange();
|
unsubscribeViewChange && unsubscribeViewChange();
|
||||||
|
unsubscribeDeleteRecords && unsubscribeDeleteRecords();
|
||||||
localRecordChangedSubscribe && localRecordChangedSubscribe();
|
localRecordChangedSubscribe && localRecordChangedSubscribe();
|
||||||
};
|
};
|
||||||
}, [onViewChange, onRecordChange]);
|
}, [onViewChange, handleDelete, onRecordChange]);
|
||||||
|
|
||||||
if (isLoading) return (<CenteredLoading />);
|
if (isLoading) return (<CenteredLoading />);
|
||||||
|
|
||||||
@@ -256,6 +258,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onAddPeople
|
|||||||
onRemoveImage={people._is_someone ? handleRemove : null}
|
onRemoveImage={people._is_someone ? handleRemove : null}
|
||||||
onAddImage={!people._is_someone ? handleAdd : null}
|
onAddImage={!people._is_someone ? handleAdd : null}
|
||||||
onSetPeoplePhoto={handleSetPeoplePhoto}
|
onSetPeoplePhoto={handleSetPeoplePhoto}
|
||||||
|
isSomeone={people._is_someone}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import React, { useMemo, useCallback, useState } from 'react';
|
import React, { useMemo, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContextMenu from '../../../components/context-menu';
|
import ContextMenu from '../../../components/context-menu';
|
||||||
import ModalPortal from '../../../../components/modal-portal';
|
|
||||||
import PeoplesDialog from '../../../components/dialog/peoples-dialog';
|
|
||||||
import { gettext } from '../../../../utils/constants';
|
import { gettext } from '../../../../utils/constants';
|
||||||
import { Dirent } from '../../../../models';
|
import { Dirent } from '../../../../models';
|
||||||
import { useFileOperations } from '../../../../hooks/file-operations';
|
import { useFileOperations } from '../../../../hooks/file-operations';
|
||||||
import { GALLERY_OPERATION_KEYS } from '../../../constants';
|
import { GALLERY_OPERATION_KEYS } from '../../../constants';
|
||||||
|
|
||||||
const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveImage, onAddImage, onSetPeoplePhoto }) => {
|
const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveImage, onAddImage, onSetPeoplePhoto }) => {
|
||||||
const [isPeoplesDialogShow, setPeoplesDialogShow] = useState(false);
|
|
||||||
|
|
||||||
const { handleDownload: handleDownloadAPI, handleCopy: handleCopyAPI } = useFileOperations();
|
const { handleDownload: handleDownloadAPI, handleCopy: handleCopyAPI } = useFileOperations();
|
||||||
|
|
||||||
const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow();
|
const checkCanDeleteRow = window.sfMetadataContext.checkCanDeleteRow();
|
||||||
@@ -22,22 +18,39 @@ const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveIma
|
|||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
let validOptions = [{ value: GALLERY_OPERATION_KEYS.DOWNLOAD, label: gettext('Download') }];
|
let validOptions = [{ value: GALLERY_OPERATION_KEYS.DOWNLOAD, label: gettext('Download') }];
|
||||||
if (onDelete && checkCanDeleteRow) {
|
if (onDelete && checkCanDeleteRow) {
|
||||||
validOptions.push({ value: GALLERY_OPERATION_KEYS.DELETE, label: gettext('Delete') });
|
validOptions.push({
|
||||||
|
value: GALLERY_OPERATION_KEYS.DELETE,
|
||||||
|
label: gettext('Delete')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (onDuplicate && canDuplicateRow && selectedImages.length === 1) {
|
if (onDuplicate && canDuplicateRow && selectedImages.length === 1) {
|
||||||
validOptions.push({ value: GALLERY_OPERATION_KEYS.DUPLICATE, label: gettext('Copy') });
|
validOptions.push({
|
||||||
|
value: GALLERY_OPERATION_KEYS.COPY,
|
||||||
|
label: gettext('Copy')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (onRemoveImage && canRemovePhotoFromPeople) {
|
if (onRemoveImage && canRemovePhotoFromPeople) {
|
||||||
validOptions.push({ value: GALLERY_OPERATION_KEYS.REMOVE, label: gettext('Remove from this group') });
|
validOptions.push({
|
||||||
|
value: GALLERY_OPERATION_KEYS.REMOVE_PHOTO_FROM_CURRENT_SET,
|
||||||
|
label: gettext('Remove from this group')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (onAddImage && canAddPhotoToPeople) {
|
if (onAddImage && canAddPhotoToPeople) {
|
||||||
validOptions.push({ value: GALLERY_OPERATION_KEYS.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) {
|
if (onSetPeoplePhoto && canSetPeoplePhoto && selectedImages.length === 1) {
|
||||||
validOptions.push({ value: GALLERY_OPERATION_KEYS.SET_PEOPLE_PHOTO, label: gettext('Set as cover photo') });
|
validOptions.push({
|
||||||
|
value: GALLERY_OPERATION_KEYS.SET_PHOTO_AS_COVER,
|
||||||
|
label: gettext('Set as cover photo')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return validOptions;
|
return validOptions;
|
||||||
}, [checkCanDeleteRow, canDuplicateRow, canRemovePhotoFromPeople, canAddPhotoToPeople, selectedImages, onDuplicate, onDelete, onRemoveImage, onAddImage, canSetPeoplePhoto, onSetPeoplePhoto]);
|
}, [checkCanDeleteRow, canDuplicateRow, canRemovePhotoFromPeople,
|
||||||
|
canAddPhotoToPeople, selectedImages, onDuplicate, onDelete,
|
||||||
|
onRemoveImage, onAddImage, canSetPeoplePhoto, onSetPeoplePhoto]);
|
||||||
|
|
||||||
const handleDuplicate = useCallback((destRepo, dirent, destPath, nodeParentPath, isByDialog) => {
|
const handleDuplicate = useCallback((destRepo, dirent, destPath, nodeParentPath, isByDialog) => {
|
||||||
const selectedImage = selectedImages[0];
|
const selectedImage = selectedImages[0];
|
||||||
@@ -68,44 +81,29 @@ const GalleryContextMenu = ({ selectedImages, onDelete, onDuplicate, onRemoveIma
|
|||||||
case GALLERY_OPERATION_KEYS.DELETE:
|
case GALLERY_OPERATION_KEYS.DELETE:
|
||||||
onDelete(selectedImages);
|
onDelete(selectedImages);
|
||||||
break;
|
break;
|
||||||
case GALLERY_OPERATION_KEYS.DUPLICATE:
|
case GALLERY_OPERATION_KEYS.COPY:
|
||||||
handleCopy();
|
handleCopy();
|
||||||
break;
|
break;
|
||||||
case GALLERY_OPERATION_KEYS.REMOVE:
|
case GALLERY_OPERATION_KEYS.REMOVE_PHOTO_FROM_CURRENT_SET:
|
||||||
onRemoveImage(selectedImages);
|
onRemoveImage(selectedImages);
|
||||||
break;
|
break;
|
||||||
case GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS:
|
case GALLERY_OPERATION_KEYS.ADD_PHOTO_TO_GROUPS:
|
||||||
setPeoplesDialogShow(true);
|
onAddImage();
|
||||||
break;
|
break;
|
||||||
case GALLERY_OPERATION_KEYS.SET_PEOPLE_PHOTO:
|
case GALLERY_OPERATION_KEYS.SET_PHOTO_AS_COVER:
|
||||||
onSetPeoplePhoto(selectedImages[0]);
|
onSetPeoplePhoto(selectedImages[0]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, [handleDownload, onDelete, selectedImages, handleCopy, onRemoveImage, onSetPeoplePhoto]);
|
}, [handleDownload, onDelete, selectedImages, handleCopy, onRemoveImage, onAddImage, onSetPeoplePhoto]);
|
||||||
|
|
||||||
const closePeoplesDialog = useCallback(() => {
|
|
||||||
setPeoplesDialogShow(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addPeople = useCallback((peopleIds, addedImages, callback) => {
|
|
||||||
onAddImage(peopleIds, addedImages, callback);
|
|
||||||
}, [onAddImage]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
options={options}
|
options={options}
|
||||||
ignoredTriggerElements={['.metadata-gallery-image-item', '.metadata-gallery-grid-image']}
|
ignoredTriggerElements={['.metadata-gallery-image-item', '.metadata-gallery-grid-image']}
|
||||||
onOptionClick={handleOptionClick}
|
onOptionClick={handleOptionClick}
|
||||||
/>
|
/>
|
||||||
{isPeoplesDialogShow && (
|
|
||||||
<ModalPortal>
|
|
||||||
<PeoplesDialog selectedImages={selectedImages} onToggle={closePeoplesDialog} onSubmit={addPeople} />
|
|
||||||
</ModalPortal>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -15,12 +15,13 @@ import { getEventClassName } from '../../../utils/dom';
|
|||||||
import { getColumns, getImageSize, getRowHeight } from './utils';
|
import { getColumns, getImageSize, getRowHeight } from './utils';
|
||||||
import ObjectUtils from '../../../utils/object';
|
import ObjectUtils from '../../../utils/object';
|
||||||
import { openFile } from '../../utils/file';
|
import { openFile } from '../../utils/file';
|
||||||
|
import PeoplesDialog from '../../components/dialog/peoples-dialog';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const OVER_SCAN_ROWS = 20;
|
const OVER_SCAN_ROWS = 20;
|
||||||
|
|
||||||
const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord, onRemoveImage, onAddImage, onSetPeoplePhoto }) => {
|
const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord, onRemoveImage, onAddImage, onSetPeoplePhoto, isSomeone }) => {
|
||||||
const [isFirstLoading, setFirstLoading] = useState(true);
|
const [isFirstLoading, setFirstLoading] = useState(true);
|
||||||
const [zoomGear, setZoomGear] = useState(0);
|
const [zoomGear, setZoomGear] = useState(0);
|
||||||
const [containerWidth, setContainerWidth] = useState(0);
|
const [containerWidth, setContainerWidth] = useState(0);
|
||||||
@@ -30,6 +31,7 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
const [imageIndex, setImageIndex] = useState(0);
|
const [imageIndex, setImageIndex] = useState(0);
|
||||||
const [selectedImages, setSelectedImages] = useState([]);
|
const [selectedImages, setSelectedImages] = useState([]);
|
||||||
const [lastSelectedImage, setLastSelectedImage] = useState(null);
|
const [lastSelectedImage, setLastSelectedImage] = useState(null);
|
||||||
|
const [isPeoplesDialogShow, setPeoplesDialogShow] = useState(false);
|
||||||
|
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const scrollContainer = useRef(null);
|
const scrollContainer = useRef(null);
|
||||||
@@ -193,8 +195,12 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
|
|
||||||
const updateSelectedImages = useCallback((selectedImages) => {
|
const updateSelectedImages = useCallback((selectedImages) => {
|
||||||
const ids = selectedImages.map(item => item.id);
|
const ids = selectedImages.map(item => item.id);
|
||||||
|
if (isSomeone != undefined) { // 'face recognition'
|
||||||
|
updateSelectedRecordIds(ids, selectedImages, isSomeone);
|
||||||
|
} else {
|
||||||
updateSelectedRecordIds(ids);
|
updateSelectedRecordIds(ids);
|
||||||
}, [updateSelectedRecordIds]);
|
}
|
||||||
|
}, [isSomeone, updateSelectedRecordIds]);
|
||||||
|
|
||||||
const handleClick = useCallback((event, image) => {
|
const handleClick = useCallback((event, image) => {
|
||||||
if (event.metaKey || event.ctrlKey) {
|
if (event.metaKey || event.ctrlKey) {
|
||||||
@@ -301,7 +307,22 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
});
|
});
|
||||||
}, [onRemoveImage, updateCurrentDirent, updateSelectedImages]);
|
}, [onRemoveImage, updateCurrentDirent, updateSelectedImages]);
|
||||||
|
|
||||||
const handleMakeSelectedAsCoverPhoto = useCallback((selectedImage) => {
|
const handleAddPhotoToGroup = useCallback((selectedImages) => {
|
||||||
|
setPeoplesDialogShow(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const closePeoplesDialog = useCallback(() => {
|
||||||
|
setPeoplesDialogShow(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addPhotoToGroup = useCallback((peopleIds, addedImages, callback) => {
|
||||||
|
onAddImage(peopleIds, addedImages, callback);
|
||||||
|
updateCurrentDirent();
|
||||||
|
setSelectedImages([]);
|
||||||
|
updateSelectedImages([]);
|
||||||
|
}, [onAddImage, updateCurrentDirent, updateSelectedImages]);
|
||||||
|
|
||||||
|
const setSelectedImageAsCover = useCallback((selectedImage) => {
|
||||||
onSetPeoplePhoto(selectedImage, {
|
onSetPeoplePhoto(selectedImage, {
|
||||||
success_callback: () => {
|
success_callback: () => {
|
||||||
updateCurrentDirent();
|
updateCurrentDirent();
|
||||||
@@ -409,11 +430,17 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
});
|
});
|
||||||
|
|
||||||
const unsubscribeSelectNone = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SELECT_NONE, selectNone);
|
const unsubscribeSelectNone = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SELECT_NONE, selectNone);
|
||||||
|
const unsubscribeRemovePhotosFromCurrentSet = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.REMOVE_PHOTOS_FROM_CURRENT_SET, handleRemoveSelectedImages);
|
||||||
|
const unsubscribeSetPhotoAsCover = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SET_PHOTO_AS_COVER, setSelectedImageAsCover);
|
||||||
|
const unsubscribeAddPhotoToGroups = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.ADD_PHOTO_TO_GROUPS, handleAddPhotoToGroup);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
container && resizeObserver.unobserve(container);
|
container && resizeObserver.unobserve(container);
|
||||||
modifyGalleryZoomGearSubscribe();
|
modifyGalleryZoomGearSubscribe();
|
||||||
unsubscribeSelectNone();
|
unsubscribeSelectNone();
|
||||||
|
unsubscribeRemovePhotosFromCurrentSet();
|
||||||
|
unsubscribeSetPhotoAsCover();
|
||||||
|
unsubscribeAddPhotoToGroups();
|
||||||
switchGalleryModeSubscribe();
|
switchGalleryModeSubscribe();
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -481,8 +508,8 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
onDelete={handleDeleteSelectedImages}
|
onDelete={handleDeleteSelectedImages}
|
||||||
onDuplicate={duplicateRecord}
|
onDuplicate={duplicateRecord}
|
||||||
onRemoveImage={onRemoveImage ? handleRemoveSelectedImages : null}
|
onRemoveImage={onRemoveImage ? handleRemoveSelectedImages : null}
|
||||||
onAddImage={onAddImage}
|
onAddImage={onAddImage ? handleAddPhotoToGroup : null}
|
||||||
onSetPeoplePhoto={handleMakeSelectedAsCoverPhoto}
|
onSetPeoplePhoto={setSelectedImageAsCover}
|
||||||
/>
|
/>
|
||||||
{isImagePopupOpen && (
|
{isImagePopupOpen && (
|
||||||
<ModalPortal>
|
<ModalPortal>
|
||||||
@@ -498,6 +525,11 @@ const Main = ({ isLoadingMore, metadata, onDelete, onLoadMore, duplicateRecord,
|
|||||||
/>
|
/>
|
||||||
</ModalPortal>
|
</ModalPortal>
|
||||||
)}
|
)}
|
||||||
|
{isPeoplesDialogShow && (
|
||||||
|
<ModalPortal>
|
||||||
|
<PeoplesDialog selectedImages={selectedImages} onToggle={closePeoplesDialog} onSubmit={addPhotoToGroup} />
|
||||||
|
</ModalPortal>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -2473,7 +2473,13 @@ class LibContentView extends React.Component {
|
|||||||
})}>
|
})}>
|
||||||
{isDirentSelected ? (
|
{isDirentSelected ? (
|
||||||
currentMode === TAGS_MODE || currentMode === METADATA_MODE ? (
|
currentMode === TAGS_MODE || currentMode === METADATA_MODE ? (
|
||||||
<MetadataPathToolbar repoID={repoID} repoInfo={currentRepoInfo} mode={currentMode} path={path} viewId={viewId} />
|
<MetadataPathToolbar
|
||||||
|
repoID={repoID}
|
||||||
|
repoInfo={currentRepoInfo}
|
||||||
|
mode={currentMode}
|
||||||
|
path={path}
|
||||||
|
viewId={viewId}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SelectedDirentsToolbar
|
<SelectedDirentsToolbar
|
||||||
repoID={this.props.repoID}
|
repoID={this.props.repoID}
|
||||||
|
Reference in New Issue
Block a user