From ac124d20ba02feccd291a10b977b28d576c7b15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=9B=BD=E7=92=87?= <37972689+YangGuoXuan-0503@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:56:29 +0800 Subject: [PATCH] feat: metadata details settings (#7145) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: metadata details settings * feat: optimize code * feat: optimize code * feat: optimize code * feat: optimize code * feat: optimize code * feat: optimize code * feat: optimize code --------- Co-authored-by: 杨国璇 Co-authored-by: 杨国璇 --- frontend/src/assets/icons/set-up.svg | 2 +- .../dirent-detail/detail/header/index.css | 21 +- .../dirent-detail/detail/header/index.js | 16 +- .../detail/header/title/index.css | 23 ++ .../detail/header/title/index.js | 24 ++ .../dirent-details/dir-details.js | 10 +- .../dirent-details/file-details/index.js | 16 +- .../dirent-detail/dirent-details/index.js | 86 ++++--- .../dirent-detail/dirent-details/utils.js | 2 +- .../embedded-file-details/file-details.js | 7 +- .../embedded-file-details/index.js | 48 ++-- .../src/components/dirent-detail/index.js | 8 +- .../src/components/file-view/file-view.js | 5 +- frontend/src/constants/index.js | 5 + frontend/src/hooks/metadata-status.js | 17 +- frontend/src/metadata/api.js | 6 + .../components/metadata-details/constants.js | 8 +- .../components/metadata-details/index.js | 168 ++------------ .../metadata-details/location/index.js | 2 +- .../metadata-details/settings/index.css | 0 .../metadata-details/settings/index.js | 46 ++++ .../components/metadata-details/utils.js | 11 +- .../hidden-columns/hide-column.js | 183 ++++++++------- .../hidden-columns/index.js | 36 +-- .../popover/hidden-column-popover/index.css | 4 + .../view-toolbar/kanban-view-toolbar/index.js | 7 +- frontend/src/metadata/hooks/index.js | 1 + .../src/metadata/hooks/metadata-details.js | 211 ++++++++++++++++++ frontend/src/metadata/utils/row/core.js | 1 + .../header-toolbar/header-toolbar.js | 4 +- frontend/src/pages/sdoc/sdoc-editor/index.css | 10 + frontend/src/pages/sdoc/sdoc-editor/index.js | 4 +- frontend/src/view-file-sdoc.js | 5 +- media/css/sf_font3/iconfont.css | 12 +- media/css/sf_font3/iconfont.eot | Bin 29872 -> 29884 bytes media/css/sf_font3/iconfont.svg | 4 +- media/css/sf_font3/iconfont.ttf | Bin 29704 -> 29716 bytes media/css/sf_font3/iconfont.woff | Bin 17584 -> 17600 bytes media/css/sf_font3/iconfont.woff2 | Bin 14860 -> 14836 bytes seahub/repo_metadata/apis.py | 62 ++++- seahub/repo_metadata/models.py | 1 + seahub/repo_metadata/urls.py | 5 +- seahub/templates/file_view_react.html | 1 + .../templates/markdown_file_view_react.html | 1 + seahub/views/file.py | 3 +- 45 files changed, 677 insertions(+), 409 deletions(-) create mode 100644 frontend/src/components/dirent-detail/detail/header/title/index.css create mode 100644 frontend/src/components/dirent-detail/detail/header/title/index.js create mode 100644 frontend/src/metadata/components/metadata-details/settings/index.css create mode 100644 frontend/src/metadata/components/metadata-details/settings/index.js create mode 100644 frontend/src/metadata/hooks/metadata-details.js diff --git a/frontend/src/assets/icons/set-up.svg b/frontend/src/assets/icons/set-up.svg index 95d4c3e52f2..f9bdefe0aa6 100644 --- a/frontend/src/assets/icons/set-up.svg +++ b/frontend/src/assets/icons/set-up.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/components/dirent-detail/detail/header/index.css b/frontend/src/components/dirent-detail/detail/header/index.css index 16a28182a93..4d61a1b4fa1 100644 --- a/frontend/src/components/dirent-detail/detail/header/index.css +++ b/frontend/src/components/dirent-detail/detail/header/index.css @@ -9,28 +9,11 @@ padding: 8px 16px; } -.detail-header .detail-title { - display: flex; - flex: 1; - align-items: center; - width: 0; /* prevent strut flex layout */ -} - -.detail-header .detail-title .detail-header-icon-container { - height: 32px; - width: 32px; +.detail-header .detail-control-container { + flex-shrink: 0; display: flex; align-items: center; justify-content: center; - flex-shrink: 0; -} - -.detail-header .detail-title .name { - margin: 0 0.5rem 0 6px; - line-height: 1.5rem; - vertical-align: middle; - font-size: 1rem; - color: #212529; } .detail-header .detail-control { diff --git a/frontend/src/components/dirent-detail/detail/header/index.js b/frontend/src/components/dirent-detail/detail/header/index.js index c152f5c842b..1ff83603a89 100644 --- a/frontend/src/components/dirent-detail/detail/header/index.js +++ b/frontend/src/components/dirent-detail/detail/header/index.js @@ -1,21 +1,20 @@ import React from 'react'; import PropTypes from 'prop-types'; import Icon from '../../../icon'; +import Title from './title'; import './index.css'; -const Header = ({ title, icon, iconSize = 32, onClose, component = {} }) => { +const Header = ({ title, icon, iconSize = 32, onClose, children, component = {} }) => { const { closeIcon } = component; return (
-
-
- + + <div className="detail-control-container"> + {children} + <div className="detail-control" onClick={onClose}> + {closeIcon ? closeIcon : <Icon symbol="close" className="detail-control-close" />} </div> - <span className="name ellipsis" title={title}>{title}</span> - </div> - <div className="detail-control" onClick={onClose}> - {closeIcon ? closeIcon : <Icon symbol="close" className="detail-control-close" />} </div> </div> ); @@ -26,6 +25,7 @@ Header.propTypes = { icon: PropTypes.string.isRequired, iconSize: PropTypes.number, component: PropTypes.object, + children: PropTypes.any, onClose: PropTypes.func.isRequired, }; diff --git a/frontend/src/components/dirent-detail/detail/header/title/index.css b/frontend/src/components/dirent-detail/detail/header/title/index.css new file mode 100644 index 00000000000..8367432a87a --- /dev/null +++ b/frontend/src/components/dirent-detail/detail/header/title/index.css @@ -0,0 +1,23 @@ +.detail-header .detail-title { + display: flex; + flex: 1; + align-items: center; + width: 0; /* prevent strut flex layout */ +} + +.detail-header .detail-title .detail-header-icon-container { + height: 32px; + width: 32px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.detail-header .detail-title .name { + margin: 0 0.5rem 0 6px; + line-height: 1.5rem; + vertical-align: middle; + font-size: 1rem; + color: #212529; +} diff --git a/frontend/src/components/dirent-detail/detail/header/title/index.js b/frontend/src/components/dirent-detail/detail/header/title/index.js new file mode 100644 index 00000000000..a00f754583a --- /dev/null +++ b/frontend/src/components/dirent-detail/detail/header/title/index.js @@ -0,0 +1,24 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import './index.css'; + +const Title = ({ icon, iconSize, title }) => { + + return ( + <div className="detail-title dirent-title"> + <div className="detail-header-icon-container"> + <img src={icon} width={iconSize} height={iconSize} alt="" /> + </div> + <span className="name ellipsis" title={title}>{title}</span> + </div> + ); +}; + +Title.propTypes = { + icon: PropTypes.string, + iconSize: PropTypes.number, + title: PropTypes.string, +}; + +export default Title; diff --git a/frontend/src/components/dirent-detail/dirent-details/dir-details.js b/frontend/src/components/dirent-detail/dirent-details/dir-details.js index 7b0ea7244ac..dca1e3ac000 100644 --- a/frontend/src/components/dirent-detail/dirent-details/dir-details.js +++ b/frontend/src/components/dirent-detail/dirent-details/dir-details.js @@ -1,16 +1,14 @@ import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; import { Formatter } from '@seafile/sf-metadata-ui-component'; -import { getDirentPath } from './utils'; import DetailItem from '../detail-item'; import { CellType } from '../../../metadata/constants'; import { gettext } from '../../../utils/constants'; import { MetadataDetails } from '../../../metadata'; import { useMetadataStatus } from '../../../hooks'; -const DirDetails = ({ repoID, repoInfo, dirent, path, direntDetail }) => { - const direntPath = useMemo(() => getDirentPath(dirent, path), [dirent, path]); - const { enableMetadata } = useMetadataStatus(); +const DirDetails = ({ direntDetail }) => { + const { enableMetadata, enableMetadataManagement } = useMetadataStatus(); const lastModifiedTimeField = useMemo(() => { return { type: CellType.MTIME, name: gettext('Last modified time') }; }, []); @@ -20,8 +18,8 @@ const DirDetails = ({ repoID, repoInfo, dirent, path, direntDetail }) => { <DetailItem field={lastModifiedTimeField} className="sf-metadata-property-detail-formatter"> <Formatter field={lastModifiedTimeField} value={direntDetail.mtime} /> </DetailItem> - {window.app.pageOptions.enableMetadataManagement && enableMetadata && ( - <MetadataDetails repoID={repoID} repoInfo={repoInfo} filePath={direntPath} direntType="dir" /> + {enableMetadataManagement && enableMetadata && ( + <MetadataDetails /> )} </> ); diff --git a/frontend/src/components/dirent-detail/dirent-details/file-details/index.js b/frontend/src/components/dirent-detail/dirent-details/file-details/index.js index e11454bf3ab..eb06faa56a2 100644 --- a/frontend/src/components/dirent-detail/dirent-details/file-details/index.js +++ b/frontend/src/components/dirent-detail/dirent-details/file-details/index.js @@ -10,7 +10,7 @@ import { gettext } from '../../../../utils/constants'; import EditFileTagPopover from '../../../popover/edit-filetag-popover'; import FileTagList from '../../../file-tag-list'; import { Utils } from '../../../../utils/utils'; -import { MetadataDetails } from '../../../../metadata'; +import { MetadataDetails, useMetadataDetails } from '../../../../metadata'; import ObjectUtils from '../../../../metadata/utils/object-utils'; import { getCellValueByColumn, getDateDisplayString, decimalToExposureTime } from '../../../../metadata/utils/cell'; import Collapse from './collapse'; @@ -57,10 +57,10 @@ const getImageInfoValue = (key, value) => { } }; -const FileDetails = React.memo(({ repoID, repoInfo, dirent, path, direntDetail, onFileTagChanged, repoTags, fileTagList }) => { +const FileDetails = React.memo(({ repoID, dirent, path, direntDetail, onFileTagChanged, repoTags, fileTagList }) => { const [isEditFileTagShow, setEditFileTagShow] = useState(false); - const { enableMetadata } = useMetadataStatus(); - const [record, setRecord] = useState(null); + const { enableMetadataManagement, enableMetadata } = useMetadataStatus(); + const { record } = useMetadataDetails(); const direntPath = useMemo(() => getDirentPath(dirent, path), [dirent, path]); const tagListTitleID = useMemo(() => `detail-list-view-tags-${uuidV4()}`, []); @@ -77,10 +77,6 @@ const FileDetails = React.memo(({ repoID, repoInfo, dirent, path, direntDetail, onFileTagChanged(dirent, direntPath); }, [dirent, direntPath, onFileTagChanged]); - const updateRecord = useCallback((record) => { - setRecord(record); - }, []); - const dom = ( <> <DetailItem field={sizeField} className="sf-metadata-property-detail-formatter"> @@ -116,8 +112,8 @@ const FileDetails = React.memo(({ repoID, repoInfo, dirent, path, direntDetail, </div> </DetailItem> )} - {window.app.pageOptions.enableMetadataManagement && enableMetadata && ( - <MetadataDetails repoID={repoID} filePath={direntPath} repoInfo={repoInfo} direntType="file" updateRecord={updateRecord} /> + {enableMetadataManagement && enableMetadata && ( + <MetadataDetails /> )} </> ); diff --git a/frontend/src/components/dirent-detail/dirent-details/index.js b/frontend/src/components/dirent-detail/dirent-details/index.js index 931f6b2dd9c..ace84a97a59 100644 --- a/frontend/src/components/dirent-detail/dirent-details/index.js +++ b/frontend/src/components/dirent-detail/dirent-details/index.js @@ -9,6 +9,9 @@ import { Detail, Header, Body } from '../detail'; import DirDetails from './dir-details'; import FileDetails from './file-details'; import ObjectUtils from '../../../metadata/utils/object-utils'; +import { MetadataDetailsProvider } from '../../../metadata/hooks'; +import Settings from '../../../metadata/components/metadata-details/settings'; +import { getDirentPath } from './utils'; import './index.css'; @@ -95,38 +98,59 @@ class DirentDetails extends React.Component { render() { const { dirent, direntDetail } = this.state; - const { repoID, path, fileTags } = this.props; + const { repoID, fileTags } = this.props; + + if (!dirent || !direntDetail) { + return ( + <Detail> + <Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={this.props.onClose} /> + <Body> + {this.renderImage()} + </Body> + </Detail> + ); + } + + let path = this.props.path; + if (dirent?.type !== 'file') { + path = this.props.dirent ? Utils.joinPath(path, dirent.name) : path; + } + return ( - <Detail> - <Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={this.props.onClose} /> - <Body> - {this.renderImage()} - {dirent && direntDetail && ( - <div className="detail-content"> - {dirent.type !== 'file' ? - <DirDetails - repoID={repoID} - repoInfo={this.props.currentRepoInfo} - dirent={dirent} - direntDetail={direntDetail} - path={this.props.dirent ? Utils.joinPath(path, dirent.name) : path} - /> - : - <FileDetails - repoID={repoID} - repoInfo={this.props.currentRepoInfo} - dirent={dirent} - path={path} - direntDetail={direntDetail} - repoTags={this.props.repoTags} - fileTagList={dirent ? dirent.file_tags : fileTags} - onFileTagChanged={this.props.onFileTagChanged} - /> - } - </div> - )} - </Body> - </Detail> + <MetadataDetailsProvider + repoID={repoID} + repoInfo={this.props.currentRepoInfo} + path={getDirentPath(dirent, path)} + dirent={dirent} + direntDetail={direntDetail} + direntType={dirent?.type !== 'file' ? 'dir' : 'file'} + > + <Detail> + <Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={this.props.onClose} > + <Settings /> + </Header> + <Body> + {this.renderImage()} + {dirent && direntDetail && ( + <div className="detail-content"> + {dirent.type !== 'file' ? ( + <DirDetails direntDetail={direntDetail} /> + ) : ( + <FileDetails + repoID={repoID} + dirent={dirent} + path={path} + direntDetail={direntDetail} + repoTags={this.props.repoTags} + fileTagList={dirent ? dirent.file_tags : fileTags} + onFileTagChanged={this.props.onFileTagChanged} + /> + )} + </div> + )} + </Body> + </Detail> + </MetadataDetailsProvider> ); } } diff --git a/frontend/src/components/dirent-detail/dirent-details/utils.js b/frontend/src/components/dirent-detail/dirent-details/utils.js index 2f7af6b1c02..2336cea886a 100644 --- a/frontend/src/components/dirent-detail/dirent-details/utils.js +++ b/frontend/src/components/dirent-detail/dirent-details/utils.js @@ -2,7 +2,7 @@ import { Utils } from '../../../utils/utils'; export const getDirentPath = (dirent, path) => { if (Utils.isMarkdownFile(path)) return path; // column mode: view file - return Utils.joinPath(path, dirent.name); + return Utils.joinPath(path, dirent?.name); }; export const getFileParent = (dirent, path) => { diff --git a/frontend/src/components/dirent-detail/embedded-file-details/file-details.js b/frontend/src/components/dirent-detail/embedded-file-details/file-details.js index 300d36f7f27..2ed2ae58946 100644 --- a/frontend/src/components/dirent-detail/embedded-file-details/file-details.js +++ b/frontend/src/components/dirent-detail/embedded-file-details/file-details.js @@ -8,7 +8,7 @@ import { Utils } from '../../../utils/utils'; import { MetadataDetails } from '../../../metadata'; import { useMetadataStatus } from '../../../hooks'; -const FileDetails = ({ repoID, repoInfo, path, direntDetail }) => { +const FileDetails = ({ direntDetail }) => { const { enableMetadata } = useMetadataStatus(); const sizeField = useMemo(() => ({ type: 'size', name: gettext('Size') }), []); @@ -36,16 +36,13 @@ const FileDetails = ({ repoID, repoInfo, path, direntDetail }) => { <Formatter field={lastModifiedTimeField} value={direntDetail.last_modified}/> </DetailItem> {enableMetadata && ( - <MetadataDetails repoID={repoID} filePath={path} repoInfo={repoInfo} direntType="file" /> + <MetadataDetails /> )} </> ); }; FileDetails.propTypes = { - repoID: PropTypes.string, - repoInfo: PropTypes.object, - path: PropTypes.string, direntDetail: PropTypes.object, }; diff --git a/frontend/src/components/dirent-detail/embedded-file-details/index.js b/frontend/src/components/dirent-detail/embedded-file-details/index.js index f7a560f4cf8..ea94d317f62 100644 --- a/frontend/src/components/dirent-detail/embedded-file-details/index.js +++ b/frontend/src/components/dirent-detail/embedded-file-details/index.js @@ -7,6 +7,8 @@ import toaster from '../../toast'; import { Header, Body } from '../detail'; import FileDetails from './file-details'; import { MetadataContext } from '../../../metadata'; +import { MetadataDetailsProvider } from '../../../metadata/hooks'; +import Settings from '../../../metadata/components/metadata-details/settings'; import './index.css'; @@ -36,27 +38,33 @@ const EmbeddedFileDetails = ({ repoID, repoInfo, dirent, path, onClose, width = }, []); return ( - <div - className={classnames('cur-view-detail', className, { - 'cur-view-detail-small': width < 400, - 'cur-view-detail-large': width > 400 - })} - style={{ width }} + <MetadataDetailsProvider + repoID={repoID} + repoInfo={repoInfo} + path={path} + dirent={dirent} + direntDetail={direntDetail} + direntType="file" > - <Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={onClose} component={headerComponent} /> - <Body> - {dirent && direntDetail && ( - <div className="detail-content"> - <FileDetails - repoID={repoID} - repoInfo={repoInfo} - path={path} - direntDetail={direntDetail} - /> - </div> - )} - </Body> - </div> + <div + className={classnames('cur-view-detail', className, { + 'cur-view-detail-small': width < 400, + 'cur-view-detail-large': width > 400 + })} + style={{ width }} + > + <Header title={dirent?.name || ''} icon={Utils.getDirentIcon(dirent, true)} onClose={onClose} component={headerComponent} > + <Settings /> + </Header> + <Body> + {dirent && direntDetail && ( + <div className="detail-content"> + <FileDetails direntDetail={direntDetail} /> + </div> + )} + </Body> + </div> + </MetadataDetailsProvider> ); }; diff --git a/frontend/src/components/dirent-detail/index.js b/frontend/src/components/dirent-detail/index.js index 8fabb6c6f91..838de2f95ed 100644 --- a/frontend/src/components/dirent-detail/index.js +++ b/frontend/src/components/dirent-detail/index.js @@ -31,13 +31,9 @@ const Detail = React.memo(({ repoID, path, dirent, currentRepoInfo, repoTags, fi } if (path === '/' && !dirent) { - return ( - <LibDetail - currentRepoInfo={currentRepoInfo} - onClose={onClose} - /> - ); + return (<LibDetail currentRepoInfo={currentRepoInfo} onClose={onClose} />); } + return ( <DirentDetail repoID={repoID} diff --git a/frontend/src/components/file-view/file-view.js b/frontend/src/components/file-view/file-view.js index 8992a431add..aebb6f9a7c2 100644 --- a/frontend/src/components/file-view/file-view.js +++ b/frontend/src/components/file-view/file-view.js @@ -31,7 +31,7 @@ const propTypes = { const { isStarred, isLocked, lockedByMe, repoID, filePath, filePerm, enableWatermark, userNickName, - fileName, repoEncrypted + fileName, repoEncrypted, isRepoAdmin } = window.app.pageOptions; class FileView extends React.Component { @@ -116,7 +116,8 @@ class FileView extends React.Component { const { isDetailsPanelOpen, isHeaderShown } = this.state; const repoInfo = { permission: filePerm, - encrypted: repoEncrypted + encrypted: repoEncrypted, + is_admin: isRepoAdmin, }; return ( <I18nextProvider i18n={ i18n }> diff --git a/frontend/src/constants/index.js b/frontend/src/constants/index.js index f369c58f785..1168a1ee234 100644 --- a/frontend/src/constants/index.js +++ b/frontend/src/constants/index.js @@ -38,3 +38,8 @@ export const MODE_TYPE_MAP = { RECENTLY_USED: 'recently_used', SEARCH_RESULTS: 'search_results', }; + +export const SYSTEM_FOLDERS = [ + '/_Internal', + '/images' +]; diff --git a/frontend/src/hooks/metadata-status.js b/frontend/src/hooks/metadata-status.js index 1aad544533d..687f660da6d 100644 --- a/frontend/src/hooks/metadata-status.js +++ b/frontend/src/hooks/metadata-status.js @@ -17,6 +17,7 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi const [enableMetadata, setEnableMetadata] = useState(false); const [enableTags, setEnableTags] = useState(false); const [tagsLang, setTagsLang] = useState('en'); + const [detailsSettings, setDetailsSettings] = useState({}); const [isBeingBuilt, setIsBeingBuilt] = useState(false); const cancelMetadataURL = useCallback(() => { @@ -37,12 +38,13 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi return; } metadataAPI.getMetadataStatus(repoID).then(res => { - const { enabled: enableMetadata, tags_enabled: enableTags, tags_lang: tagsLang } = res.data; + const { enabled: enableMetadata, tags_enabled: enableTags, tags_lang: tagsLang, details_settings: detailsSettings } = res.data; if (!enableMetadata) { cancelMetadataURL(); } setEnableTags(enableTags); setTagsLang(tagsLang || 'en'); + setDetailsSettings(JSON.parse(detailsSettings)); setEnableMetadata(enableMetadata); setLoading(false); }).catch(error => { @@ -60,6 +62,7 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi cancelMetadataURL(); setEnableTags(false); } + setDetailsSettings({}); setIsBeingBuilt(newValue); setEnableMetadata(newValue); }, [enableMetadata, cancelMetadataURL]); @@ -74,6 +77,16 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi setTagsLang(lang); }, [enableTags, tagsLang, cancelMetadataURL, hideMetadataView]); + const modifyDetailsSettings = useCallback((update) => { + metadataAPI.modifyMetadataDetailsSettings(repoID, update).then(res => { + const newDetailsSettings = { ...detailsSettings, ...update }; + setDetailsSettings(newDetailsSettings); + }).catch(error => { + const newDetailsSettings = { ...detailsSettings, ...update }; + setDetailsSettings(newDetailsSettings); + }); + }, [repoID, detailsSettings]); + return ( <EnableMetadataContext.Provider value={{ @@ -85,6 +98,8 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi enableTags, tagsLang, updateEnableTags, + detailsSettings, + modifyDetailsSettings, }} > {!isLoading && children} diff --git a/frontend/src/metadata/api.js b/frontend/src/metadata/api.js index 8c9f5419b0d..53d8f0669db 100644 --- a/frontend/src/metadata/api.js +++ b/frontend/src/metadata/api.js @@ -65,6 +65,12 @@ class MetadataManagerAPI { return this.req.delete(url); } + modifyMetadataDetailsSettings(repoID, settings) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/details-settings/'; + const data = { settings: settings }; + return this.req.put(url, data); + } + getMetadata(repoID, params) { const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/records/'; return this.req.get(url, { params: params }); diff --git a/frontend/src/metadata/components/metadata-details/constants.js b/frontend/src/metadata/components/metadata-details/constants.js index 12d7876bf66..1b811db4eed 100644 --- a/frontend/src/metadata/components/metadata-details/constants.js +++ b/frontend/src/metadata/components/metadata-details/constants.js @@ -1,4 +1,4 @@ -import { PRIVATE_COLUMN_KEY } from '../../constants'; +import { PRIVATE_COLUMN_KEY, CellType } from '../../constants'; export const NOT_DISPLAY_COLUMN_KEYS = [ PRIVATE_COLUMN_KEY.ID, @@ -23,11 +23,7 @@ export const NOT_DISPLAY_COLUMN_KEYS = [ PRIVATE_COLUMN_KEY.FACE_VECTORS, ]; -export const SYSTEM_FOLDERS = [ - '/_Internal', - '/images' -]; - export { PRIVATE_COLUMN_KEY, + CellType, }; diff --git a/frontend/src/metadata/components/metadata-details/index.js b/frontend/src/metadata/components/metadata-details/index.js index db7db7e68ef..9705e53fb69 100644 --- a/frontend/src/metadata/components/metadata-details/index.js +++ b/frontend/src/metadata/components/metadata-details/index.js @@ -1,159 +1,45 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import PropTypes from 'prop-types'; -import toaster from '../../../components/toast'; +import React, { useMemo } from 'react'; import CellFormatter from '../cell-formatter'; import DetailEditor from '../detail-editor'; import DetailItem from '../../../components/dirent-detail/detail-item'; import { Utils } from '../../../utils/utils'; -import metadataAPI from '../../api'; -import Column from '../../model/column'; -import { getCellValueByColumn, getOptionName, getColumnOptionNamesByIds, getColumnOptionNameById, getFileNameFromRecord, getRecordIdFromRecord, getFileObjIdFromRecord } from '../../utils/cell'; -import { normalizeFields } from './utils'; +import { getCellValueByColumn, getFileNameFromRecord } from '../../utils/cell'; import { gettext } from '../../../utils/constants'; -import { CellType, EVENT_BUS_TYPE, PREDEFINED_COLUMN_KEYS, PRIVATE_COLUMN_KEY } from '../../constants'; -import { getColumnByKey, getColumnOptions, getColumnOriginName } from '../../utils/column'; -import { SYSTEM_FOLDERS } from './constants'; +import { PRIVATE_COLUMN_KEY } from '../../constants'; import Location from './location'; +import { useMetadataDetails } from '../../hooks'; import { checkIsDir } from '../../utils/row'; -import tagsAPI from '../../../tag/api'; import './index.css'; -const MetadataDetails = ({ repoID, filePath, repoInfo, direntType, updateRecord }) => { - const [isLoading, setLoading] = useState(true); - const [metadata, setMetadata] = useState({ record: {}, fields: [] }); - const permission = useMemo(() => repoInfo.permission !== 'admin' && repoInfo.permission !== 'rw' ? 'r' : 'rw', [repoInfo]); +const MetadataDetails = () => { + const { isLoading, canModifyRecord, record, columns, onChange, modifyColumnData, updateFileTags } = useMetadataDetails(); - const onChange = useCallback((fieldKey, newValue) => { - const { record, fields } = metadata; - const field = getColumnByKey(fields, fieldKey); - const fileName = getColumnOriginName(field); - const recordId = getRecordIdFromRecord(record); - const fileObjId = getFileObjIdFromRecord(record); - let update = { [fileName]: newValue }; - if (field.type === CellType.SINGLE_SELECT) { - update = { [fileName]: getColumnOptionNameById(field, newValue) }; - } else if (field.type === CellType.MULTIPLE_SELECT) { - update = { [fileName]: newValue ? getColumnOptionNamesByIds(field, newValue) : [] }; - } - metadataAPI.modifyRecord(repoID, recordId, update, fileObjId).then(res => { - const newMetadata = { ...metadata, record: { ...record, ...update } }; - setMetadata(newMetadata); - if (window?.sfMetadataContext?.eventBus) { - window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, recordId, update); - } - }).catch(error => { - const errorMsg = Utils.getErrorMsg(error); - toaster.danger(errorMsg); - }); - }, [repoID, metadata]); - - const modifyColumnData = useCallback((fieldKey, newData) => { - const { fields, record } = metadata; - let newFields = fields.slice(0); - let update; - metadataAPI.modifyColumnData(repoID, fieldKey, newData).then(res => { - const newField = new Column(res.data.column); - const fieldIndex = fields.findIndex(f => f.key === fieldKey); - newFields[fieldIndex] = newField; - return newField; - }).then((newField) => { - const fileName = getColumnOriginName(newField); - const options = getColumnOptions(newField); - const newOption = options[options.length - 1]; - update = { [fileName]: newOption.id }; - if (!PREDEFINED_COLUMN_KEYS.includes(fieldKey) && newField.type === CellType.SINGLE_SELECT) { - update = { [fileName]: getOptionName(options, newOption.id) }; - } else if (newField.type === CellType.MULTIPLE_SELECT) { - const oldValue = getCellValueByColumn(record, newField) || []; - update = { [fileName]: [...oldValue, newOption.name] }; - } - return metadataAPI.modifyRecord(repoID, record._id, update, record._obj_id); - }).then(res => { - const newMetadata = { ...metadata, record: { ...record, ...update }, fields: newFields }; - setMetadata(newMetadata); - }).catch(error => { - const errorMsg = Utils.getErrorMsg(error); - toaster.danger(errorMsg); - }); - }, [repoID, metadata]); - - const localRecordChanged = useCallback((recordId, updates) => { - if (getRecordIdFromRecord(metadata?.record) !== recordId) return; - const newMetadata = { ...metadata, record: { ...metadata.record, ...updates } }; - setMetadata(newMetadata); - }, [metadata]); - - const updateFileTags = useCallback((updateRecords) => { - const { record } = metadata; - const { record_id, tags } = updateRecords[0]; - - tagsAPI.updateFileTags(repoID, [{ record_id, tags }]).then(res => { - const newValue = tags ? tags.map(id => ({ row_id: id, display_value: id })) : []; - const update = { [PRIVATE_COLUMN_KEY.TAGS]: newValue }; - const newMetadata = { ...metadata, record: { ...record, ...update } }; - setMetadata(newMetadata); - if (window?.sfMetadataContext?.eventBus) { - window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, record_id, update); - } - }).catch(error => { - const errorMsg = Utils.getErrorMsg(error); - toaster.danger(errorMsg); - }); - }, [repoID, metadata]); - - useEffect(() => { - setLoading(true); - if (SYSTEM_FOLDERS.find(folderPath => filePath.startsWith(folderPath))) { - setLoading(false); - return; - } - - const dirName = Utils.getDirName(filePath); - const fileName = Utils.getFileName(filePath); - let parentDir = direntType === 'file' ? dirName : dirName.slice(0, dirName.length - fileName.length - 1); - if (!parentDir.startsWith('/')) { - parentDir = '/' + parentDir; - } - metadataAPI.getMetadataRecordInfo(repoID, parentDir, fileName).then(res => { - const { results, metadata } = res.data; - const record = Array.isArray(results) && results.length > 0 ? results[0] : {}; - let fields = normalizeFields(metadata).map(field => new Column(field)); - const isDir = checkIsDir(record); - if (isDir) { - fields = fields.filter(field => field.type !== CellType.TAGS); - } - updateRecord && updateRecord(record); - setMetadata({ record, fields }); - setLoading(false); - }).catch(error => { - const errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - setLoading(false); - }); - }, [repoID, filePath, direntType, updateRecord]); - - useEffect(() => { - const eventBus = window?.sfMetadataContext?.eventBus; - if (!eventBus) return; - const unsubscribeLocalRecordChanged = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_DETAIL_CHANGED, localRecordChanged); - return () => { - unsubscribeLocalRecordChanged(); - }; - }, [localRecordChanged]); + const displayColumns = useMemo(() => columns.filter(c => c.shown), [columns]); if (isLoading) return null; - const { fields, record } = metadata; + if (!record) return null; if (!record._id) return null; + const fileName = getFileNameFromRecord(record); const isImage = record && (Utils.imageCheck(fileName) || Utils.videoCheck(fileName)); + const isDir = record && checkIsDir(record); + return ( <> - {fields.map(field => { - let canEdit = permission === 'rw' && field.editable; + {displayColumns.map(field => { + if (field.key === PRIVATE_COLUMN_KEY.LOCATION) { + if (!isImage) return null; + return (<Location key={field.key} position={getCellValueByColumn(record, field)} />); + } + + if (field.key === PRIVATE_COLUMN_KEY.TAGS && isDir) return null; + + let canEdit = canModifyRecord && field.editable; if (!isImage && canEdit && field.key === PRIVATE_COLUMN_KEY.CAPTURE_TIME) { canEdit = false; } + const value = getCellValueByColumn(record, field); return ( <DetailItem key={field.key} field={field} readonly={!canEdit}> @@ -161,7 +47,7 @@ const MetadataDetails = ({ repoID, filePath, repoInfo, direntType, updateRecord <DetailEditor field={field} value={value} - fields={fields} + fields={columns} record={record} modifyColumnData={modifyColumnData} onChange={onChange} @@ -173,18 +59,8 @@ const MetadataDetails = ({ repoID, filePath, repoInfo, direntType, updateRecord </DetailItem> ); })} - {isImage && (<Location position={getCellValueByColumn(record, { key: PRIVATE_COLUMN_KEY.LOCATION })} />)} </> ); }; -MetadataDetails.propTypes = { - repoID: PropTypes.string, - filePath: PropTypes.string, - repoInfo: PropTypes.object, - direntType: PropTypes.string, - direntDetail: PropTypes.object, - updateRecord: PropTypes.func, -}; - export default MetadataDetails; diff --git a/frontend/src/metadata/components/metadata-details/location/index.js b/frontend/src/metadata/components/metadata-details/location/index.js index 9bc380b5d9a..16ab8582862 100644 --- a/frontend/src/metadata/components/metadata-details/location/index.js +++ b/frontend/src/metadata/components/metadata-details/location/index.js @@ -175,7 +175,7 @@ class Location extends React.Component { )} </DetailItem> {isLoading ? (<Loading />) : this.mapType && ( - <div className={classnames('dirent-detail-item-value-map', { 'd-none': !isValid })}> + <div className={classnames('dirent-detail-item dirent-detail-item-value-map', { 'd-none': !isValid })}> <div className="w-100 h-100" ref={ref => this.ref = ref} id="sf-geolocation-map-container"></div> </div> )} diff --git a/frontend/src/metadata/components/metadata-details/settings/index.css b/frontend/src/metadata/components/metadata-details/settings/index.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/src/metadata/components/metadata-details/settings/index.js b/frontend/src/metadata/components/metadata-details/settings/index.js new file mode 100644 index 00000000000..a3f99b8464f --- /dev/null +++ b/frontend/src/metadata/components/metadata-details/settings/index.js @@ -0,0 +1,46 @@ +import React, { useMemo, useCallback, useState } from 'react'; +import Icon from '../../../../components/icon'; +import HideColumnPopover from '../../popover/hidden-column-popover'; +import { useMetadataDetails } from '../../../hooks'; +import { useMetadataStatus } from '../../../../hooks'; + +import './index.css'; + +const Settings = () => { + const [isShowSetter, setShowSetter] = useState(false); + + const { enableMetadata } = useMetadataStatus(); + const { modifyColumnOrder, modifyHiddenColumns, columns, canModifyDetails } = useMetadataDetails(); + const hiddenColumns = useMemo(() => columns.filter(c => !c.shown).map(c => c.key), [columns]); + + const onSetterToggle = useCallback(() => { + setShowSetter(!isShowSetter); + }, [isShowSetter]); + const target = useMemo(() => 'detail-control-settings-btn', []); + + if (!enableMetadata) return null; + if (!canModifyDetails) return null; + + return ( + <> + <div className="detail-control mr-2" id={target} onClick={onSetterToggle}> + <Icon symbol="set-up" className="detail-control-close" /> + </div> + {isShowSetter && ( + <HideColumnPopover + readOnly={false} + hiddenColumns={hiddenColumns} + target={target} + placement="bottom-end" + columns={columns} + hidePopover={onSetterToggle} + onChange={modifyHiddenColumns} + modifyColumnOrder={modifyColumnOrder} + /> + )} + </> + ); + +}; + +export default Settings; diff --git a/frontend/src/metadata/components/metadata-details/utils.js b/frontend/src/metadata/components/metadata-details/utils.js index 050c5c30c8b..0721f694f09 100644 --- a/frontend/src/metadata/components/metadata-details/utils.js +++ b/frontend/src/metadata/components/metadata-details/utils.js @@ -1,10 +1,10 @@ import { getNormalizedColumnType } from '../../utils/column'; import { getCellValueByColumn } from '../../utils/cell'; -import { NOT_DISPLAY_COLUMN_KEYS } from './constants'; +import { NOT_DISPLAY_COLUMN_KEYS, CellType, PRIVATE_COLUMN_KEY } from './constants'; export const normalizeFields = (fields) => { if (!Array.isArray(fields) || fields.length === 0) return []; - const validFields = fields.map((field) => { + let validFields = fields.map((field) => { const { type, key, ...params } = field; return { ...params, @@ -13,11 +13,8 @@ export const normalizeFields = (fields) => { width: 200, }; }).filter(field => !NOT_DISPLAY_COLUMN_KEYS.includes(field.key)); - let displayFields = []; - validFields.forEach(field => { - displayFields.push(field); - }); - return displayFields; + validFields.push({ key: PRIVATE_COLUMN_KEY.LOCATION, type: CellType.GEOLOCATION, width: 200 }); + return validFields; }; export { diff --git a/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/hide-column.js b/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/hide-column.js index e0c9fe6e2c7..c3b554c3201 100644 --- a/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/hide-column.js +++ b/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/hide-column.js @@ -1,110 +1,105 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useRef } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { DragSource, DropTarget } from 'react-dnd'; import { Icon, Switch } from '@seafile/sf-metadata-ui-component'; import { COLUMNS_ICON_CONFIG } from '../../../../constants'; -const dragSource = { - beginDrag: props => { - return { key: props.column.key, column: props.column }; - }, - endDrag(props, monitor) { - const source = monitor.getItem(); - const didDrop = monitor.didDrop(); - let target = {}; - if (!didDrop) { - return { source, target }; - } - }, - isDragging(props) { - const { columnIndex, currentIndex } = props; - return currentIndex > columnIndex; - } -}; -const dropTarget = { - drop(props, monitor) { - const source = monitor.getItem(); - const { column: targetColumn } = props; - if (targetColumn.key !== source.key && source.column.frozen === targetColumn.frozen) { - const target = { key: targetColumn.key }; - props.onMove(source.key, target.key); - } - } -}; - -const dragCollect = (connect, monitor) => ({ - connectDragSource: connect.dragSource(), - connectDragPreview: connect.dragPreview(), - isDragging: monitor.isDragging(), -}); - -const dropCollect = (connect, monitor) => ({ - connectDropTarget: connect.dropTarget(), - isOver: monitor.isOver(), - canDrop: monitor.canDrop(), - dragged: monitor.getItem(), -}); - const HideColumnItem = ({ - isOver, - isDragging, - canDrop, - connectDragSource, - connectDragPreview, - connectDropTarget, readOnly, + isHidden, column, columnIndex, - isHidden, + draggingColumnKey, + draggingColumnIndex, + dragOverColumnKey, + updateDraggingKey, + updateDragOverKey, onChange, - onMouseEnter, - onMouseLeave, + onMove, }) => { + const ref = useRef(null); + + const onDragStart = useCallback((event) => { + const dragData = JSON.stringify({ type: 'sf-metadata-filed-display-setting', column_key: column.key }); + event.dataTransfer.setDragImage(ref.current, 10, 10); + event.dataTransfer.effectAllowed = 'move'; + event.dataTransfer.setData('application/drag-sf-metadata-filed-display-setting', dragData); + updateDraggingKey(column.key); + }, [column, updateDraggingKey]); + + const onDragEnter = useCallback(() => { + if (!draggingColumnKey) return; + updateDragOverKey(column.key); + }, [column, updateDragOverKey, draggingColumnKey]); + + const onDragLeave = useCallback(() => { + if (!draggingColumnKey) return; + updateDragOverKey(null); + }, [updateDragOverKey, draggingColumnKey]); + + const onDragOver = useCallback((event) => { + if (!draggingColumnKey) return; + event.preventDefault(); + event.dataTransfer.dropEffect = 'move'; + updateDragOverKey(column.key); + }, [column, updateDragOverKey, draggingColumnKey]); + + const onDrop = useCallback((event) => { + event.stopPropagation(); + let dragData = event.dataTransfer.getData('application/drag-sf-metadata-filed-display-setting'); + if (!dragData) return false; + dragData = JSON.parse(dragData); + if (dragData.type !== 'sf-metadata-filed-display-setting' || !dragData.column_key) return false; + if (dragData.column_key !== column.key) { + onMove && onMove(dragData.column_key, column.key); + } + }, [column, onMove]); + + const onDragEnd = useCallback(() => { + updateDraggingKey(null); + updateDragOverKey(null); + }, [updateDraggingKey, updateDragOverKey]); const update = useCallback(() => { if (readOnly) return; onChange(column.key); }, [readOnly, column, onChange]); + const isOver = dragOverColumnKey === column.key; + return ( - <> - {connectDropTarget( - connectDragPreview( - <div - className={classNames('hide-column-item', { - 'disabled': readOnly, - 'hide-column-can-drop-top': isOver && canDrop && isDragging, - 'hide-column-can-drop': isOver && canDrop && !isDragging - })} - onMouseEnter={() => onMouseEnter(columnIndex)} - onMouseLeave={onMouseLeave} - > - {!readOnly && ( - <> - {connectDragSource( - <div className="drag-hide-column-handle"> - <Icon iconName="drag" /> - </div> - )} - </> - )} - <Switch - disabled={readOnly} - checked={isHidden} - placeholder={( - <> - <Icon iconName={COLUMNS_ICON_CONFIG[column.type]} /> - <span className="text-truncate">{column.name}</span> - </> - )} - onChange={update} - switchClassName="hide-column-item-switch" - /> - </div> - ) + <div + ref={ref} + className={classNames('hide-column-item', { + 'disabled': readOnly, + 'hide-column-can-drop-top': isOver && draggingColumnIndex >= columnIndex, + 'hide-column-can-drop': isOver && draggingColumnIndex < columnIndex, + 'dragging': draggingColumnKey === column.key + })} + onDrop={onDrop} + onDragEnter={onDragEnter} + onDragOver={onDragOver} + onDragLeave={onDragLeave} + onDragEnd={onDragEnd} + > + {!readOnly && ( + <div className="drag-hide-column-handle" draggable="true" onDragStart={onDragStart}> + <Icon iconName="drag" /> + </div> )} - </> + <Switch + disabled={readOnly} + checked={isHidden} + placeholder={( + <> + <Icon iconName={COLUMNS_ICON_CONFIG[column.type]} /> + <span className="text-truncate">{column.name}</span> + </> + )} + onChange={update} + switchClassName="hide-column-item-switch" + /> + </div> ); }; @@ -112,14 +107,14 @@ HideColumnItem.propTypes = { readOnly: PropTypes.bool, isHidden: PropTypes.bool, columnIndex: PropTypes.number, - currentIndex: PropTypes.number, column: PropTypes.object.isRequired, + draggingColumnKey: PropTypes.string, + draggingColumnIndex: PropTypes.number, + dragOverColumnKey: PropTypes.string, + updateDraggingKey: PropTypes.func, + updateDragOverKey: PropTypes.func, onChange: PropTypes.func.isRequired, onMove: PropTypes.func, - onMouseEnter: PropTypes.func, - onMouseLeave: PropTypes.func, }; -export default DropTarget('sfMetadataHiddenColumns', dropTarget, dropCollect)( - DragSource('sfMetadataHiddenColumns', dragSource, dragCollect)(HideColumnItem) -); +export default HideColumnItem; diff --git a/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/index.js b/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/index.js index d1210be77dd..c4609101a00 100644 --- a/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/index.js +++ b/frontend/src/metadata/components/popover/hidden-column-popover/hidden-columns/index.js @@ -1,27 +1,29 @@ import React, { useCallback, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import { DropTarget } from 'react-dnd'; import HideColumn from './hide-column'; -import html5DragDropContext from '../../../../../pages/wiki2/wiki-nav/html5DragDropContext'; import { gettext } from '../../../../../utils/constants'; const HiddenColumns = ({ readOnly, columns, hiddenColumns, onChange, modifyColumnOrder }) => { - const [currentIndex, setCurrentIndex] = useState(-1); + const [draggingColumnKey, setDraggingCellKey] = useState(null); + const [dragOverColumnKey, setDragOverCellKey] = useState(null); const isEmpty = useMemo(() => { if (!Array.isArray(columns) || columns.length === 0) return true; return false; }, [columns]); - const onMouseEnter = useCallback((columnIndex) => { - if (currentIndex === columnIndex) return; - setCurrentIndex(columnIndex); - }, [currentIndex]); + const updateDraggingKey = useCallback((cellKey) => { + if (cellKey === draggingColumnKey) return; + setDraggingCellKey(cellKey); + }, [draggingColumnKey]); - const onMouseLeave = useCallback(() => { - setCurrentIndex(-1); - }, []); + const updateDragOverKey = useCallback((cellKey) => { + if (cellKey === dragOverColumnKey) return; + setDragOverCellKey(cellKey); + }, [dragOverColumnKey]); + + const draggingColumnIndex = draggingColumnKey ? columns.findIndex(c => c.key === draggingColumnKey) : -1; return ( <div className={classnames('hide-columns-list', { 'empty-hide-columns-container': isEmpty })}> @@ -32,13 +34,15 @@ const HiddenColumns = ({ readOnly, columns, hiddenColumns, onChange, modifyColum key={column.key} readOnly={readOnly} columnIndex={columnIndex} - currentIndex={currentIndex} isHidden={!hiddenColumns.includes(column.key)} column={column} + draggingColumnKey={draggingColumnKey} + draggingColumnIndex={draggingColumnIndex} + dragOverColumnKey={dragOverColumnKey} onChange={onChange} onMove={modifyColumnOrder} - onMouseEnter={onMouseEnter} - onMouseLeave={onMouseLeave} + updateDraggingKey={updateDraggingKey} + updateDragOverKey={updateDragOverKey} /> ); })} @@ -54,8 +58,4 @@ HiddenColumns.propTypes = { modifyColumnOrder: PropTypes.func, }; -const DndHiddenColumns = DropTarget('sfMetadataHiddenColumns', {}, connect => ({ - connectDropTarget: connect.dropTarget() -}))(HiddenColumns); - -export default html5DragDropContext(DndHiddenColumns); +export default HiddenColumns; diff --git a/frontend/src/metadata/components/popover/hidden-column-popover/index.css b/frontend/src/metadata/components/popover/hidden-column-popover/index.css index 00438adf5ab..039f8259d2e 100644 --- a/frontend/src/metadata/components/popover/hidden-column-popover/index.css +++ b/frontend/src/metadata/components/popover/hidden-column-popover/index.css @@ -145,6 +145,10 @@ display: none; } +.sf-metadata-hide-columns-popover .hide-column-item.dragging { + background-color: #f5f5f5; +} + .sf-metadata-hide-columns-popover .hide-column-item.hide-column-can-drop::after, .sf-metadata-hide-columns-popover .hide-column-item.hide-column-can-drop-top::before { content: ''; diff --git a/frontend/src/metadata/components/view-toolbar/kanban-view-toolbar/index.js b/frontend/src/metadata/components/view-toolbar/kanban-view-toolbar/index.js index 3176fbccd79..9835eb6575a 100644 --- a/frontend/src/metadata/components/view-toolbar/kanban-view-toolbar/index.js +++ b/frontend/src/metadata/components/view-toolbar/kanban-view-toolbar/index.js @@ -67,13 +67,14 @@ const KanbanViewToolBar = ({ className="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-setting" size={24} role="button" - aria-label="Setting" + aria-label={gettext('Settings')} + title={gettext('Settings')} tabIndex={0} onClick={onToggleKanbanSetting} /> {!isCustomPermission && ( - <div className="cur-view-path-btn ml-2" onClick={toggleDetails}> - <span className="sf3-font sf3-font-info" aria-label={gettext('Properties')} title={gettext('Properties')}></span> + <div className="cur-view-path-btn ml-2" onClick={toggleDetails} aria-label={gettext('Properties')} title={gettext('Properties')}> + <span className="sf3-font sf3-font-info"></span> </div> )} </div> diff --git a/frontend/src/metadata/hooks/index.js b/frontend/src/metadata/hooks/index.js index a00eced1d9a..ca990d0368c 100644 --- a/frontend/src/metadata/hooks/index.js +++ b/frontend/src/metadata/hooks/index.js @@ -1,2 +1,3 @@ export { MetadataProvider, useMetadata } from './metadata'; export { CollaboratorsProvider, useCollaborators } from './collaborators'; +export { MetadataDetailsProvider, useMetadataDetails } from './metadata-details'; diff --git a/frontend/src/metadata/hooks/metadata-details.js b/frontend/src/metadata/hooks/metadata-details.js new file mode 100644 index 00000000000..45ecccb5eee --- /dev/null +++ b/frontend/src/metadata/hooks/metadata-details.js @@ -0,0 +1,211 @@ +import React, { useContext, useEffect, useCallback, useState, useMemo, useRef } from 'react'; +import metadataAPI from '../api'; +import { Utils } from '../../utils/utils'; +import toaster from '../../components/toast'; +import { useMetadataStatus } from '../../hooks/metadata-status'; +import { SYSTEM_FOLDERS } from '../../constants'; +import Column from '../model/column'; +import { normalizeFields } from '../components/metadata-details/utils'; +import { CellType, EVENT_BUS_TYPE, PREDEFINED_COLUMN_KEYS, PRIVATE_COLUMN_KEY } from '../constants'; +import { getCellValueByColumn, getOptionName, getColumnOptionNamesByIds, getColumnOptionNameById, getRecordIdFromRecord, + getFileObjIdFromRecord +} from '../utils/cell'; +import tagsAPI from '../../tag/api'; +import { getColumnByKey, getColumnOptions, getColumnOriginName } from '../utils/column'; + +const MetadataDetailsContext = React.createContext(null); + +export const MetadataDetailsProvider = ({ repoID, repoInfo, path, dirent, direntDetail, direntType, children }) => { + const { enableMetadata, detailsSettings, modifyDetailsSettings } = useMetadataStatus(); + + const [isLoading, setLoading] = useState(true); + const [record, setRecord] = useState(null); + const [originColumns, setOriginColumns] = useState([]); + + const canModifyRecord = useMemo(() => repoInfo.permission !== 'admin' && repoInfo.permission !== 'rw' ? false : true, [repoInfo]); + const canModifyDetails = useMemo(() => repoInfo.is_admin, [repoInfo]); + + const allColumnsRef = useRef([]); + + const columns = useMemo(() => { + const orderAndHiddenColumns = detailsSettings?.columns || []; + if (!Array.isArray(orderAndHiddenColumns) || orderAndHiddenColumns.length === 0) { + return originColumns.map(c => ({ ...c, shown: true })); + } + const oldColumnsMap = orderAndHiddenColumns.reduce((pre, cur) => { + pre[cur.key] = true; + return pre; + }, {}); + const columnsMap = originColumns.reduce((pre, cur) => { + pre[cur.key] = cur; + return pre; + }, {}); + const exitColumnsOrder = orderAndHiddenColumns.map(c => { + const column = columnsMap[c.key]; + if (column) return { ...c, ...column }; + return null; + }).filter(c => c); + const newColumns = originColumns.filter(c => !oldColumnsMap[c.key]).map(c => ({ ...c, shown: false })); + return [...exitColumnsOrder, ...newColumns]; + }, [originColumns, detailsSettings]); + + const localRecordChanged = useCallback((recordId, updates) => { + if (getRecordIdFromRecord(record) !== recordId) return; + const newRecord = { ...record, ...updates }; + setRecord(newRecord); + }, [record]); + + const onChange = useCallback((fieldKey, newValue) => { + const field = getColumnByKey(originColumns, fieldKey); + const fileName = getColumnOriginName(field); + const recordId = getRecordIdFromRecord(record); + const fileObjId = getFileObjIdFromRecord(record); + let update = { [fileName]: newValue }; + if (field.type === CellType.SINGLE_SELECT) { + update = { [fileName]: getColumnOptionNameById(field, newValue) }; + } else if (field.type === CellType.MULTIPLE_SELECT) { + update = { [fileName]: newValue ? getColumnOptionNamesByIds(field, newValue) : [] }; + } + metadataAPI.modifyRecord(repoID, recordId, update, fileObjId).then(res => { + setRecord({ ...record, ...update }); + if (window?.sfMetadataContext?.eventBus) { + window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, recordId, update); + } + }).catch(error => { + const errorMsg = Utils.getErrorMsg(error); + toaster.danger(errorMsg); + }); + }, [repoID, record, originColumns]); + + const modifyColumnData = useCallback((fieldKey, newData) => { + let newColumns = originColumns.slice(0); + let update; + metadataAPI.modifyColumnData(repoID, fieldKey, newData).then(res => { + const newColumn = new Column(res.data.column); + const fieldIndex = originColumns.findIndex(f => f.key === fieldKey); + newColumns[fieldIndex] = newColumn; + return newColumn; + }).then((newField) => { + const fileName = getColumnOriginName(newField); + const options = getColumnOptions(newField); + const newOption = options[options.length - 1]; + update = { [fileName]: newOption.id }; + if (!PREDEFINED_COLUMN_KEYS.includes(fieldKey) && newField.type === CellType.SINGLE_SELECT) { + update = { [fileName]: getOptionName(options, newOption.id) }; + } else if (newField.type === CellType.MULTIPLE_SELECT) { + const oldValue = getCellValueByColumn(record, newField) || []; + update = { [fileName]: [...oldValue, newOption.name] }; + } + return metadataAPI.modifyRecord(repoID, record._id, update, record._obj_id); + }).then(res => { + setOriginColumns(newColumns); + setRecord({ ...record, ...update }); + }).catch(error => { + const errorMsg = Utils.getErrorMsg(error); + toaster.danger(errorMsg); + }); + }, [repoID, record, originColumns]); + + const updateFileTags = useCallback((updateRecords) => { + const { record_id, tags } = updateRecords[0]; + + tagsAPI.updateFileTags(repoID, [{ record_id, tags }]).then(res => { + const newValue = tags ? tags.map(id => ({ row_id: id, display_value: id })) : []; + const update = { [PRIVATE_COLUMN_KEY.TAGS]: newValue }; + setRecord({ ...record, ...update }); + if (window?.sfMetadataContext?.eventBus) { + window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, record_id, update); + } + }).catch(error => { + const errorMsg = Utils.getErrorMsg(error); + toaster.danger(errorMsg); + }); + }, [repoID, record]); + + const saveColumns = useCallback((columns) => { + modifyDetailsSettings({ columns: columns.map(c => ({ key: c.key, shown: c.shown })) }); + }, [modifyDetailsSettings]); + + const modifyHiddenColumns = useCallback((hiddenColumns) => { + let newColumns = columns.slice(0); + newColumns = newColumns.map(c => ({ ...c, shown: !hiddenColumns.includes(c.key) })); + saveColumns(newColumns); + }, [columns, saveColumns]); + + const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => { + const targetColumnIndex = columns.findIndex(c => c.key === targetColumnKey); + const sourceColumn = columns.find(c => c.key === sourceColumnKey); + let newColumns = columns.slice(0); + newColumns = newColumns.filter(c => c.key !== sourceColumnKey); + newColumns.splice(targetColumnIndex, 0, sourceColumn); + saveColumns(newColumns); + }, [columns, saveColumns]); + + useEffect(() => { + setLoading(true); + if (!dirent || !direntDetail || !enableMetadata || SYSTEM_FOLDERS.find(folderPath => path.startsWith(folderPath))) { + setRecord(null); + setOriginColumns([]); + setLoading(false); + return; + } + + const dirName = Utils.getDirName(path); + const fileName = Utils.getFileName(path); + let parentDir = direntType === 'file' ? dirName : dirName.slice(0, dirName.length - fileName.length - 1); + + if (!parentDir.startsWith('/')) { + parentDir = '/' + parentDir; + } + metadataAPI.getMetadataRecordInfo(repoID, parentDir, fileName).then(res => { + const { results, metadata } = res.data; + const record = Array.isArray(results) && results.length > 0 ? results[0] : {}; + const columns = normalizeFields(metadata).map(field => new Column(field)); + allColumnsRef.current = columns; + setRecord(record); + setOriginColumns(columns); + setLoading(false); + }).catch(error => { + const errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + setLoading(false); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [enableMetadata, repoID, path, direntType, dirent, direntDetail]); + + useEffect(() => { + const eventBus = window?.sfMetadataContext?.eventBus; + if (!eventBus) return; + const unsubscribeLocalRecordChanged = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_DETAIL_CHANGED, localRecordChanged); + return () => { + unsubscribeLocalRecordChanged(); + }; + }, [localRecordChanged]); + + return ( + <MetadataDetailsContext.Provider + value={{ + isLoading, + canModifyRecord, + canModifyDetails, + record, + columns, + onChange, + modifyColumnData, + updateFileTags, + modifyHiddenColumns, + modifyColumnOrder, + }} + > + {children} + </MetadataDetailsContext.Provider> + ); +}; + +export const useMetadataDetails = () => { + const context = useContext(MetadataDetailsContext); + if (!context) { + throw new Error('\'MetadataDetailsContext\' is null'); + } + return context; +}; diff --git a/frontend/src/metadata/utils/row/core.js b/frontend/src/metadata/utils/row/core.js index 145cfcc471c..f69e806ee6d 100644 --- a/frontend/src/metadata/utils/row/core.js +++ b/frontend/src/metadata/utils/row/core.js @@ -27,6 +27,7 @@ const updateTableRowsWithRowsData = (tables, tableId, recordsData = []) => { }; export const checkIsDir = (record) => { + if (!record) return false; const isDir = record[PRIVATE_COLUMN_KEY.IS_DIR]; if (typeof isDir === 'string') { return isDir.toUpperCase() === 'TRUE'; diff --git a/frontend/src/pages/markdown-editor/header-toolbar/header-toolbar.js b/frontend/src/pages/markdown-editor/header-toolbar/header-toolbar.js index 690120e6e8d..7f23efd2859 100644 --- a/frontend/src/pages/markdown-editor/header-toolbar/header-toolbar.js +++ b/frontend/src/pages/markdown-editor/header-toolbar/header-toolbar.js @@ -17,7 +17,7 @@ import Dirent from '../../../../src/models/dirent'; import '../css/header-toolbar.css'; const { seafileCollabServer } = window.app.config; -const { canDownloadFile, repoID, filePath } = window.app.pageOptions; +const { canDownloadFile, repoID, filePath, isRepoAdmin } = window.app.pageOptions; const propTypes = { editorApi: PropTypes.object.isRequired, @@ -95,7 +95,7 @@ class HeaderToolbar extends React.Component { }; onArticleInfoToggle = () => { - const repoInfo = { permission: this.currentDirent.permission }; + const repoInfo = { permission: this.currentDirent.permission, is_admin: isRepoAdmin, }; const eventBus = EventBus.getInstance(); eventBus.dispatch(EXTERNAL_EVENTS.ON_ARTICLE_INFO_TOGGLE, this.isFileInfoShow ? null : { diff --git a/frontend/src/pages/sdoc/sdoc-editor/index.css b/frontend/src/pages/sdoc/sdoc-editor/index.css index 66584c35223..d152a3dd188 100644 --- a/frontend/src/pages/sdoc/sdoc-editor/index.css +++ b/frontend/src/pages/sdoc/sdoc-editor/index.css @@ -15,6 +15,16 @@ background-color: inherit; } +.sdoc-content-right-panel .detail-header .seafile-multicolor-icon-set-up { + fill: #999; + font-weight: 700; + font-size: 16px; +} + +.sdoc-content-right-panel .detail-header .detail-control:hover .seafile-multicolor-icon-set-up { + fill: #5a5a5a; +} + .sdoc-content-right-panel .detail-header .sdoc-sm-close { color: #999; font-weight: 700; diff --git a/frontend/src/pages/sdoc/sdoc-editor/index.js b/frontend/src/pages/sdoc/sdoc-editor/index.js index ea6beab5d63..5742a7d223e 100644 --- a/frontend/src/pages/sdoc/sdoc-editor/index.js +++ b/frontend/src/pages/sdoc/sdoc-editor/index.js @@ -16,7 +16,7 @@ const SdocEditor = () => { const [currentDirent, setCurrentDirent] = useState(null); const { collaborators } = useCollaborators(); const plugins = useMemo(() => { - const { repoID, docPath, docPerm } = window.seafile; + const { repoID, docPath, docPerm, isRepoAdmin } = window.seafile; return [ { name: 'sdoc-info', @@ -29,7 +29,7 @@ const SdocEditor = () => { repoID={repoID} path={docPath} dirent={currentDirent} - repoInfo={{ permission: docPerm }} + repoInfo={{ permission: docPerm, is_admin: isRepoAdmin }} width={width - 1} component={{ headerComponent: { diff --git a/frontend/src/view-file-sdoc.js b/frontend/src/view-file-sdoc.js index e30a45fa9a5..c1087f17b22 100644 --- a/frontend/src/view-file-sdoc.js +++ b/frontend/src/view-file-sdoc.js @@ -15,11 +15,12 @@ const { repoID, repoName, repoEncrypted, parentDir, filePerm, docPath, docName, docUuid, seadocAccessToken, seadocServerUrl, assetsUrl, isSdocRevision, isPublished, originFilename, revisionCreatedAt, originFileVersion, - originFilePath, originDocUuid, revisionId, isFreezed, mobileLogin + originFilePath, originDocUuid, revisionId, isFreezed, mobileLogin, isRepoAdmin } = window.app.pageOptions; window.seafile = { repoID, + isRepoAdmin, docPath, docName, docUuid, @@ -52,7 +53,7 @@ window.seafile = { mobileLogin, }; -const repoInfo = { encrypted: repoEncrypted, permission: filePerm }; +const repoInfo = { encrypted: repoEncrypted, permission: filePerm, is_admin: isRepoAdmin }; ReactDom.render( <I18nextProvider i18n={ i18n } > diff --git a/media/css/sf_font3/iconfont.css b/media/css/sf_font3/iconfont.css index d0684766eaf..def6c7fe635 100644 --- a/media/css/sf_font3/iconfont.css +++ b/media/css/sf_font3/iconfont.css @@ -1,11 +1,11 @@ @font-face { font-family: "sf3-font"; /* Project id 1230969 */ - src: url('iconfont.eot?t=1732614348756'); /* IE9 */ - src: url('iconfont.eot?t=1732614348756#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('iconfont.woff2?t=1732614348756') format('woff2'), - url('iconfont.woff?t=1732614348756') format('woff'), - url('iconfont.ttf?t=1732614348756') format('truetype'), - url('iconfont.svg?t=1732614348756#sf3-font') format('svg'); + src: url('./iconfont.eot?t=1733301127109'); /* IE9 */ + src: url('./iconfont.eot?t=1733301127109#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('./iconfont.woff2?t=1733301127109') format('woff2'), + url('./iconfont.woff?t=1733301127109') format('woff'), + url('./iconfont.ttf?t=1733301127109') format('truetype'), + url('./iconfont.svg?t=1733301127109#sf3-font') format('svg'); } .sf3-font { diff --git a/media/css/sf_font3/iconfont.eot b/media/css/sf_font3/iconfont.eot index d4fb6fdc870fdc352c6439e3a4f9026c97333ed1..4bb9fed7ba7e370a5b1157415b64ee9ccc8538c0 100644 GIT binary patch delta 948 zcmY+AZ)h839LJyMxqrFK{mJE$yWHh2O>${2xg>4cyWDNn#p1MVL0dXyMhX2xwHB#v z){1j4?2s{-D7Xa_(cy%l!-*6lvKM_R;tPeo6GWsMRyq+Gs1sIAybRy?!1wq3`0#u2 z{eCxZ!mXQ-*jfi5c7gEmYujDt!sOKlnn$qr0pKnJFn4w3sl_Ml$TtiCU?-5b5&-H3 z_E)fP1<I{FyMAg<?RNoyzXsY{J+ZX-(i?M$b{U%UM*u)ipFHuxdT95(9|3r7698ff zKmf2a{WGA2ll}evZ9F_6|9hwJl7Kqh?Q8SGy?=r*e)pjJ;+N!L8T|eI&ZqEii2D2O zO>DYz2kX)s3yD27tFCGj+Skcc@?>%=c}s8TujsqRxzzosTSFIzeoMca-p*Xler2}I zx6B`M3%S>GJHww1-^nlMcde>*%DP?f3Twqe@fW*pU$l2hZ<anTT`&Dy*2`<<KPq#T z%OlOvM*|Omqy81_Cu|X<K^b^p0)S47|8VqR5b8V*u~nc4bQXZ&nw!s3qyS|l1;>5w z5X_8wHP^x@OUXb*uA@;%krb)4@2P7WR91l4$N*rz;-e>`Nrq&WAJRfXBFw=hBTs+C zO`Yp~*Zaa`bRHq=9UaFI&gDBin-E0!m_O0$qO{3|C`_c=4zGlHI%IcvClO&br?|I0 zn~&m%T5csNf(mgJOONu<ZfO5NP9g|58slCwNRbT-q|*D=sPPQxR2g_lp$wK_QT}{3 z5rVi3Jx%19Nbh^~=<lGz-ghIyy^B*p87zo{XTS&T-ptyD=Ldm3UslL?EEOb;$0#1f z6p|W&K_OJ$@;yIjVgy>j^y>%#x9PggmBDa}zJJX3U#5m4&o4_1t(6kIhHDH;Np#Vb zS&VI+6>|hVRv%-CjC8ieLRtxq7;y-rWkL}PwG9T*^y8-^X^O45qo0#XHda)R9&aQL z)Jf|>o59KrTk<B=*?GI59y&-62ro7&7*n3I(BywM0xt^#AIE&SB(S)4Tun)`T2iC@ zfu>Ux<EUn(bT%urEJ73w(=<epuv!7oQ|h#>qPSRf9yu(Co+ZavgPF+*ylfbkBu$Ej xrL<|LBaSAOrd_gHO-G3FnO0^@waSVzEW1%DEDGfrhv3rHYRGxG^T{l3{tE&I(6Imj delta 933 zcmY+CZ)h839LImpJ$ddfm)u=$>HSM`S&~ccnp|=XX_vHJjV-Cpm8#WJr_!3%O;)sS z8jB9!Bril%9BfqfVonh(MM1_~QTAdCUyu1l*j@~gO0{&u$^Q5UM@hU4-}pRyf6tE( zU-*6b@m#!t&fP%d+%f=rl2m+i6Ibt?9Q|VapKnIK2H-yfc;U?AOACjxJJ(JDz=o&t zq6e5Q{I}O%^pswFb@|w~*4YL?zj@kTI(l&7t-W(sR`STKj{s1IUpxB7GP`x=Cx9cX z0OTMb0Nm=dVAe->b~=Cg0$uXI^Y#Pc(K}Zs=IY|epAhgpFl@fEf3n+j-_FkZS+s*z z&f=-{`*_ped{Mipr}ZO|k;vs}BHD;vir$S)##*s$<GuKJ{O<0LcHd6CllUQdKJ}gX zjCsPmmVQ3{Zu)xWtIQwPytQHH?1p{2x7fRsO=W+{4dy<~U3WfkR-N<Ck9j4(l>fc( zY~i%~bl($R0548w75|JEAOU$O!!W@5tgzNM<nb@@27Ux$9-Rir>>039w1`xtdrReq zP_k6sGhk!JR+AZ3sZzFOGc-f5?5#$cwq<%=>>`igidvzjC3P1)Z&V4x5>-ZzM=bgi zzSe4QwZAtxoyVAso>2XS<;*pa*8~xbRx0g#6gGo2!6D{&ks!pgf}gS1_>#u^Kd<q} zC#;~vlKIqQn5K}(=d1`HMoLY+b#E|Ce1aU%4@Zc^=}fr2p_D{FQz&rg{V=2RBuJSp zAs_}=<O`#OA_#uIeM_lruCovS8sb02H}N3|f($Ri$1C@rY&7GjRIVs0E%(H|4ahx= zK*>ES&A2E<GnVZw!bRO$sUix7>Vt#zMz;*5TzA}c8%$hyz23uddR7xPD#B5Q<hKUY z0L33@N=YB*Rtp?SO3ed7#3@=%<s^gRRH6vh0LL)gO!Js%Fnq2*f0}lx%Gl(X(qE>{ zYKFtTqnS`~Sl&M~p$rv6nK2u4!;{q1fAhT%t!{vE7riO+Bs!zV!;0?cyM)Sf{Y6Q} zWjh`VnBuHWB*`#MLz0L+8%&9@xaY#MRP3LwiBh?0tKmSLn=(Z~F^q3Rx*0JN2}8>3 oq25RP7{@U}#NC%oTaK2_=1k48(%F43;SI+L&UruT!c#u;U)QkBssI20 diff --git a/media/css/sf_font3/iconfont.svg b/media/css/sf_font3/iconfont.svg index afa771ec951..d40bdac5381 100644 --- a/media/css/sf_font3/iconfont.svg +++ b/media/css/sf_font3/iconfont.svg @@ -150,7 +150,7 @@ <glyph glyph-name="copy1" unicode="" d="M704 640c35.2 0 64-28.8 64-64v-352h96c16 0 28.8 12.8 32 28.8V736c0 19.2-12.8 32-32 32H384c-19.2 0-32-12.8-32-32v-96h352z m-44.8-96H140.8c-6.4 0-12.8-6.4-12.8-12.8v-518.4c0-6.4 6.4-12.8 12.8-12.8h518.4c9.6 0 12.8 6.4 12.8 12.8V531.2c0 6.4-6.4 12.8-12.8 12.8zM256 800c0 35.2 28.8 64 64 64h608c35.2 0 64-28.8 64-64v-608c0-35.2-28.8-64-64-64h-160v-160c0-35.2-25.6-60.8-60.8-64H96c-35.2 0-64 28.8-64 64V576c0 35.2 28.8 64 64 64h160V800z" horiz-adv-x="1024" /> - <glyph glyph-name="trash" unicode="" d="M595.2 73.6v38.4c0 16-12.8 28.8-28.8 28.8s-28.8-6.4-35.2-12.8l-96-96c57.6-67.2 89.6-105.6 96-108.8 9.6-9.6 19.2-9.6 32-9.6s32 9.6 32 28.8v41.6H928c35.2 0 64 28.8 64 64 0 9.6-3.2 22.4-6.4 32l-156.8 278.4-12.8-67.2-67.2 22.4 128-236.8h-281.6zM288 320l35.2-19.2c12.8-6.4 32-3.2 41.6 6.4s9.6 25.6 6.4 38.4c-3.2 9.6-16 54.4-35.2 128L192 448c-16-3.2-25.6-9.6-32-22.4-6.4-12.8 0-32 12.8-41.6l35.2-19.2-166.4-288c-19.2-28.8-9.6-67.2 22.4-86.4 9.6-6.4 19.2-9.6 28.8-9.6l320-6.4-54.4 44.8 54.4 44.8-268.8 9.6L288 320z m371.2 147.2l-35.2-19.2c-16-9.6-19.2-28.8-12.8-44.8 3.2-6.4 16-16 25.6-19.2l140.8-35.2 48 128c6.4 16 9.6 35.2-9.6 51.2-12.8 12.8-32 6.4-38.4 3.2l-38.4-19.2-166.4 288c-16 28.8-54.4 41.6-86.4 22.4-9.6-6.4-16-12.8-22.4-22.4l-163.2-275.2 67.2 22.4 12.8-67.2 140.8 227.2 137.6-240z" horiz-adv-x="1025" /> + <glyph glyph-name="trash" unicode="" d="M601.8512 54.4V96c0 19.2-12.8 32-32 32s-28.8-6.4-38.4-12.8l-102.4-102.4c60.8-73.6 96-112 102.4-118.4 9.6-9.6 19.2-12.8 35.2-12.8 12.8 0 35.2 9.6 35.2 28.8v44.8h355.2c38.4 0 67.2 28.8 67.2 67.2 0 12.8-3.2 22.4-9.6 32L848.2512 352l-12.8-73.6-70.4 25.6 134.4-252.8h-297.6zM272.2512 320l35.2-19.2c12.8-6.4 35.2-3.2 44.8 9.6 9.6 12.8 9.6 25.6 6.4 41.6-3.2 9.6-16 57.6-38.4 137.6l-153.6-28.8c-16-3.2-28.8-9.6-32-22.4s-3.2-35.2 16-44.8l38.4-22.4L9.8512 64c-19.2-38.4-9.6-76.8 22.4-96 9.6-6.4 22.4-9.6 32-9.6l342.4-6.4-54.4 51.2 57.6 48-284.8 9.6L272.2512 320z m396.8 153.6l-35.2-22.4c-16-9.6-22.4-32-12.8-48 3.2-6.4 16-16 28.8-19.2l147.2-38.4 51.2 137.6c6.4 16 9.6 38.4-9.6 57.6-16 12.8-35.2 6.4-41.6 3.2l-41.6-22.4L576.2512 832c-19.2 35.2-57.6 48-89.6 28.8-9.6-6.4-19.2-16-25.6-25.6l-176-294.4 70.4 25.6 12.8-73.6L518.6512 736l150.4-262.4z" horiz-adv-x="1025" /> <glyph glyph-name="history" unicode="" d="M512 864C350 864 209 786 122 663V744c0 24-21 45-45 45S32 768 32 744v-180c0-24 21-45 45-45H272c15 0 33 9 39 21 9 15 9 33 0 45-6 15-24 24-39 24H194C263 708 380 774 512 774c216 0 390-174 390-390s-174-390-390-390c-183 0-333 123-378 291-6 18-21 30-42 30-12 0-24-6-33-12s-12-21-12-33c0-3 0-9 3-12v-6C107 51 293-96 512-96c264 0 480 216 480 480S776 864 512 864z m0-201c-12 0-24-6-33-12-9-9-12-21-12-33v-270c0-12 6-24 12-33 9-9 21-12 33-12h195c15 0 30 9 39 21s9 30 0 45-24 24-39 21h-150V618c0 12-6 24-12 33-9 6-21 12-33 12z" horiz-adv-x="1024" /> @@ -190,7 +190,7 @@ <glyph glyph-name="search" unicode="" d="M448.099844 896c246.015601 0 447.301092-201.285491 447.301092-447.301092 0-95.850234-28.75507-182.115445-79.875195-255.600624l182.115445-182.115445c31.950078-31.950078 31.950078-83.070203 0-115.02028s-83.070203-31.950078-115.020281 0L703.700468 78.078003c-73.485179-51.120125-159.75039-79.875195-255.600624-79.875195-246.015601 0-447.301092 201.285491-447.301092 447.301092C0.798752 694.714509 202.084243 896 448.099844 896z m0-127.800312C272.374415 768.199688 128.599064 624.424337 128.599064 448.698908s143.775351-319.50078 319.50078-319.50078 319.50078 143.775351 319.50078 319.50078S623.825273 768.199688 448.099844 768.199688z" horiz-adv-x="1024" /> - <glyph glyph-name="set-up" unicode="" d="M512 592c115.2 0 208-92.8 208-208s-92.8-208-208-208-208 92.8-208 208 92.8 208 208 208z m0-128c-44.8 0-80-35.2-80-80s35.2-80 80-80 80 35.2 80 80-35.2 80-80 80zM432 838.4c-9.6 19.2-32 28.8-51.2 22.4-80-19.2-150.4-60.8-208-112-12.8-16-16-35.2-9.6-54.4 6.4-12.8 9.6-25.6 9.6-41.6 0-51.2-41.6-92.8-89.6-92.8-19.2 0-38.4-12.8-41.6-32C22.4 486.4 16 435.2 16 384c0-35.2 3.2-67.2 9.6-99.2 3.2-22.4 25.6-38.4 48-35.2h9.6c51.2 0 89.6-41.6 89.6-92.8 0-22.4-9.6-41.6-22.4-57.6-16-16-12.8-41.6 3.2-60.8 57.6-60.8 131.2-105.6 214.4-131.2 22.4-6.4 48 6.4 54.4 28.8 12.8 38.4 44.8 64 86.4 64s73.6-25.6 86.4-64c6.4-22.4 32-35.2 54.4-28.8 83.2 25.6 156.8 70.4 214.4 131.2 16 16 16 41.6 3.2 60.8-12.8 16-22.4 35.2-22.4 57.6 0 51.2 41.6 92.8 89.6 92.8h9.6c22.4-3.2 44.8 12.8 48 35.2 6.4 32 9.6 67.2 9.6 99.2 0 51.2-6.4 102.4-22.4 150.4-6.4 19.2-22.4 32-41.6 32-51.2 0-89.6 41.6-89.6 92.8 0 16 3.2 28.8 9.6 41.6 9.6 16 3.2 38.4-9.6 51.2-57.6 54.4-128 92.8-204.8 115.2-19.2 0-41.6-9.6-51.2-28.8-16-28.8-44.8-51.2-80-51.2s-67.2 22.4-80 51.2zM288 633.6c0 16-3.2 28.8-6.4 41.6 32 25.6 67.2 44.8 105.6 60.8 28.8-38.4 73.6-60.8 124.8-60.8s96 22.4 124.8 60.8c38.4-12.8 73.6-35.2 105.6-60.8-3.2-12.8-6.4-28.8-6.4-41.6 0-80 57.6-150.4 134.4-163.2 6.4-28.8 9.6-57.6 9.6-86.4 0-16 0-28.8-3.2-44.8-80-9.6-140.8-80-140.8-163.2 0-25.6 6.4-51.2 16-73.6-32-28.8-67.2-51.2-105.6-67.2-28.8 48-80 76.8-137.6 76.8s-108.8-32-137.6-76.8c-38.4 16-73.6 38.4-105.6 67.2 9.6 22.4 16 48 16 73.6 0 83.2-60.8 153.6-140.8 163.2 3.2 12.8 3.2 28.8 3.2 41.6 0 28.8 3.2 57.6 9.6 86.4C230.4 483.2 288 550.4 288 633.6z" horiz-adv-x="1024" /> + <glyph glyph-name="set-up" unicode="" d="M512 576c105.6 0 192-86.4 192-192s-86.4-192-192-192-192 86.4-192 192 86.4 192 192 192z m0-96c-54.4 0-96-41.6-96-96s41.6-96 96-96 96 41.6 96 96-41.6 96-96 96zM432 835.2c-9.6 19.2-32 28.8-54.4 22.4-83.2-19.2-153.6-60.8-214.4-112-12.8-16-16-35.2-9.6-54.4 6.4-12.8 9.6-25.6 9.6-41.6 0-51.2-44.8-92.8-92.8-92.8-19.2 0-38.4-12.8-44.8-32-19.2-41.6-25.6-92.8-25.6-144 0-35.2 3.2-67.2 9.6-99.2 3.2-22.4 25.6-38.4 51.2-35.2h9.6c54.4 0 92.8-41.6 92.8-92.8 0-22.4-9.6-41.6-22.4-57.6-16-16-12.8-41.6 3.2-60.8 60.8-60.8 137.6-105.6 224-131.2 22.4-6.4 51.2 6.4 57.6 28.8 12.8 38.4 48 64 89.6 64s76.8-25.6 89.6-64c6.4-22.4 32-35.2 57.6-28.8 86.4 25.6 163.2 70.4 224 131.2 16 16 16 41.6 3.2 60.8-12.8 16-22.4 35.2-22.4 57.6 0 51.2 44.8 92.8 92.8 92.8h9.6c22.4-3.2 48 12.8 51.2 35.2 6.4 32 9.6 67.2 9.6 99.2 0 51.2-6.4 102.4-22.4 150.4-6.4 19.2-22.4 32-44.8 32-54.4 0-92.8 41.6-92.8 92.8 0 16 3.2 28.8 9.6 41.6 3.2 16-3.2 38.4-16 51.2-60.8 54.4-134.4 92.8-211.2 115.2-19.2 0-44.8-9.6-54.4-28.8-16-28.8-48-51.2-83.2-51.2s-70.4 22.4-83.2 51.2zM262.4 656c0 16-3.2 32-6.4 44.8 35.2 28.8 76.8 48 118.4 67.2 32-41.6 83.2-67.2 140.8-67.2 57.6 0 108.8 25.6 140.8 67.2 44.8-12.8 83.2-38.4 118.4-67.2-3.2-12.8-6.4-32-6.4-44.8 0-86.4 64-166.4 150.4-179.2 6.4-32 9.6-64 9.6-96 0-16 0-32-3.2-48-89.6-9.6-160-86.4-160-179.2 0-28.8 6.4-57.6 19.2-80-35.2-32-76.8-57.6-118.4-73.6-32 51.2-89.6 83.2-153.6 83.2s-121.6-35.2-153.6-83.2c-44.8 16-83.2 41.6-118.4 73.6 6.4 25.6 16 51.2 16 80 0 89.6-67.2 169.6-160 179.2 3.2 12.8 3.2 32 3.2 44.8 0 32 3.2 64 9.6 96 89.6 16 153.6 89.6 153.6 182.4z" horiz-adv-x="1024" /> <glyph glyph-name="language" unicode="" d="M982.4 582.4C905.6 768 723.2 896 512 896 230.4 896 0 665.6 0 384s230.4-512 512-512 512 230.4 512 512c0 96-41.6 198.4-41.6 198.4zM76.8 384c0 54.4 9.6 105.6 28.8 153.6 22.4-12.8 54.4-16 54.4-41.6 0-86.4 3.2-179.2 86.4-179.2 3.2 0 44.8-16 67.2-67.2 6.4-19.2 35.2 0 67.2 0 16 0 0-25.6 0-80s121.6-134.4 121.6-134.4c0-35.2 0-64 3.2-86.4C265.6-48 76.8 147.2 76.8 384z m540.8-422.4c16 70.4 25.6 108.8 60.8 137.6 51.2 41.6 6.4 89.6-32 83.2-32-3.2-12.8 35.2-38.4 38.4-28.8 3.2-64 54.4-102.4 73.6-22.4 9.6-41.6 35.2-73.6 35.2-28.8 0-70.4-22.4-70.4-3.2 0 60.8-6.4 102.4-6.4 121.6 0 12.8-9.6 3.2 28.8 3.2 22.4 0 9.6 41.6 32 41.6 19.2 0 70.4-19.2 83.2-9.6 12.8 6.4 86.4-185.6 86.4-32 0 19.2-9.6 48 0 67.2 38.4 67.2 76.8 124.8 73.6 131.2-3.2 3.2-41.6 9.6-70.4 0-9.6-3.2 3.2-19.2-12.8-22.4-57.6-12.8-105.6 12.8-86.4 38.4 16 25.6 83.2 9.6 86.4 60.8 3.2 28.8 6.4 64 6.4 86.4 156.8-22.4 284.8-128 339.2-272-147.2-108.8-108.8-182.4-60.8-227.2 25.6-22.4 51.2-57.6 67.2-83.2-57.6-128-169.6-233.6-310.4-268.8z" horiz-adv-x="1024" /> diff --git a/media/css/sf_font3/iconfont.ttf b/media/css/sf_font3/iconfont.ttf index 62b77ed106fc5524790012d7e3dab095275fc347..0a1dae1a5d6a7ba21ac1b533cd4fb8f47919ded5 100644 GIT binary patch delta 910 zcmXv~ZD<>H9RC0R_m;cdYc9FVUG6R~m*kR5(x$!3-5f3yon;HU(kV4c=vq2!mFi}l zIQ?LUl;K2STV*1;IX@}-Wf+lt=tmI|g?$r5v{+VxhzxuKtBF_856|=a@$m5D`8}@; z;2Q&Yaq4jQ2=*=j+;srvKUjHe@uVw$#Q*@dBLpjvK;6dvjP|Vv#g(VdoE>PR9RT3Z z5eBQLmKL9XeLj6@!?uqAfF3`6>e(}~-FLnR;OQFx5K908fSnti13jD^?OpoPvb>#J zADs~H{vE{e=pq0+&wWPzKSz6g68;U*Xm3-*rZ;)S_UEu4=qDD^1FfK~>Id~NGFIkv zW-D{Y=ol{<yXJZ89_vo_a`u<p%eh<mn}yHqo_)psuDDQqt+-wKxb#<fxxDK%owLp# zm7ua#tyF(<+wNs|yLPemVeMw^$GTBptN+%RZ(JYijz84D#%+zSkM>3vaEPq}0|a0e zfKtmZ7bsGIifX~hFgOJBlR?XOFv?N$P*vJ!98x4js!A4Oq@pSw;e;hf@i6jdVHh}N zsvtmYY~O{2YKR_9WEhfJzF&_C={N_M%rgBxH+_Ei&G1v3SvPouoVN@dLpWFN^K4p> z;KSj;;SS2#Y>dJrdeh_8I8VpiKJTSP=EgMlX5jJ(98t@?3`I~euHhI79=aX<AIQlB zkw|i{nxw?W1yUV;ZMJxZ^qLI3s!}FPu&8{Ykd8rIfq^dZF-9DIs~!Cn^iQ^Li`?5d zg)IUWq`;Hlz0J9qwe=v3Y6wC_B~wW&`ahMVc$8F0Y79m-QDr9#!l<7y=tLa05dwbK z_q!|m<X6M+co@DwWyNQfWro&kX<o;523ay)^%WLldmB=bpeNcB43U>NdMu>X$izrl zj8+I$s<hS_MAMJFDCQ`(;g5eps)b}#J37}%A83=#eJ+F5JFXl|X|pHXigxHOf<Sn+ z)4-Vew1cMpixFj6*w1l1gi8X8>vNhVD_TuU@CUkHQ%a$hV;O8g=sAQWnYL|865;eB z!LYPru7*-l(|hn<K?)ot$(qbeQQ#HRyejK*A};4_J12U&Ts!8I&1Oy{CTDv23C*di aYDw`Ea$FMXGakX^n$4K^Kp&sQ?SBCeQpM%~ delta 895 zcmXv~U5Fc16ux(E?%ZTDcP7*9{3V&$B$Lc+GRbU6wv*kuhF!ASc3HJ{*;ZxO-P%f5 zU0aPs`<6TusbXQv79VOYf~6q%VuO7u#pj|gf_*5W3)Ll*w$xS;VM&|?<?wyyaL&g$ zhwnlUp6$W)shNMio%{v>`UL>5URr(q$g#rq?N0#!n*sdQph33K-$8vNKyLNzQ>S~{ zpa%fFAE38(^5~Hdo?80;{29xd1b{jI&dK*qg|{yK0>FtY0N|ql0)RS$4p<DagYEOT zO!JSQW|x-5$-h7}6l?_G?pyok{?CK$E(^EehJf~M2n^pngno^@@tSr|&*>);lZji& zbh4GanS7j@OLbB`<E%MjJ|4a>{3v}U{bS}@_B-p4wQk+cy^{MdcPIaK{!e?w-gJsi z%Xu_X8Cff23%?b|i=PzlxF5S$+-vU7C8e}hdRTs`e9=2N`h52?y)oJbVDJ^%M9+W} z@WDI)`Q2l7mKC9@>_pXn8fL2g?lA`uN6q9_rNKD1Ls-Hp!w|87q=ub(9ufhnCLD%! zKN#CqumE{5kfFL-XXYh!7rSCKFbQK-hR-Ez_H)|o^tbvyv@K4j2!)gDY6OQl>#9gK zL4;HFdjAQ7ES|+EM$T0*gfuKfh;x-zH5&P{NzcvNycEVO*?ov*ph$~$g2tiJR3AKv z<B%Xn_2UUFaXN|jH<hXwA>}d$KZ+BbVxF-&LR5@~VJObSv?2%*+JB%l?{-%jzsKlh zbPpW^JdnYg;IoZ`FSObwton6DW#u6=@I@XX0wWKpEb(BLCAJgT<G~%SHy{HhmdD4J zTRSw7^}HF+YY|g;cX^28^nxa8OoC$!DPoVQQHCCFOPLVoHOd^$NbSQs<P@!_a+1Mt zDpmx0j3b0wXrC4hLW{N1Mb>R7({s~G&1bDfo<k#3`B-I-ynkU<nW)6_(+=YH%rOW4 zyB|E!*?C~bgYSzJCl_=xuIR45OQ^qGt4K2P9WxcR#6<^7l3`hfBw=Tf&x$ECP$5~W z)aIL_<To5O9yPfGmMAEOaXqG62_v00q>>&Rd3Kbzt`WoD-a^iHwOpZSX|A0s?Da4; OT$f)0pc{KJWc>^1-NPFI diff --git a/media/css/sf_font3/iconfont.woff b/media/css/sf_font3/iconfont.woff index fe823786dc8f008852dfa4c3c3a21e1ec491a251..77a4a0b7a7fc85ca681a18600395cd7729161962 100644 GIT binary patch delta 14946 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 delta 14870 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 Iv-m&A1V4oMJOBUy diff --git a/media/css/sf_font3/iconfont.woff2 b/media/css/sf_font3/iconfont.woff2 index 5a753e5c8fabb8201adff39a3cee1c4a083de0ce..48dbc69dbe0b1b331fba4fe32aa88fcbd53f65d6 100644 GIT binary patch literal 14836 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 aQhJ)WG^8oM9+9(DWkWb4F60jY0001eTjN0h literal 14860 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�J&%r;-C12;9us| z!V<I8`AYf&@sF&XKb_g`bw_gl{OO%(cBo)ReET^*O087VE=Ya|&_7&^G;lhELG`NT z_#uxGMq~^ta?I120Z+7_28{}+R=mCdJIt^`Fn5SWmi)`P4Iax$W3H2~V~TS_LnfKy z%;9(+<jssDz|AMy7g?=sEM)LBctZafDYl#Z`K!3Hq-`8&;~IX8g-gJhtkRT*d7-Ay zZsMhu7T+}%DJQZ#8AL;Xd6}`N%?+zvv}nR(Mcco{*RD?lO<cS7aM(k3IeU>alggm> zvIl@4q@IvWG}f5!5!sh)x^ke;Ep`u_xi9G@QRI~R%KDn1;UqB$I{sb?gz?2!_i;8o zuD`F;MP#}M&cEZom(~~mZH9n}Fr(Xd8V^me=)3-w(dV<SZ&<|`Jvike$~>I`kM)mr zjr+6dXZsv4U^pNT0>%PhqJtn{6ypg5$O>SPfO55u-!6|&mb19Hi`RL6jrSTD?&|EK z;B!Ueow{^>soGQ1L7Bz1n(F-gKQy%%W&fF<S6!>Yc&^O*^Uk`O3Qb>|t-lq&q3T=~ zU=5^Dy*C^GLNHZ81=+ihjnNMb+lp)K!VnL*01QK1?PFxrUbJ&;a?HsOm_)~S;zN)a z3KHT<)2WO?4FQqQO1}It*BBV$%N*Ie2*>Vo&oPGLdhJGYe?f#-rq!P)maC7l$t3!0 z!S$c@@%-@PKLu!&A8tpZeOEWBA03C$@t@Sw*PDD(Tq%b-wC!fQoL~G_=n}py=I3hp za=TgE-f^h>QKe*8<*-#Y$f-;TmS=@lAyuKru~LG860#@lHWarwU&ab(i<r8`CTMdA zB<Vv(F5O@ffF|*XT%M9A<UM)!jKapVgnc%kY}7t%2kxOYdj5!dKs_aiI~;Z>=c10^ zr{_<>1L}XJZ&lPks7LhtFJ&K%@MqE^Lj6bmm@P;01EM%lWg@vYaXJ;Y%8tSs5ST1W zY&MB*B$yIzh#(o$|M&+#W;Vo{aYN{cDUOXQZ82m$4R;HO**KY6+lZ6o)%W;u7S{0g z_|+`poMp8h?6#nZ$xp&Jf_pVR(a3VPzhE!;q3k&u-#IvHcW2=iX^f;Q+qp{<4WgaT zpI25oLLU6LqBNcbq)T4Sm6dP*_3?%-d3dcjMy3-dLYgWnUp#-kdq@j?f<*UtU_#}U zbDn=-(1s#OfBA`!=86h{9q<Mh?R=B$lR3MAH$Lu&WPNwd{fN<H?e}BQljk{$+Cxaj z=x%KP6&ho-ER&`{Rh8!Q4>{!o(d=l=w5cW!yEFIlnz^SqI@)nFKPuF{euZkw2W4Q# z_=%gLuqI(IHaw60QT>DHl8&F&zpnu(J3A^B9Cq+c;03u@27n`kSvhu@LuPkfv1j~u zr%N#7ZsBwy6i+Hb^`z{hZn9yJ)ns#m>dE(f4}s@p<45n~dupNgmodag4%2{=42QuQ zO-Ysp&kxaNt{<~P-ZTKdPKkGxZfBCdu~DCd)Wjy0RpI0rts@NX%LQ4e`4<sbL=~%E z7)j5IZyQ6$0HK@H_w5s^;qLALLCF13SRL&hY_mxS7Og{QFU;or{FK)5eHqNl8(i0O zH|)@G+xc~a<A?18LFmupaV4>_CCxF#rP0l$F)^jFyc-qc8U8_aMbVqoq><8?Sj8z# zeNp{l_hLA2_A8Tz#NDXGz*wg2&xvm^34mV-9Rxr9V``-S=e^AHjO)|&BfqPDpB|Zi z<v4SEzwF8UYfPc(APVgQ)E%-WB7i3%eNoU%6@f@FOwq==cNhpvu0f^k`A*5&!Ckgs z#)73>ahQnP*$GC61e9Pp7&aI)6TRdReq>^&Dknr%F1?VG=S+OR4hSKHai5~3+-JDx zOCH{D?ebiBJmUC5&pkW~59}U1<O<KhbvRB~sjTGlD*?2m^TyX|6H)o-z`!T+$&ZSO z${GtuES;^NP<(u>m{cgT(aIE=+^9Un9%nNzgR<al+m5mxN*}TWf{Ot{_5;N@`^>i8 zkAkK@1%a}^)jBN<^1Smrg9hRv_#~$IAZy`mh)+tQ&w$x{!WebJVl69?Rh7!h;Q8{B zT3M;JuTNF#Rj|ybLwv9#5_V6kthB}}vmihnSuC@tbUGo(<7WBH2M5W2$uvg}+%_QE zL=ycdB5e}My%x!W9R=h`=zU+nX1kZgYa83@HD&Gj43_4jkul4>l%58O#S4HznI!6t zO(3I)*XQ&cax7Vn-w<G~NANqhe8%VmmpS(@_9d=h$82MGRf4?MVC!jR?e`&fkrl?e zA9{GAifFkeylQspb^&YJYbZ1)G$dCgZ`C-alxUT!%q=IhIvQuXdJ<QmzUBXSExS_n z-^r_{_ftA)@AciYCaL(S<!s{ygJWmzwT8ba$HM>29ySyMwuhOwoLm^Y$jz26`KEz$ z?p(09&+0=<U8~+Me%rCuZ*@N<n0xNLBzOs1y2u?{Nb0ejHd0pH<gXiOYLo`v9d#_> zEUBNB@Lg`BV{qUWzj1zM(?FjIs6x2j;RRFz5DrqbKrPT{g(}SLw3qfW#z-$HW}O$I zcu{v>K>=gCp4-gBQ?M)4B}@tQ#iNxy11C<v3V+XImSc{dZZI@DJT`0}<3VjWY2D+r zlT9|823O1Nem!008Wci^aG00E8#Y{@t61ZDT;HnE8!xEtE)CAP+d;NGXb(1LLqO>D zd5hbdwT)(rhbIl2W1ZM`_}H_7b=dih9s>ig+ib3^90LR>NZJ+m(?G<gf2L(m0>Z<8 zTyhz9%ccYT0s@}MKAi&m0|Jh5cEC@LPlf0K;|eMs>g~0ERR!VsO*f5beJ_8CKZMq$ zZS`DTxDW_d7F@fgva7Tj(8dmdj}s9xjC?qya|z6^Lu)d^h475OrYzZ~wHG~&eAIEc z%r}0`5vDP*EY)-7q-J_VSe^(`RUeK6-gP@`f>p?Vz?zwLIq@T*w1GeshTMzwfL-`R zho0{vTk2U6;4tl!53V+w*ksl)OzG+J18%2q)^C&E+h$m^%4I%3eg)X{BsDv&GPriu z0>lgqSBV}4c3^X7c64ZUZ{8A3^qj~9F_3Z=Hv2WU8F=5Q+YaoGX#6NrIC5Q^MvDS@ zUW)zc3<`)DuXW`Zch!2>)3EU&H>ebFWa}uAXvC{<rrYuc*IQ!w00FJNrPOxi3|pY- zEx-Ri2zKL4-#A~WevzSS{D|~=^Vmq(qApvrw!VI?Ce+5sWW<`T9Hn%XL9kj_YCi89 zb7>58FzW2G{dO|l=U1sV*RHbRu+3Ogp-}emZ``Uh(WVR!^Oze;9DYHzQA`FLPOi;% zJU&@lR)=shDDrgwZzf9iAd9TkvYk^r)pK}N`z4XQh3Dw;E_E4OR>NEPzaRhN4o!or ztR#D&JK;llCeiz%ZaCPPPNZIFrn*XsxA0H<eSWTclczQhwfmQei?yt#J!WEImgjcS zcFzM&q=ixQyywJJk~6|~4`ERj&6^o^_pq5a!Y&J&7YHn0)y~RExB2_zWHVvhc*tez z3l+AY%DW3YI)tdvDsK_y1=`Qid`4JQ+TJR2l9YDU`&R14)xTX6J|GT~eEhon=xwuK zdIc3u&J6N=S-pbp=c3YS?a*Wxu!E1q*qYg*$H`+oU<#NISXN)asPdqL5Qubb3!IHx z*Z%$}^(4E-l)bMEYKTl^ZH3m}%AsI1_5gGIXD?5Pt;Z4M7!}1k8Tah(hD*6<fZh(J z<uBF0By8SPcdPjNc1&HmcWnQ(x*G$by`>N&@St(M-Ya!`0;~Z(Vcy)Z+ivt^8Ux5W z-{~e)>-$|#(ZhPO{=A+NrV7hR{q<w^F|bxT$13FNCm@quT?l>|K{o<x>2O`*LvfDm z|IrEPu=&uNS2-%N%nz@D;a`jDr(Q+s5VLP^&@A!5_>51C@*Vm0K?sAjTDy54aPsHo z3oWptIazl4b{aPoqr<p(PA$gB26As7l%>S+tZ*J|v}_%=4{x__UvFQ(wd?Qj{3x|O zI)QEQHud~h|GKBqYNRG6%$^?!LQCv{e~(B6a!P=YloAG@*+@S+HONnLu}hvk>Kbzm zIbFdumx$&bLG%j?0yc*@-JDwjUs>-JZ23>8_3`XrE^klZk`EpIuikg83g06S<`N;i zdi;D7du*exlxlXmJvtJ^Y!;|MP-;#Ol5;=f$#PESJjR>6<<<hYsgVuAKy-S1FwA z-~WB5)Oq7-5);v_-B0G`CqRaOj+MnFVcw<3#%0f9+#s>_n%bH~U8H;ZCsC<LO;zLx z^@uW5kx>_2@mk<cew1|Ccp1Qd7pe&{9#w*aEBOfQ3ezU2>xM(^geF&r+Z{4f#7N-- z&+9R5GLnk(lkD}HpZxQbsS0gl(iA&W70GgWiad31?#dKds$!<!mAXJecX7n$^Ww{6 z<I57}zIEhip<R0GbvfeV9Px7(%#&unR`@IK+8`NmoZlGcp}B}*>()yi4?v%>K>kUk zErjt0(}^iW3&v_BrjyR#1qCYIlYBX*vY1)IJZeTx^ZpA|>J3Cyt3NL-)%lO;Nga~v zn^i1DqiX8zdFg6S(1++<aiy`br7ey+9tS;IR_2Hq$tMSSrb^U(&ieB_#67;+FEHaZ zhb>JH4$xyhQ<(HKr2Z{8gKAPu3=oPM)>dgWRZ9$6&yxFR>z?Y2LS-t9Z)qAd(of;@ zh=rs%7bT9$?Rkn6WkyyrO-X3MJIXN?o9Xg$d<(&Ii}HEjzzzrYLe1%~4-3+j@H_1_ zI?~xZLKmMI>MW8L3c~6h^lkYwH#rygE2$E8!{#8N`@rsz>-B}G-jIx<18y}34r{+< z-hQKDHVRyGCRQOxb(^NjR=cFu)?b@8q`Dd@^G?d~?h8(yojm<uRs+gGsiAx@@Rc=* zme`DjUzy{Q@1^77@lAo`uCln0&Vl;1m|d-`VSVpK49t(-o}M4qU}eJ<Rb+VUo-3cb z8RD6<6i2?krBwZ29ltk|nJU<y(0)g(mb}6pdKOBIn{%QRJRc6`+q*aD<SD+0cZG+8 zz-O%>Al@myijFz^y5Rqn<^BFPnzyA?OF<|`3~$R~&-B0)k^U-FzxKZN|6TGaPyT(p zC%pt8t)IZbvN`1O!UA4-ZD?FZqNRo(g?qFi4R6E`>%y4uJ&$lv{-`RgH9q6o*P8sm zqHE9HexdT&;?EdbqH@l)qH8bQzF)kOs3R@{U&z&39#^JJ`iLuUU7k^Y@L;pft!v(Q zu-?4fmk?AUZq5t0$CQ=DmdCX?t<-R9nLOFDQ*M-}Bp=nCM$e<9D2zK5sq*A{jEXKN z**C2?9LZoplz1P{qy>JG1HR0RkmB&P0`i;e)kjOu6`re`dTXWXXc1IB6=VMAMbLEA zicAM?bM)-U$l3LVx~Kl$7v+>dT2a?n{oqC|Z+33f`aZVzmz`W%o!{zw^$`6O+Cv;J z@vqqKdD%Ma3o!<S3|>n(F^B-n<<~lE1hrw7zxRSQ93uJ@eMp_d)@Ec<<DLMgZ(h|v zuDKbeU9LJks6H}qke;{cZUMqK>EF}>!K^&G6i#|*SgY_0ZulrN$V9K+eWOc}T8y&n zW$#{zWFi9+RI2n-tX-E@0OE@cfd$>tP%-3xwdTZmrS^Xp)q5t}H#z4NC+9nIRNO3F zsu<J%=Mk`)(~EtPOU4oXGdN7?Z(9YnASApIl*HO&B8#F+d_%@pkNt;b%GAS2LM=1A zcKBWgor0f#WBx5FX(<!eOOPb7@DK$0nD_{xS{OlX%ym7}3Fd}x<bV0H>AO%|27#J< zwlj2IUsC3Zz)%8KoO$ps!(jNTtX~`Z-$D6)4fKO6q?N@f7$oQ(g{3Gm8?ueS?F4h= zy<+g9bC*ZeZ4yLS?Uf<Xqui!+Rw9QFM-Znu6Xb|?_8gJ^hvi-Kouna8O3c_Q0K*8C z;Tu4?J`b|ZaZ5^o9YhY>U(zk~2GjSXJ?B)*qxCf%h>6iT?=)LaU$f|v%_UePey*D7 z1=4dmZL1q(uevqLhvIhSCJI+*J||_=@giI?8aE2U<fc*}FeOGGxnfUF8*l;8FJYg* z_)vajLOwCKvQQkC3hzTFGXI4q6jy$Zb@8q<Ju&&nfp<k6fd9=jnh65=F9;pFH5PBB zDe!Y^k}bUlWyl;{cit<L{{!FeD@W)Ch`3#m7^*{fa>JG^&P=S=s(c8~U$%UbCI+Wc zZTk3ZMd}^+HIw8e{%}9TBu@C%^lSg4W&CFPEn(^0;5B<!^b6%5mj5%a@4!CXydU$r zj$mTsF;5o0Gx^0@A~U)3WEGO%bZ0Zzsn>T2E_5v+q*}fkDC*o(YSmDlQD6V@Z<qJn zHM})kelt|MqL+vSp#W~Poll0iDC)c4rv}1My-NA$b{zaa+i|~rroN2YTk6<<dCtE5 zW#uKn8k(;v-w(<_NvKtocSx+0WVK<_u<8CO-q8=fOiV+iqhINC5_21A4d37$@#!mM z01JdPd!k^)YREGgtHY$lx5W<%W!gY7B90H9lNlHMrHCn>WLX^Ctw>S&LvwZ$&8Xh{ zspMBQ9oU~6%-Q`tIR1;r@QjuH%VPp-61cPdh$|zmwxPaYXK9BG1mbx#yZ+kIuz)iD z4nh}a8PEWI3I`cL{MD!SEc(WNh>?uZ5i@vg@w@p_T~g2GB2USrh#~qPVo!f!&UWbc zt<OqE(Vx=Erh4NiJEno{^xzgJ+yAK`x^uOk$L4Z%=r1@~s^JJO@!Tl8_}X$S2v=Qy zEO|@|FY-m!QFuZ!K_k;>4<+MXY$uLl*Fo#OPcueGWFUq*1p5uq$xgR&86kA;IF}y6 z;I^L5H$a_3uGHT9;~v<Z&q!hzO)ZsfvD_^5@VaCf!@`hdex%KYZ!^DjUUun4{DnN) z$oZVtFU)68+998>&-k8Q?(_Ls-!tcyGm_}341FGuYa&2MK3XaxH?ru~8E4E1;2-k` ztaZ~NpXFz%+_7aoU!3;7LnO1u6_*qfiU&Zw=?^Z0yOa~a-SO@x^HJT=?^GLB8c295 z>`P-(7ju^3sal^fo{krmC=(pj?YuD)ca+}AsQmbsUU!t4z;yiq$%DeOw*G#^td$_5 zz(lcjy&g0WK?1en4XBks#3M*-?di+{E-D1{iiZTXv}dl?e77>md(bZKC_sIBF^Y-Z z8mCTZU<TqVxM2UDC%riUG~54?$fs1GZlPing7g&s(&xD8IaN<((sWcEO<nb57)?9) z4LTn*c^If0yzT3;n`;y2M5nyJTV>SY@dm4<F}7R17VAR0XO;2p`;_R!IklVh*kO-x zqUq`J8ROfd`+hmbKeq4pb?uCq@4drB)C=O?;yun1{wD4q5wFlr)~$%JS{$B^`U0$7 zM!T_TI{hsF8~!#Q=vmS|(-l>^whzL2<M#N-kg`ExgBE46_e$fKuII(ydUF<42It9A zdrtE^Vp#c`3O41IxW@hvYdhCPrnN7wy0co306nwxwuXh<f^E*HoNWL_H@@hI*mU9( z4}x-#d};ZNM4t`Cd739cKMRN;r7ZlR1I_3)FAfC|#5FedHHIKjXb06A3Kq#KYo30! z7_CCHlGNzAt%ki9{H0T`4hhz37Wt1of3BwnS|*!Npk{h9PTKfr^6(^j>g41}`2Y<? z-F$ey?8xL1%E=>}sVLgHh?M}g!Nymzuw&1MLZ%b&-E2>+)Ff22B@8#T-2;_@iiSDf zlb(>q(zW7OHnBF{$~?^2PJB#$U$E$VNhl-JLlapL89u8bqM)S;AV?J#g0E;=Ilc7B zL!-%Tdicb_C^e=Tjk`l0PZ&)prUQQ?YmM3h3&FePT(?hFas8JZ3P;WHoj&>}p?E*h z8y@|0j}PZX2yAQ2HSP?l|C=Y|#B<c@Fss`eivD^bSELqk7ji^AE`}LC%E721&ZzW) z$9)OzZdqmg=9@2czpPc!gAI(QXxMDnOoAcz)~-Of51`$l(hUZM><CY2-GWBPlZF#O zH9bC?G^^8BrXo(A1?_W~20pP-+fSV>M_FWF)=ugV6&UJUGXQ08^=WeKDl0`+qgKh` zq#K!Tdg?}a0A3>$%{!rQDNS0IjL!-!-LS?z<0JiBo^TD^rP6LumX#aMNQ;l3%x!6u zdPS5xopFV3+^FvCLX$J^rQ$l`e}?;nsl+Wa68CKgAs0}7^z)sFUW|suEi%oDEN*0m zXC^n5K(s^@0W~H`216KJv@*NQ8!63qZ<%Sk5a{kapt`+(^X+-6Ie`nW*?&0WLnf4r zz?htXls*`4(<I|M!RKxlo&K@1j{)u5_!%nNy4_GrwhiOB-IZ9V4S=>jCCq~{6G_CQ z0YDT4!AEdZtnH)HCMoR#zA-e8#HpN6ZVm}O&yA0A0BC>2ag!O1F$nR2QOO-Ibuvk% za@s)r2H8XYvo&0al4iJKn1jTqB>sX6#-v9QODEl*{!<zkQ~B{6V=`P4<wu@y$Ze$v zx8M|9kNz-3PyhgwpsZL6whz|M#~UaPZgLXIa(hjKL*dl4(^>dCR02Rd7=MHzpF<o$ z&o;)NP%$Ufz!-~-mPp`>DK9ZX|Ch25OX%Y@A+&*b8`P)>#scc+P@dF~Y9<fWW{h>^ zF?})tx@v}PzBDN$HI^cGfiV^*j677kF&Ja^KHtYLkRGlZ!Uab>F~(@PO28hfkPde( zN!{mYq984-yK6`ZV<bVC*%<$W3hxU3NyD(;zajpCN*^-(AOa{_qj*=qkXD2PCPOZe z*zW3m6f^?dA9DD9DMLR(+FTraiS}@NQR`(`Y(eZpPXf?(XkeU-qZqs!2Q&-(e1zK# zNDwK{iGHe0(OvP9^Qf`AHgha7kS>&u-!=RO^(~IYGe{T{pJD=P|5W@1asDf+J9u?7 zwa`Y3dqp5&fSY(zVKjMMhvCGK9xn3afBrIhz<)f|3NW}t;Pq@r?+YUg0Orrf?OtCH zW}~mAm;VIg`MW<+Hfp@gBFWpBPqYp1aW7b(dC7iG_lI=Jhw$c5f9QcTW(0otFQ4K= z1E!nj0RFG+a34H0@_<a1KnUn|u!H9l3<R){o$}xq5>;><L40tU0wf)K1{2f*2r4}Q zune?s1X1W<TM&)va1cTVX9Y~>?I0E#{29cdgO5QXD~eJdi5S%{z9`6%hQnpxC}mRG zZMqA7>YtdmOnNztd;beHo*2gcP5ZzvD9}DU>@?rHPs60L4nJ?*Fyt&lRr!YK`^CL} zy}q7ezV}hq2R|stk%q%%`Pdw#Oh>y-cOm@I|A~3aq={K!{0jnSyzj%fzk%=zFQi$8 z*zGjmy3wZL@R};?@N*vEFgMFk<K{O+82cr|tY5F2l_o0R*C?;gO8kB|r`taMGHhB( z+m7q6-I9;5k9PmXdA9^f(G1J+f+)#~s_BMl*^cY^!EPT$agt_vQC4-+cKt9Ojwe+$ zbq!4|Z5>@beFH-yV-r&|0+B?fP-%1qlf~w6d3=Gng{76Xjjf%%gQJtPi>sTvho_gf zkFQ^nrCfNYm=w0Wikm8mhb)ntr9314Z?+A2yi)yA7jdx=Gnq|{6b_eAAvL4>gUUg* zIy%VaW4Dz_a%vX4ddh1R^<YWj^Q~r~6k`3*zz1j8*hod`W|gguT|4E_=J9e_3my6_ zaY!&uIAF^2n8gri?{GgFzK-{g6<nFhobfC!h{q6FW5$~#ZJ$|Nm5cAJaw*UzOFTA4 zCp^XlPshf>aDHCnzEVknROM`eviG)3uuQf*i<F0+NU!2ghn#F7$+`3w%2p?V^y}KL zG;{22Aw@@9YodPF@>MZ(g_IXb2`fi(gc>Q_t#U$ed0Df>s$6gmPKPFQId*EPx6KN7 zs$JMcpO}*dtko~gIcrA2t};kp%bra$ZzU9Tib5+|9pQ1OOrKP$bl1mDb3ZGmaN-zl zlg#X~Sw+!`Qpc-_hp?5uOUQ7H&*Nq|K^<*CPVO_Cr}WcsnWT+UFJtRUw(J)FilUcY z%#7mJ;){>gp{q3ua(&6=#14&Fqg?DsLM8PTLxs<pA{FTK#1Yn=6(ugsnUDO0qI04# zhP~+I{4@I!DCZ|VK(VUyITW{B^f_*`azRfV45V@CZs5psxyn@Ljb`-S#si6vcCn}V zWoJGp>4i9BdO-*u(b|987bm(gHfJgD9an8TkYV=PzARW4q9eWX3{P9uJ9lPtA8y9R z?qElky8B;4l!Q-hAoIT^h%eA2o9PK^jdQhbpiiUAGRx*yiOcMik2{o1I-@Iu%zCWI y3C7>iy0>Ya4jHc_m53Y=AdVK+)IR4irSvp~vXCWzJtAvVWkWb4F60jY0002UE7>~$ diff --git a/seahub/repo_metadata/apis.py b/seahub/repo_metadata/apis.py index 215fb007b40..d8564d6835b 100644 --- a/seahub/repo_metadata/apis.py +++ b/seahub/repo_metadata/apis.py @@ -50,10 +50,14 @@ def get(self, request, repo_id): is_enabled = False is_tags_enabled = False tags_lang = '' + details_settings = '{}' try: record = RepoMetadata.objects.filter(repo_id=repo_id).first() if record and record.enabled: is_enabled = True + details_settings = record.details_settings + if not details_settings: + details_settings = '{}' if record and record.tags_enabled: is_tags_enabled = True tags_lang = record.tags_lang @@ -66,6 +70,7 @@ def get(self, request, repo_id): 'enabled': is_enabled, 'tags_enabled': is_tags_enabled, 'tags_lang': tags_lang, + 'details_settings': details_settings }) def put(self, request, repo_id): @@ -148,6 +153,7 @@ def delete(self, request, repo_id): record.enabled = False record.face_recognition_enabled = False record.tags_enabled = False + record.details_settings = '{}' record.save() RepoMetadataViews.objects.filter(repo_id=repo_id).delete() except Exception as e: @@ -157,6 +163,48 @@ def delete(self, request, repo_id): return Response({'success': True}) + +class MetadataDetailsSettingsView(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated, ) + throttle_classes = (UserRateThrottle, ) + + def put(self, request, repo_id): + settings = request.data.get('settings', {}) + if not settings: + error_msg = 'settings invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # resource check + repo = seafile_api.get_repo(repo_id) + if not repo: + error_msg = f'Library {repo_id} not found.' + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + if not is_repo_admin(request.user.username, repo_id): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + metadata = RepoMetadata.objects.filter(repo_id=repo_id).first() + if not metadata or not metadata.enabled: + error_msg = f'The metadata module is not enabled for repo {repo_id}.' + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + old_details_settings = metadata.details_settings if metadata.details_settings else '{}' + old_details_settings = json.loads(old_details_settings) + if not old_details_settings: + old_details_settings = {} + + old_details_settings.update(settings) + try: + metadata.details_settings = json.dumps(old_details_settings) + metadata.save() + except Exception as e: + logger.exception(e) + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') + + return Response({'success': True}) + class MetadataRecords(APIView): authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated, ) @@ -831,6 +879,7 @@ def post(self, request, repo_id): try: results = RepoMetadataViews.objects.move_view(repo_id, view_id, target_view_id) except Exception as e: + logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) @@ -1184,7 +1233,7 @@ def post(self, request, repo_id): return Response({'task_id': task_id}) def delete(self, request, repo_id): - # recource check + # resource check repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id @@ -1393,13 +1442,11 @@ def get(self, request, repo_id): return Response(query_result) - - def post(self, request, repo_id): tags_data = request.data.get('tags_data', []) if not tags_data: - error_msg = f'Tags data is required.' + error_msg = 'Tags data is required.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) metadata = RepoMetadata.objects.filter(repo_id=repo_id).first() @@ -1546,7 +1593,7 @@ def delete(self, request, repo_id): tag_ids = request.data.get('tag_ids', []) if not tag_ids: - error_msg = f'Tag ids is required.' + error_msg = 'Tag ids is required.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) metadata = RepoMetadata.objects.filter(repo_id=repo_id).first() @@ -1722,13 +1769,13 @@ def get(self, request, repo_id, tag_id): tag_files_records = tag_query.get('results', []) if not tag_files_records: - return Response({ 'metadata': [], 'results': [] }) + return Response({'metadata': [], 'results': []}) tag_files_record = tag_files_records[0] tag_files_record_ids = tag_files_record.get(TAGS_TABLE.columns.file_links.name , []) if not tag_files_record_ids: - return Response({ 'metadata': [], 'results': [] }) + return Response({'metadata': [], 'results': []}) tag_files_sql = 'SELECT `%s`, `%s`, `%s`, `%s`, `%s`, `%s` FROM %s WHERE `%s` IN (%s)' % (METADATA_TABLE.columns.id.name, METADATA_TABLE.columns.file_name.name, \ METADATA_TABLE.columns.parent_dir.name, METADATA_TABLE.columns.size.name, \ @@ -1743,4 +1790,3 @@ def get(self, request, repo_id, tag_id): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response(tag_files_query) - diff --git a/seahub/repo_metadata/models.py b/seahub/repo_metadata/models.py index 078f33f8867..5f0dbf9f930 100644 --- a/seahub/repo_metadata/models.py +++ b/seahub/repo_metadata/models.py @@ -68,6 +68,7 @@ class RepoMetadata(models.Model): tags_enabled = models.BooleanField(db_index=True) tags_lang = models.CharField(max_length=36) last_face_cluster_time = models.DateTimeField(db_index=True, blank=True, null=True) + details_settings = models.TextField() objects = RepoMetadataManager() diff --git a/seahub/repo_metadata/urls.py b/seahub/repo_metadata/urls.py index d44ddabbdb4..62d8f88e2ed 100644 --- a/seahub/repo_metadata/urls.py +++ b/seahub/repo_metadata/urls.py @@ -2,7 +2,7 @@ from .apis import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \ MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView, FacesRecords, \ FaceRecognitionManage, FacesRecord, MetadataExtractFileDetails, PeoplePhotos, MetadataTagsStatusManage, MetadataTags, \ - MetadataFileTags, MetadataTagFiles + MetadataFileTags, MetadataTagFiles, MetadataDetailsSettingsView urlpatterns = [ re_path(r'^$', MetadataManage.as_view(), name='api-v2.1-metadata'), @@ -24,6 +24,9 @@ re_path(r'^extract-file-details/$', MetadataExtractFileDetails.as_view(), name='api-v2.1-metadata-extract-file-details'), + # details settings + re_path(r'^details-settings/', MetadataDetailsSettingsView.as_view(), name='api-v2.1-metadata-details-settings'), + # tags api re_path(r'^tags-status/$', MetadataTagsStatusManage.as_view(), name='api-v2.1-metadata-tags-status'), re_path(r'^tags/$', MetadataTags.as_view(), name='api-v2.1-metadata-tags'), diff --git a/seahub/templates/file_view_react.html b/seahub/templates/file_view_react.html index 9f1270036f8..678ad5100a6 100644 --- a/seahub/templates/file_view_react.html +++ b/seahub/templates/file_view_react.html @@ -30,6 +30,7 @@ repoID: '{{ repo.id }}', repoName: '{{ repo.name|escapejs }}', repoEncrypted: {% if repo.encrypted %}true{% else %}false{% endif %}, + isRepoAdmin: {% if is_repo_admin %}true{% else %}false{% endif %}, filePath: '{{ path|escapejs }}', filePerm: '{{ file_perm }}', fileType: '{{ filetype }}', diff --git a/seahub/templates/markdown_file_view_react.html b/seahub/templates/markdown_file_view_react.html index d18e7a64a80..334dba81502 100644 --- a/seahub/templates/markdown_file_view_react.html +++ b/seahub/templates/markdown_file_view_react.html @@ -39,6 +39,7 @@ repoID: '{{ repo.id }}', repoName: '{{ repo.name|escapejs }}', repoEncrypted: {% if repo.encrypted %}true{% else %}false{% endif %}, + isRepoAdmin: {% if is_repo_admin %}true{% else %}false{% endif %}, filePath: '{{ path|escapejs }}', fileName: '{{ filename|escapejs }}', filePerm: '{{ file_perm }}', diff --git a/seahub/views/file.py b/seahub/views/file.py index 740fb559cb9..2dc89fcaef6 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -68,7 +68,7 @@ ONLINE_OFFICE_LOCK_OWNER, if_locked_by_online_office from seahub.views import check_folder_permission, \ get_unencry_rw_repos_by_user -from seahub.utils.repo import is_repo_owner, parse_repo_perm +from seahub.utils.repo import is_repo_owner, parse_repo_perm, is_repo_admin from seahub.group.utils import is_group_member from seahub.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \ XMIND_IMAGE_SIZE, get_share_link_thumbnail_src, get_thumbnail_image_path @@ -567,6 +567,7 @@ def view_lib_file(request, repo_id, path): 'file_id': file_id, 'last_commit_id': repo.head_cmmt_id, 'is_repo_owner': is_repo_owner(request, repo_id, username), + 'is_repo_admin': is_repo_admin(username, repo_id), 'path': path, 'parent_dir': parent_dir, 'filename': filename,