Skip to content

Commit

Permalink
optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
zhouwenxuan authored and zhouwenxuan committed Jan 4, 2025
1 parent d9e3407 commit 68b6c2a
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 157 deletions.
17 changes: 0 additions & 17 deletions frontend/src/metadata/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
15 changes: 0 additions & 15 deletions frontend/src/metadata/store/operations/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/metadata/store/operations/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = [
Expand Down
122 changes: 23 additions & 99 deletions frontend/src/metadata/views/map/cluster-photos/index.js
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -119,27 +48,22 @@ const ClusterPhotos = ({ view, markerIds, onClose, onDelete }) => {
}, []);

return (
isLoading ? (
<CenteredLoading />
) : (
<div className="sf-metadata-view-map sf-metadata-map-photos-container">
<div className="sf-metadata-map-photos-header" onClick={onClose}>
<div className="sf-metadata-map-photos-header-back">
<i className="sf3-font sf3-font-arrow rotate-180"></i>
</div>
<div className="sf-metadata-map-location">{gettext('Location')}</div>
<div className="sf-metadata-view-map sf-metadata-map-photos-container">
<div className="sf-metadata-map-photos-header">
<div className="sf-metadata-map-photos-header-back" onClick={onClose}>
<i className="sf3-font sf3-font-arrow rotate-180"></i>
</div>
<Gallery metadata={metadata} onDelete={handelDelete} />
<div className="sf-metadata-map-location">{gettext('Location')}</div>
</div>
)
<Gallery metadata={clusterMetadata} onDelete={handelDelete} duplicateRecord={duplicateRecord} onAddFolder={addFolder} />
</div>
);
};

ClusterPhotos.propTypes = {
view: PropTypes.object,
metadata: PropTypes.object,
markerIds: PropTypes.array,
onClose: PropTypes.func,
onDelete: PropTypes.func,
};

export default ClusterPhotos;
8 changes: 2 additions & 6 deletions frontend/src/metadata/views/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import './index.css';
const Map = () => {
const [showGallery, setShowGallery] = useState(false);
const [markerIds, setMarkerIds] = useState([]);
const { metadata, store } = useMetadataView();
const { metadata } = useMetadataView();

const repoID = window.sfMetadataContext.getSetting('repoID');

Expand Down Expand Up @@ -51,18 +51,14 @@ const Map = () => {
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_MAP_VIEW_TOOLBAR, false);
}, []);

const onDeleteLocationPhotos = useCallback((ids) => {
store.deleteLocationPhotos(ids);
}, [store]);

useEffect(() => {
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.MAP_VIEW, metadata.view);
}, [metadata.view]);

return (
<>
{showGallery ? (
<ClusterPhotos view={metadata.view} markerIds={markerIds} onClose={closeGallery} onDelete={onDeleteLocationPhotos} />
<ClusterPhotos metadata={metadata} markerIds={markerIds} onClose={closeGallery} />
) : (
<Main validImages={validImages} onOpen={openGallery} />
)}
Expand Down
34 changes: 25 additions & 9 deletions frontend/src/metadata/views/map/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,26 @@ const Main = ({ validImages, onOpen }) => {
}
}, []);

const saveMapState = useCallback(() => {
if (!mapRef.current) return;
const point = mapRef.current.getCenter && mapRef.current.getCenter();
const zoom = mapRef.current.getZoom && mapRef.current.getZoom();
window.sfMetadataContext.localStorage.setItem('map-center', point);
window.sfMetadataContext.localStorage.setItem('map-zoom', zoom);
}, []);

const loadMapState = useCallback(() => {
const savedCenter = window.sfMetadataContext.localStorage.getItem('map-center') || DEFAULT_POSITION;
const savedZoom = window.sfMetadataContext.localStorage.getItem('map-zoom') || DEFAULT_ZOOM;
return { center: savedCenter, zoom: savedZoom };
}, []);

const onClickMarker = useCallback((e, markers) => {
saveMapState();

const imageIds = markers.map(marker => marker._imageId);
onOpen(imageIds);
}, [onOpen]);
}, [onOpen, saveMapState]);

const renderMarkersBatch = useCallback(() => {
if (!validImages.length || !clusterRef.current) return;
Expand Down Expand Up @@ -110,23 +126,23 @@ const Main = ({ validImages, onOpen }) => {

const renderBaiduMap = useCallback(() => {
if (!mapRef.current || !window.BMap.Map) return;
let mapCenter = window.sfMetadataContext.localStorage.getItem('map-center') || DEFAULT_POSITION;
let { center, zoom } = loadMapState();
// ask for user location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((userInfo) => {
mapCenter = { lng: userInfo.coords.longitude, lat: userInfo.coords.latitude };
window.sfMetadataContext.localStorage.setItem('map-center', mapCenter);
center = { lng: userInfo.coords.longitude, lat: userInfo.coords.latitude };
window.sfMetadataContext.localStorage.setItem('map-center', center);
});
}
if (!isValidPosition(mapCenter?.lng, mapCenter?.lat)) return;
if (!isValidPosition(center?.lng, center?.lat)) return;

const gcPosition = wgs84_to_gcj02(mapCenter.lng, mapCenter.lat);
const gcPosition = wgs84_to_gcj02(center.lng, center.lat);
const bdPosition = gcj02_to_bd09(gcPosition.lng, gcPosition.lat);
const { lng, lat } = bdPosition;

mapRef.current = new window.BMap.Map('sf-metadata-map-container', { enableMapClick: false });
const point = new window.BMap.Point(lng, lat);
mapRef.current.centerAndZoom(point, DEFAULT_ZOOM);
mapRef.current.centerAndZoom(point, zoom);
mapRef.current.enableScrollWheelZoom(true);

const savedValue = window.sfMetadataContext.localStorage.getItem('map-type');
Expand All @@ -138,7 +154,7 @@ const Main = ({ validImages, onOpen }) => {

batchIndexRef.current = 0;
renderMarkersBatch();
}, [addMapController, initializeClusterer, initializeUserMarker, renderMarkersBatch, getMapType]);
}, [addMapController, initializeClusterer, initializeUserMarker, renderMarkersBatch, getMapType, loadMapState]);

useEffect(() => {
const switchMapTypeSubscribe = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SWITCH_MAP_TYPE, (newType) => {
Expand All @@ -150,7 +166,7 @@ const Main = ({ validImages, onOpen }) => {
switchMapTypeSubscribe();
};

}, [getMapType]);
}, [getMapType, saveMapState]);

useEffect(() => {
if (mapInfo.type === MAP_PROVIDER.B_MAP) {
Expand Down
21 changes: 19 additions & 2 deletions frontend/src/metadata/views/map/overlay/custom-image-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,30 @@ const customImageOverlay = (center, image, callback) => {
this._div.append(label);

const eventHandler = (event) => {
event.stopPropagation();
event.preventDefault();
this._callback && this._callback(event, [{ _imageId: this._imageId }]);
};

if (Utils.isDesktop()) {
this._div.addEventListener('click', eventHandler);
let clickTimeout;
this._div.addEventListener('click', (event) => {
if (clickTimeout) {
clearTimeout(clickTimeout);
clickTimeout = null;
return;
}
clickTimeout = setTimeout(() => {
eventHandler(event);
clickTimeout = null;
}, 300);
});
this._div.addEventListener('dblclick', (e) => {
e.preventDefault();
if (clickTimeout) {
clearTimeout(clickTimeout);
clickTimeout = null;
}
});
} else {
this._div.addEventListener('touchend', eventHandler);
}
Expand Down
Loading

0 comments on commit 68b6c2a

Please sign in to comment.