1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 01:44:13 +00:00

[library] added new 'settings' dialog(includes setting panels for (#7002)

'history', 'auto deletion', 'extended properties', and 'face
recognition')

- deleted 'history settings', 'auto deletion setting' in the dropdown
  menu & context menu of 'my library' & 'department library' items.
- fixed bug in the context menu of 'department library' items.
- deleted the 'more' menu(included 'extended properties' & 'face
  recognition') for library 'views'.
- click the 'extended properties' prompt in 'views', the new 'settings'
  dialog will be shown.
This commit is contained in:
llj
2024-11-06 20:12:39 +08:00
committed by GitHub
parent d32ca4e8fd
commit b04cc17872
13 changed files with 262 additions and 220 deletions

View File

@@ -0,0 +1,129 @@
import React, { Fragment, useCallback, useState } from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap';
import { gettext, enableRepoAutoDel } from '../../utils/constants';
import LibHistorySettingPanel from './lib-settings/lib-history-setting-panel';
import LibAutoDelSettingPanel from './lib-settings/lib-old-files-auto-del-setting-panel';
import {
MetadataStatusManagementDialog as LibExtendedPropertiesSettingPanel,
MetadataFaceRecognitionDialog as LibFaceRecognitionSettingPanel,
useMetadata
} from '../../metadata';
import '../../css/lib-settings.css';
const propTypes = {
toggleDialog: PropTypes.func.isRequired,
repoID: PropTypes.string.isRequired,
currentRepoInfo: PropTypes.object.isRequired
};
const LibSettingsDialog = ({ repoID, currentRepoInfo, toggleDialog, tab }) => {
let [activeTab, setActiveTab] = useState(tab || 'historySetting');
const toggleTab = useCallback((tab) => {
setActiveTab(tab);
}, []);
const onTabKeyDown = useCallback((e) => {
if (e.key == 'Enter' || e.key == 'Space') {
e.target.click();
}
}, []);
const { encrypted, is_admin } = currentRepoInfo;
const { enableMetadataManagement } = window.app.pageOptions;
const { enableMetadata, updateEnableMetadata, enableFaceRecognition, updateEnableFaceRecognition } = useMetadata();
const enableHistorySetting = is_admin; // repo owner, admin of the department which the repo belongs to, and ...
const enableAutoDelSetting = is_admin && enableRepoAutoDel;
const enableExtendedPropertiesSetting = !encrypted && is_admin && enableMetadataManagement;
const enableFaceRecognitionSetting = enableExtendedPropertiesSetting && enableMetadata;
return (
<div>
<Modal isOpen={true} className="lib-settings-dialog" toggle={toggleDialog}>
<ModalHeader toggle={toggleDialog}>
{gettext('Settings')}
</ModalHeader>
<ModalBody className="d-md-flex p-md-0" role="tablist">
<Fragment>
<div className="lib-setting-nav p-4">
<Nav pills className="flex-column">
{enableHistorySetting &&
<NavItem role="tab" aria-selected={activeTab === 'historySetting'} aria-controls="history-setting-panel">
<NavLink className={activeTab === 'historySetting' ? 'active' : ''} onClick={(toggleTab.bind(this, 'historySetting'))} tabIndex="0" onKeyDown={onTabKeyDown}>
{gettext('History')}
</NavLink>
</NavItem>
}
{enableAutoDelSetting &&
<NavItem role="tab" aria-selected={activeTab === 'autoDelSetting'} aria-controls="auto-del-setting-panel">
<NavLink className={activeTab === 'autoDelSetting' ? 'active' : ''} onClick={toggleTab.bind(this, 'autoDelSetting')} tabIndex="0" onKeyDown={onTabKeyDown}>
{gettext('Auto deletion')}
</NavLink>
</NavItem>
}
{enableExtendedPropertiesSetting &&
<NavItem role="tab" aria-selected={activeTab === 'extendedPropertiesSetting'} aria-controls="extended-properties-setting-panel">
<NavLink className={activeTab === 'extendedPropertiesSetting' ? 'active' : ''} onClick={toggleTab.bind(this, 'extendedPropertiesSetting')} tabIndex="0" onKeyDown={onTabKeyDown}>
{gettext('Extended properties')}
</NavLink>
</NavItem>
}
{enableFaceRecognitionSetting &&
<NavItem role="tab" aria-selected={activeTab === 'faceRecognitionSetting'} aria-controls="face-recognition-setting-panel">
<NavLink className={activeTab === 'faceRecognitionSetting' ? 'active' : ''} onClick={toggleTab.bind(this, 'faceRecognitionSetting')} tabIndex="0" onKeyDown={onTabKeyDown}>
{gettext('Face recognition')}
</NavLink>
</NavItem>
}
</Nav>
</div>
<TabContent activeTab={activeTab} className="flex-fill">
{(enableHistorySetting && activeTab === 'historySetting') &&
<TabPane tabId="historySetting" role="tabpanel" id="history-setting-panel">
<LibHistorySettingPanel
repoID={repoID}
toggleDialog={toggleDialog}
/>
</TabPane>
}
{(enableAutoDelSetting && activeTab === 'autoDelSetting') &&
<TabPane tabId="autoDelSetting" role="tabpanel" id="auto-del-setting-panel">
<LibAutoDelSettingPanel
repoID={repoID}
toggleDialog={toggleDialog}
/>
</TabPane>
}
{(enableExtendedPropertiesSetting && activeTab === 'extendedPropertiesSetting') &&
<TabPane tabId="extendedPropertiesSetting" role="tabpanel" id="extended-properties-setting-panel">
<LibExtendedPropertiesSettingPanel
repoID={repoID}
value={enableMetadata}
submit={(value) => { updateEnableMetadata(value); }}
toggleDialog={toggleDialog}
/>
</TabPane>
}
{(enableFaceRecognitionSetting && activeTab === 'faceRecognitionSetting') &&
<TabPane tabId="faceRecognitionSetting" role="tabpanel" id="face-recognition-setting-panel">
<LibFaceRecognitionSettingPanel
repoID={repoID}
value={enableFaceRecognition}
submit={(value) => { updateEnableFaceRecognition(true); }}
toggleDialog={toggleDialog}
/>
</TabPane>
}
</TabContent>
</Fragment>
</ModalBody>
</Modal>
</div>
);
};
LibSettingsDialog.propTypes = propTypes;
export default LibSettingsDialog;

View File

@@ -1,13 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Alert } from 'reactstrap';
import { gettext, enableRepoHistorySetting } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import { Button, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Alert } from 'reactstrap';
import { gettext, enableRepoHistorySetting } from '../../../utils/constants';
import { seafileAPI } from '../../../utils/seafile-api';
import { Utils } from '../../../utils/utils';
import toaster from '../../toast';
const propTypes = {
itemName: PropTypes.string.isRequired,
toggleDialog: PropTypes.func.isRequired,
repoID: PropTypes.string.isRequired,
};
@@ -108,14 +107,8 @@ class LibHistorySetting extends React.Component {
};
render() {
const { itemName: repoName } = this.props;
let title = gettext('{placeholder} History Setting');
title = title.replace('{placeholder}', '<span class="op-target text-truncate mx-1">' + Utils.HTMLescape(repoName) + '</span>');
return (
<Modal isOpen={true} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog}>
<span dangerouslySetInnerHTML={{ __html: title }} className="d-flex mw-100"></span>
</ModalHeader>
<>
<ModalBody>
<Form>
{!enableRepoHistorySetting &&
@@ -151,7 +144,7 @@ class LibHistorySetting extends React.Component {
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
<Button color="primary" onClick={this.submit}>{gettext('Submit')}</Button>
</ModalFooter>
</Modal>
</>
);
}
}

View File

@@ -1,17 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Alert } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import { Button, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Alert } from 'reactstrap';
import { gettext } from '../../../utils/constants';
import { seafileAPI } from '../../../utils/seafile-api';
import { Utils } from '../../../utils/utils';
import toaster from '../../toast';
const propTypes = {
toggleDialog: PropTypes.func.isRequired,
repoID: PropTypes.string.isRequired,
};
class LibOldFilesAutoDelDialog extends React.Component {
class LibOldFilesAutoDelSetting extends React.Component {
constructor(props) {
super(props);
@@ -93,10 +93,7 @@ class LibOldFilesAutoDelDialog extends React.Component {
render() {
return (
<Modal isOpen={true} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog}>
{gettext('Auto deletion')}
</ModalHeader>
<>
<ModalBody>
<Form>
<FormGroup check>
@@ -123,11 +120,11 @@ class LibOldFilesAutoDelDialog extends React.Component {
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
<Button color="primary" onClick={this.submit}>{gettext('Submit')}</Button>
</ModalFooter>
</Modal>
</>
);
}
}
LibOldFilesAutoDelDialog.propTypes = propTypes;
LibOldFilesAutoDelSetting.propTypes = propTypes;
export default LibOldFilesAutoDelDialog;
export default LibOldFilesAutoDelSetting;

View File

@@ -4,9 +4,17 @@ import { gettext, siteRoot } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import TreeSection from '../tree-section';
import TrashDialog from '../dialog/trash-dialog';
import LibSettingsDialog from '../dialog/lib-settings';
import './dir-others.css';
const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
const showSettings = currentRepoInfo.is_admin; // repo owner, department admin, shared with 'Admin' permission
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
const toggleSettingsDialog = () => {
setSettingsDialogOpen(!isSettingsDialogOpen);
};
const [showTrashDialog, setShowTrashDialog] = useState(false);
let trashUrl = null;
const historyUrl = siteRoot + 'repo/history/' + repoID + '/';
@@ -18,6 +26,12 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
};
return (
<TreeSection title={gettext('Others')} className="dir-others">
{showSettings &&
<div className='dir-others-item text-nowrap' title={gettext('Settings')} onClick={toggleSettingsDialog}>
<span className="sf3-font-set-up sf3-font"></span>
<span className="dir-others-item-text">{gettext('Settings')}</span>
</div>
}
{trashUrl &&
<div className='dir-others-item text-nowrap' title={gettext('Trash')} onClick={toggleTrashDialog}>
<span className="sf3-font-trash sf3-font"></span>
@@ -38,6 +52,13 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
toggleTrashDialog={toggleTrashDialog}
/>
)}
{isSettingsDialogOpen && (
<LibSettingsDialog
repoID={repoID}
currentRepoInfo={currentRepoInfo}
toggleDialog={toggleSettingsDialog}
/>
)}
</TreeSection>
);
};

View File

@@ -2,8 +2,9 @@ import React, { useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants';
import TreeSection from '../tree-section';
import { MetadataStatusManagementDialog, MetadataFaceRecognitionDialog, MetadataTreeView, useMetadata } from '../../metadata';
import { MetadataTreeView, useMetadata } from '../../metadata';
import ExtensionPrompts from './extension-prompts';
import LibSettingsDialog from '../dialog/lib-settings';
const DirViews = ({ userPerm, repoID, currentPath, currentRepoInfo }) => {
const enableMetadataManagement = useMemo(() => {
@@ -12,53 +13,14 @@ const DirViews = ({ userPerm, repoID, currentPath, currentRepoInfo }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [window.app.pageOptions.enableMetadataManagement, currentRepoInfo]);
const [showMetadataStatusManagementDialog, setShowMetadataStatusManagementDialog] = useState(false);
const [showMetadataFaceRecognitionDialog, setShowMetadataFaceRecognitionDialog] = useState(false);
const { enableMetadata, updateEnableMetadata, enableFaceRecognition, updateEnableFaceRecognition, navigation } = useMetadata();
const moreOperations = useMemo(() => {
if (!enableMetadataManagement || !currentRepoInfo.is_admin) return [];
let operations = [
{ key: 'extended-properties', value: gettext('Extended properties') }
];
if (enableMetadata) {
operations.push({ key: 'face-recognition', value: gettext('Face recognition') });
}
return operations;
}, [enableMetadataManagement, enableMetadata, currentRepoInfo]);
const moreOperationClick = useCallback((operationKey) => {
switch (operationKey) {
case 'extended-properties': {
setShowMetadataStatusManagementDialog(true);
break;
}
case 'face-recognition': {
setShowMetadataFaceRecognitionDialog(true);
break;
}
default:
break;
}
}, []);
const closeMetadataManagementDialog = useCallback(() => {
setShowMetadataStatusManagementDialog(false);
}, []);
const closeMetadataFaceRecognitionDialog = useCallback(() => {
setShowMetadataFaceRecognitionDialog(false);
}, []);
const openMetadataFaceRecognition = useCallback(() => {
updateEnableFaceRecognition(true);
}, [updateEnableFaceRecognition]);
const toggleMetadataStatus = useCallback((value) => {
updateEnableMetadata(value);
}, [updateEnableMetadata]);
const { enableMetadata, navigation } = useMetadata();
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
const toggleSettingsDialog = () => {
setSettingsDialogOpen(!isSettingsDialogOpen);
};
const onExtendedProperties = useCallback(() => {
setShowMetadataStatusManagementDialog(true);
setSettingsDialogOpen(true);
}, []);
if (!enableMetadataManagement) return null;
@@ -67,9 +29,6 @@ const DirViews = ({ userPerm, repoID, currentPath, currentRepoInfo }) => {
<>
<TreeSection
title={gettext('Views')}
moreKey={{ name: 'views' }}
moreOperations={moreOperations}
moreOperationClick={moreOperationClick}
>
{!enableMetadata ? (
<ExtensionPrompts onExtendedProperties={onExtendedProperties} />
@@ -77,20 +36,12 @@ const DirViews = ({ userPerm, repoID, currentPath, currentRepoInfo }) => {
<MetadataTreeView userPerm={userPerm} currentPath={currentPath} />
) : null}
</TreeSection>
{showMetadataStatusManagementDialog && (
<MetadataStatusManagementDialog
value={enableMetadata}
{isSettingsDialogOpen && (
<LibSettingsDialog
repoID={repoID}
toggle={closeMetadataManagementDialog}
submit={toggleMetadataStatus}
/>
)}
{showMetadataFaceRecognitionDialog && (
<MetadataFaceRecognitionDialog
value={enableFaceRecognition}
repoID={repoID}
toggle={closeMetadataFaceRecognitionDialog}
submit={openMetadataFaceRecognition}
currentRepoInfo={currentRepoInfo}
tab="extendedPropertiesSetting"
toggleDialog={toggleSettingsDialog}
/>
)}
</>
@@ -101,7 +52,7 @@ DirViews.propTypes = {
userPerm: PropTypes.string,
repoID: PropTypes.string,
currentPath: PropTypes.string,
onNodeClick: PropTypes.func,
currentRepoInfo: PropTypes.object.isRequired,
};
export default DirViews;

View File

@@ -5,18 +5,16 @@ import relativeTime from 'dayjs/plugin/relativeTime';
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
import { Link, navigate } from '@gatsbyjs/reach-router';
import { Utils } from '../../utils/utils';
import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff, enableResetEncryptedRepoPassword, isEmailConfigured, enableRepoAutoDel } from '../../utils/constants';
import { gettext, siteRoot, isPro, username, folderPermEnabled, isSystemStaff, enableResetEncryptedRepoPassword, isEmailConfigured } from '../../utils/constants';
import ModalPortal from '../../components/modal-portal';
import ShareDialog from '../../components/dialog/share-dialog';
import LibSubFolderPermissionDialog from '../../components/dialog/lib-sub-folder-permission-dialog';
import DeleteRepoDialog from '../../components/dialog/delete-repo-dialog';
import ChangeRepoPasswordDialog from '../../components/dialog/change-repo-password-dialog';
import ResetEncryptedRepoPasswordDialog from '../../components/dialog/reset-encrypted-repo-password-dialog';
import LibOldFilesAutoDelDialog from '../../components/dialog/lib-old-files-auto-del-dialog';
import Rename from '../rename';
import { seafileAPI } from '../../utils/seafile-api';
import { userAPI } from '../../utils/user-api';
import LibHistorySettingDialog from '../dialog/lib-history-setting-dialog';
import toaster from '../toast';
import RepoAPITokenDialog from '../dialog/repo-api-token-dialog';
import RepoShareAdminDialog from '../dialog/repo-share-admin-dialog';
@@ -55,7 +53,6 @@ class SharedRepoListItem extends React.Component {
isRenaming: false,
isStarred: this.props.repo.starred,
isFolderPermissionDialogOpen: false,
isHistorySettingDialogShow: false,
isDeleteDialogShow: false,
isAPITokenDialogShow: false,
isTransferDialogShow: false,
@@ -63,7 +60,6 @@ class SharedRepoListItem extends React.Component {
isRepoDeleted: false,
isChangePasswordDialogShow: false,
isResetPasswordDialogShow: false,
isOldFilesAutoDelDialogOpen: false
};
this.isDeparementOnwerGroupMember = false;
}
@@ -182,9 +178,6 @@ class SharedRepoListItem extends React.Component {
case 'Unshare':
this.onItemUnshare();
break;
case 'History Setting':
this.onHistorySettingToggle();
break;
case 'API Token':
this.onAPITokenToggle();
break;
@@ -203,9 +196,6 @@ class SharedRepoListItem extends React.Component {
case 'Unwatch File Changes':
this.unwatchFileChanges();
break;
case 'Old Files Auto Delete':
this.toggleOldFilesAutoDelDialog();
break;
// no default
}
};
@@ -273,10 +263,6 @@ class SharedRepoListItem extends React.Component {
this.setState({ isFolderPermissionDialogOpen: !this.state.isFolderPermissionDialogOpen });
};
onHistorySettingToggle = () => {
this.setState({ isHistorySettingDialogShow: !this.state.isHistorySettingDialogShow });
};
onItemShare = () => {
this.setState({ isShowSharedDialog: true });
};
@@ -328,10 +314,6 @@ class SharedRepoListItem extends React.Component {
this.setState({ isRepoShareAdminDialogOpen: !this.state.isRepoShareAdminDialogOpen });
};
toggleOldFilesAutoDelDialog = () => {
this.setState({ isOldFilesAutoDelDialogOpen: !this.state.isOldFilesAutoDelDialogOpen });
};
onAPITokenToggle = () => {
this.setState({ isAPITokenDialogShow: !this.state.isAPITokenDialogShow });
};
@@ -362,9 +344,6 @@ class SharedRepoListItem extends React.Component {
case 'Share':
translateResult = gettext('Share');
break;
case 'History Setting':
translateResult = gettext('History Setting');
break;
case 'Share Admin':
translateResult = gettext('Share Admin');
break;
@@ -380,9 +359,6 @@ class SharedRepoListItem extends React.Component {
case 'Unwatch File Changes':
translateResult = gettext('Unwatch File Changes');
break;
case 'Old Files Auto Delete':
translateResult = gettext('Auto Deletion Setting');
break;
case 'API Token':
translateResult = 'API Token'; // translation is not needed here
break;
@@ -401,9 +377,6 @@ class SharedRepoListItem extends React.Component {
getAdvancedOperations = () => {
const operations = [];
operations.push('API Token');
if (enableRepoAutoDel) {
operations.push('Old Files Auto Delete');
}
return operations;
};
@@ -435,9 +408,8 @@ class SharedRepoListItem extends React.Component {
const monitorOp = repo.monitored ? 'Unwatch File Changes' : 'Watch File Changes';
operations.push(monitorOp);
}
operations.push('Divider', 'History Setting');
if (Utils.isDesktop()) {
operations.push('Advanced');
operations.push('Divider', 'Advanced');
}
return operations;
} else {
@@ -803,15 +775,6 @@ class SharedRepoListItem extends React.Component {
/>
</ModalPortal>
}
{this.state.isHistorySettingDialogShow && (
<ModalPortal>
<LibHistorySettingDialog
repoID={repo.repo_id}
itemName={repo.repo_name}
toggleDialog={this.onHistorySettingToggle}
/>
</ModalPortal>
)}
{this.state.isAPITokenDialogShow && (
<ModalPortal>
<RepoAPITokenDialog
@@ -845,14 +808,6 @@ class SharedRepoListItem extends React.Component {
/>
</ModalPortal>
)}
{this.state.isOldFilesAutoDelDialogOpen && (
<ModalPortal>
<LibOldFilesAutoDelDialog
repoID={repo.repo_id}
toggleDialog={this.toggleOldFilesAutoDelDialog}
/>
</ModalPortal>
)}
{this.state.isTransferDialogShow && (
<ModalPortal>
<TransferDialog