1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-08 10:22:46 +00:00

feat: metadata details settings (#7145)

* 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: 杨国璇 <ygx@Hello-word.local>
Co-authored-by: 杨国璇 <ygx@192.168.1.6>
This commit is contained in:
杨国璇
2024-12-09 16:56:29 +08:00
committed by GitHub
parent 3f6c4f3d26
commit ac124d20ba
45 changed files with 677 additions and 409 deletions

View File

@@ -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 {

View File

@@ -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-header">
<div className="detail-title dirent-title">
<div className="detail-header-icon-container">
<img src={icon} width={iconSize} height={iconSize} alt="" />
<Title title={title} icon={icon} iconSize={iconSize} />
<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,
};

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 />
)}
</>
);

View File

@@ -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 />
)}
</>
);

View File

@@ -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>
);
}
}

View File

@@ -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) => {

View File

@@ -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,
};

View File

@@ -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>
);
};

View File

@@ -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}

View File

@@ -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 }>