diff --git a/frontend/src/metadata/store/index.js b/frontend/src/metadata/store/index.js
index a07a40a2f5d..64a08bd3978 100644
--- a/frontend/src/metadata/store/index.js
+++ b/frontend/src/metadata/store/index.js
@@ -622,23 +622,6 @@ class Store {
});
this.applyOperation(operation);
};
-
- // map
- deleteLocationPhotos = (rows_ids) => {
- if (!Array.isArray(rows_ids) || rows_ids.length === 0) return;
-
- const type = OPERATION_TYPE.DELETE_LOCATION_PHOTOS;
- const valid_rows_ids = rows_ids.filter((rowId) => {
- const row = getRowById(this.data, rowId);
- return row && this.context.canModifyRow(row);
- });
- const deleted_rows = valid_rows_ids.map((rowId) => getRowById(this.data, rowId));
- const operation = this.createOperation({
- type, repo_id: this.repoId, rows_ids, deleted_rows
- });
- this.applyOperation(operation);
- };
-
}
export default Store;
diff --git a/frontend/src/metadata/store/operations/apply.js b/frontend/src/metadata/store/operations/apply.js
index 64df8f7eca7..7e809ea710b 100644
--- a/frontend/src/metadata/store/operations/apply.js
+++ b/frontend/src/metadata/store/operations/apply.js
@@ -335,21 +335,6 @@ export default function apply(data, operation) {
return data;
}
- // map
- case OPERATION_TYPE.DELETE_LOCATION_PHOTOS: {
- const { rows_ids } = operation;
- const idNeedDeletedMap = rows_ids.reduce((currIdNeedDeletedMap, rowId) => ({ ...currIdNeedDeletedMap, [rowId]: true }), {});
- data.rows = data.rows.filter((row) => !idNeedDeletedMap[row._id]);
- data.recordsCount = data.rows.length;
- // delete rows in id_row_map
- rows_ids.forEach(rowId => {
- delete data.id_row_map[rowId];
- });
-
- data.row_ids = data.row_ids.filter(row_id => !idNeedDeletedMap[row_id]);
- return data;
- }
-
default: {
return data;
}
diff --git a/frontend/src/metadata/store/operations/constants.js b/frontend/src/metadata/store/operations/constants.js
index ee4ce655038..2872778e2a8 100644
--- a/frontend/src/metadata/store/operations/constants.js
+++ b/frontend/src/metadata/store/operations/constants.js
@@ -34,9 +34,6 @@ export const OPERATION_TYPE = {
// tag
UPDATE_FILE_TAGS: 'update_file_tags',
-
- // map
- DELETE_LOCATION_PHOTOS: 'delete_location_photos',
};
export const COLUMN_DATA_OPERATION_TYPE = {
@@ -77,8 +74,6 @@ export const OPERATION_ATTRIBUTES = {
[OPERATION_TYPE.MODIFY_SETTINGS]: ['repo_id', 'view_id', 'settings'],
[OPERATION_TYPE.UPDATE_FILE_TAGS]: ['repo_id', 'file_tags_data'],
-
- [OPERATION_TYPE.DELETE_LOCATION_PHOTOS]: ['repo_id', 'rows_ids', 'deleted_rows'],
};
export const UNDO_OPERATION_TYPE = [
diff --git a/frontend/src/metadata/views/map/cluster-photos/index.js b/frontend/src/metadata/views/map/cluster-photos/index.js
index 921b1645e70..4fc69e70c2d 100644
--- a/frontend/src/metadata/views/map/cluster-photos/index.js
+++ b/frontend/src/metadata/views/map/cluster-photos/index.js
@@ -1,114 +1,43 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import deepCopy from 'deep-copy';
-import { CenteredLoading } from '@seafile/sf-metadata-ui-component';
import Gallery from '../../gallery/main';
import { gettext } from '../../../../utils/constants';
-import { EVENT_BUS_TYPE, PER_LOAD_NUMBER } from '../../../constants';
+import { EVENT_BUS_TYPE } from '../../../constants';
import metadataAPI from '../../../api';
-import { normalizeColumns } from '../../../utils/column';
-import Metadata from '../../../model/metadata';
import { Utils } from '../../../../utils/utils';
import toaster from '../../../../components/toast';
import { useMetadataView } from '../../../hooks/metadata-view';
import './index.css';
-const ClusterPhotos = ({ view, markerIds, onClose, onDelete }) => {
- const [isLoading, setLoading] = useState(true);
- const [metadata, setMetadata] = useState({ rows: [] });
-
- const { deleteFilesCallback } = useMetadataView();
+const ClusterPhotos = ({ metadata, markerIds, onClose }) => {
+ const { store, duplicateRecord, addFolder } = useMetadataView();
const repoID = window.sfMetadataContext.getSetting('repoID');
- const loadData = useCallback((view) => {
- setLoading(true);
- const params = {
- view_id: view._id,
- start: 0,
- limit: PER_LOAD_NUMBER,
- };
- metadataAPI.getMetadata(repoID, params).then(res => {
- const rows = res?.data?.results || [];
- const filteredRows = rows.filter(row => markerIds.includes(row._id));
- const columns = normalizeColumns(res?.data?.metadata);
- const metadata = new Metadata({ rows: filteredRows, columns, view });
- metadata.hasMore = rows.length >= PER_LOAD_NUMBER;
- setMetadata(metadata);
- window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.MAP_VIEW, metadata.view);
- setLoading(false);
- }).catch(error => {
- const errorMessage = Utils.getErrorMsg(error);
- toaster.danger(errorMessage);
- setLoading(false);
- });
- }, [repoID, markerIds]);
-
- const deletedByIds = useCallback((ids) => {
- if (!Array.isArray(ids) || ids.length === 0) return;
+ const clusterMetadata = useMemo(() => {
+ const filteredRows = metadata.rows.filter(row => markerIds.includes(row._id));
const newMetadata = deepCopy(metadata);
- const idNeedDeletedMap = ids.reduce((currIdNeedDeletedMap, rowId) => ({ ...currIdNeedDeletedMap, [rowId]: true }), {});
- newMetadata.rows = newMetadata.rows.filter((row) => !idNeedDeletedMap[row._id]);
- newMetadata.row_ids = newMetadata.row_ids.filter((id) => !idNeedDeletedMap[id]);
-
- // delete rows in id_row_map
- ids.forEach(rowId => {
- delete newMetadata.id_row_map[rowId];
- });
- newMetadata.recordsCount = newMetadata.row_ids.length;
- setMetadata(newMetadata);
-
- if (newMetadata.rows.length === 0) {
- onClose && onClose();
- }
-
- onDelete(ids);
- }, [metadata, onClose, onDelete]);
+ newMetadata.rows = filteredRows;
+ return newMetadata;
+ }, [metadata, markerIds]);
const handelDelete = useCallback((deletedImages, { success_callback } = {}) => {
if (!deletedImages.length) return;
let recordIds = [];
- let paths = [];
- let fileNames = [];
- deletedImages.forEach((record) => {
- const { id, parentDir, name } = record || {};
- if (parentDir && name) {
- const path = Utils.joinPath(parentDir, name);
- paths.push(path);
- fileNames.push(name);
- recordIds.push(id);
- }
- });
- window.sfMetadataContext.batchDeleteFiles(repoID, paths).then(res => {
- deletedByIds(recordIds);
- 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();
- }).catch(error => {
- toaster.danger(gettext('Failed to delete records'));
- });
- }, [deleteFilesCallback, repoID, deletedByIds]);
+ deletedImages.forEach((record) => recordIds.push(record.id));
+ store.deleteRecords(recordIds, { success_callback });
+ }, [store]);
const handleViewChange = useCallback((update) => {
- metadataAPI.modifyView(repoID, view._id, update).then(res => {
- const newView = { ...view, ...update };
- loadData(newView);
+ metadataAPI.modifyView(repoID, metadata.view._id, update).then(res => {
+
}).catch(error => {
const errorMessage = Utils.getErrorMsg(error);
toaster.danger(errorMessage);
});
- }, [view, repoID, loadData]);
-
- useEffect(() => {
- loadData({ _id: view._id, sorts: view.sorts });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [metadata, repoID,]);
useEffect(() => {
const unsubscribeViewChange = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.MAP_GALLERY_VIEW_CHANGE, handleViewChange);
@@ -119,27 +48,22 @@ const ClusterPhotos = ({ view, markerIds, onClose, onDelete }) => {
}, []);
return (
- isLoading ? (
-