1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-09 10:50:24 +00:00
Files
seahub/frontend/src/metadata/hooks/metadata.js

180 lines
6.0 KiB
JavaScript
Raw Normal View History

import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import metadataAPI from '../api';
import { Utils } from '../../utils/utils';
import toaster from '../../components/toast';
import { gettext } from '../../utils/constants';
import { PRIVATE_FILE_TYPE } from '../../constants';
// This hook provides content related to seahub interaction, such as whether to enable extended attributes, views data, etc.
const MetadataContext = React.createContext(null);
export const MetadataProvider = ({ repoID, hideMetadataView, selectMetadataView, renameMetadataView, children }) => {
const enableMetadataManagement = useMemo(() => {
return window.app.pageOptions.enableMetadataManagement;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [window.app.pageOptions.enableMetadataManagement]);
const [enableMetadata, setEnableExtendedProperties] = useState(false);
const [showFirstView, setShowFirstView] = useState(false);
const [navigation, setNavigation] = useState([]);
const viewsMap = useRef({});
useEffect(() => {
if (!enableMetadataManagement) {
setEnableExtendedProperties(false);
return;
}
metadataAPI.getMetadataStatus(repoID).then(res => {
setEnableExtendedProperties(res.data.enabled);
}).catch(error => {
const errorMsg = Utils.getErrorMsg(error, true);
toaster.danger(errorMsg);
setEnableExtendedProperties(false);
});
}, [repoID, enableMetadataManagement]);
const updateEnableMetadata = useCallback((newValue) => {
if (newValue === enableMetadata) return;
if (!newValue) {
hideMetadataView && hideMetadataView();
} else {
setShowFirstView(true);
}
setEnableExtendedProperties(newValue);
}, [enableMetadata, hideMetadataView]);
// views
useEffect(() => {
if (enableMetadata) {
metadataAPI.listViews(repoID).then(res => {
const { navigation, views } = res.data;
if (Array.isArray(views)) {
views.forEach(view => {
viewsMap.current[view._id] = view;
});
}
setNavigation(navigation);
}).catch(error => {
const errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
return;
}
// If attribute extension is turned off, unmark the URL
const { origin, pathname, search } = window.location;
const urlParams = new URLSearchParams(search);
const viewID = urlParams.get('view');
if (viewID) {
const url = `${origin}${pathname}`;
window.history.pushState({ url: url, path: '' }, '', url);
}
viewsMap.current = {};
setNavigation([]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [repoID, enableMetadata]);
const selectView = useCallback((view, isSelected) => {
if (isSelected) return;
const node = {
children: [],
path: '/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/' + view.name,
isExpanded: false,
isLoaded: true,
isPreload: true,
object: {
file_tags: [],
id: PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES,
name: gettext('File extended properties'),
type: PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES,
isDir: () => false,
},
parentNode: {},
key: repoID,
view_id: view._id,
};
selectMetadataView(node);
setShowFirstView(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [repoID, selectMetadataView]);
const addView = useCallback((name, successCallback, failCallback) => {
metadataAPI.addView(repoID, name).then(res => {
const view = res.data.view;
let newNavigation = navigation.slice(0);
newNavigation.push({ _id: view._id, type: 'view' });
viewsMap.current[view._id] = view;
setNavigation(newNavigation);
selectView(view);
successCallback && successCallback();
}).catch(error => {
failCallback && failCallback(error);
});
}, [navigation, repoID, viewsMap, selectView]);
const deleteView = useCallback((viewId, isSelected) => {
metadataAPI.deleteView(repoID, viewId).then(res => {
const newNavigation = navigation.filter(item => item._id !== viewId);
delete viewsMap.current[viewId];
setNavigation(newNavigation);
if (isSelected) {
const currentViewIndex = navigation.findIndex(item => item._id === viewId);
const lastViewId = navigation[currentViewIndex - 1]._id;
const lastView = viewsMap.current[lastViewId];
selectView(lastView);
}
}).catch((error => {
const errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
}));
}, [repoID, navigation, selectView, viewsMap]);
const updateView = useCallback((viewId, update, successCallback, failCallback) => {
metadataAPI.modifyView(repoID, viewId, update).then(res => {
const currentView = viewsMap.current[viewId];
viewsMap.current[viewId] = { ...currentView, ...update };
if (Object.prototype.hasOwnProperty.call(update, 'name')) {
renameMetadataView(viewId, '/' + PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES + '/' + update['name']);
}
successCallback && successCallback();
}).catch(error => {
failCallback && failCallback(error);
});
}, [repoID, viewsMap, renameMetadataView]);
const moveView = useCallback((sourceViewId, targetViewId) => {
metadataAPI.moveView(repoID, sourceViewId, targetViewId).then(res => {
const { navigation } = res.data;
setNavigation(navigation);
}).catch(error => {
const errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
}, [repoID]);
return (
<MetadataContext.Provider value={{
enableMetadata,
updateEnableMetadata,
showFirstView,
navigation,
viewsMap: viewsMap.current,
selectView,
addView,
deleteView,
updateView,
moveView,
}}>
{children}
</MetadataContext.Provider>
);
};
export const useMetadata = () => {
const context = useContext(MetadataContext);
if (!context) {
throw new Error('\'MetadataContext\' is null');
}
return context;
};