diff --git a/frontend/src/components/cur-repo-path/index.js b/frontend/src/components/cur-repo-path/index.js index e0469620ff..2c7f023d93 100644 --- a/frontend/src/components/cur-repo-path/index.js +++ b/frontend/src/components/cur-repo-path/index.js @@ -4,18 +4,18 @@ import RepoPath from './repo-path'; import RepoTool from './repo-tool'; const propTypes = { - currentTab: PropTypes.string.isRequired, + libraryType: PropTypes.string.isRequired, currentGroup: PropTypes.object, }; class CurGroupPath extends React.Component { render() { - let { currentTab, currentGroup } = this.props; + let { libraryType, currentGroup } = this.props; return ( - - + + ); } diff --git a/frontend/src/components/cur-repo-path/repo-path.js b/frontend/src/components/cur-repo-path/repo-path.js index 0d15095446..f19deceefd 100644 --- a/frontend/src/components/cur-repo-path/repo-path.js +++ b/frontend/src/components/cur-repo-path/repo-path.js @@ -4,14 +4,14 @@ import {gettext, siteRoot} from '../../utils/constants'; const propTypes = { currentGroup: PropTypes.object, // for group - currentTab: PropTypes.string.isRequired, //for my-library, shared width me, shared whith all, groups + libraryType: PropTypes.string.isRequired, //for my-library, shared width me, shared whith all, groups }; class RepoPath extends React.Component { render() { - let { currentTab, currentGroup } = this.props; - if (currentTab === 'group' && currentGroup) { + let { libraryType, currentGroup } = this.props; + if (libraryType === 'group' && currentGroup) { return (
{gettext("Groups")} @@ -26,7 +26,7 @@ class RepoPath extends React.Component { return (
- {currentTab} + {libraryType}
); } diff --git a/frontend/src/components/cur-repo-path/repo-tool.js b/frontend/src/components/cur-repo-path/repo-tool.js index 07ca1c42a7..0e3205946f 100644 --- a/frontend/src/components/cur-repo-path/repo-tool.js +++ b/frontend/src/components/cur-repo-path/repo-tool.js @@ -4,13 +4,13 @@ import { gettext, username } from '../../utils/constants'; const propTypes = { currentGroup: PropTypes.object, // for group - currentTab: PropTypes.string.isRequired, //for my-library, shared width me, shared whith all, groups + libraryType: PropTypes.string.isRequired, //for my-library, shared width me, shared whith all, groups }; class RepoTool extends React.Component { render() { - if (this.props.currentTab === 'group' && this.props.currentGroup) { + if (this.props.libraryType === 'group' && this.props.currentGroup) { let currentGroup = this.props.currentGroup; let isShowSettingIcon = !(currentGroup.parent_group_id !== 0 && currentGroup.admins.indexOf(username) === -1); return ( diff --git a/frontend/src/components/dialog/create-department-repo-dialog.js b/frontend/src/components/dialog/create-department-repo-dialog.js new file mode 100644 index 0000000000..b320cdae46 --- /dev/null +++ b/frontend/src/components/dialog/create-department-repo-dialog.js @@ -0,0 +1,106 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Col, FormText } from 'reactstrap'; +import { gettext, maxFileName } from '../../utils/constants'; + +const propTypes = { + onCreateRepo: PropTypes.func.isRequired, + onCreateToggle: PropTypes.func.isRequired +}; + +class CreateDepartmentRepoDialog extends React.Component { + constructor(props) { + super(props); + this.state = { + repoName: '', + errMessage: '', + }; + this.newInput = React.createRef(); + } + + handleChange = (e) => { + this.setState({ + repoName: e.target.value, + }); + } + + handleSubmit = () => { + let isValid = this.validateRepoName(); + if (isValid) { + let repo = this.createRepo(this.state.repoName); + this.props.onCreateRepo(repo); + } + + } + + handleKeyPress = (e) => { + if (e.key === 'Enter') { + this.handleSubmit(); + } + } + + toggle = () => { + this.props.onCreateToggle(); + } + + componentDidMount = () => { + this.newInput.focus(); + } + + validateRepoName = () => { + let errMessage = ''; + let repoName = this.state.repoName.trim(); + if (!repoName.length) { + errMessage = 'Name is required'; + this.setState({errMessage: errMessage}); + return false; + } + if (repoName.indexOf('/') > -1) { + errMessage = 'Name should not include \'/\'.'; + this.setState({errMessage: errMessage}); + return false; + } + if (repoName.length > maxFileName) { + errMessage = 'RepoName\'s length is must little than ' + maxFileName; + this.setState({errMessage: errMessage}); + return false; + } + return true; + } + + createRepo = (repoName) => { + let repo = { repo_name: repoName }; + return repo; + } + + render() { + return ( + + {gettext('New Department Library')} + +
+ + + {this.newInput = input;}} + value={this.state.repoName} + onChange={this.handleChange} + maxLength={maxFileName} + /> + +
+ +
+ + + +
+ ); + } +} + +CreateDepartmentRepoDialog.propTypes = propTypes; + +export default CreateDepartmentRepoDialog; diff --git a/frontend/src/components/share-repo-list-view/share-repo-list-item.js b/frontend/src/components/share-repo-list-view/share-repo-list-item.js index 1473acb60d..3f854fccc8 100644 --- a/frontend/src/components/share-repo-list-view/share-repo-list-item.js +++ b/frontend/src/components/share-repo-list-view/share-repo-list-item.js @@ -9,8 +9,8 @@ const propTypes = { currentGroup: PropTypes.object, repo: PropTypes.object.isRequired, isItemFreezed: PropTypes.bool.isRequired, - isShowRepoOwner: PropTypes.bool.isRequired, onFreezedItem: PropTypes.func.isRequired, + onItemUnshared: PropTypes.func.isRequired, }; class SharedRepoListItem extends React.Component { @@ -33,6 +33,15 @@ class SharedRepoListItem extends React.Component { }); } } + + onMouseOver = () => { + if (!this.props.isItemFreezed) { + this.setState({ + highlight: true, + isOperationShow: true, + }); + } + } onMouseLeave = () => { if (!this.props.isItemFreezed) { @@ -128,6 +137,7 @@ class SharedRepoListItem extends React.Component { onItemUnshared = () => { // todo + this.props.onItemUnshared(this.props.repo); } onItemDelete = () => { @@ -208,7 +218,7 @@ class SharedRepoListItem extends React.Component { // scene two: (share, unshare), (share), (unshare) let operations = this.generatorOperations(); const shareOperation = ; - const unshareOperation = + const unshareOperation = const deleteOperation = ; if (this.isDeparementOnwerGroupMember) { @@ -255,28 +265,28 @@ class SharedRepoListItem extends React.Component { renderPCUI = () => { let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams(); - let { repo, isShowRepoOwner } = this.props; + let { repo } = this.props; return ( - + {iconTitle} {repo.repo_name} {this.state.isOperationShow && this.generatorPCMenu()} {repo.size} {moment(repo.last_modified).fromNow()} - {isShowRepoOwner && {repo.owner_name}} + {repo.owner_name} ); } renderMobileUI = () => { let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams(); - let { repo, isShowRepoOwner } = this.props; + let { repo } = this.props; return ( - + {iconTitle}/ {repo.repo_name}
- {isShowRepoOwner ? {repo.owner_name} : null} + {repo.owner_name} {repo.size} {moment(repo.last_modified).fromNow()} diff --git a/frontend/src/components/share-repo-list-view/share-repo-list-view.js b/frontend/src/components/share-repo-list-view/share-repo-list-view.js index caa9104157..d0da0b4167 100644 --- a/frontend/src/components/share-repo-list-view/share-repo-list-view.js +++ b/frontend/src/components/share-repo-list-view/share-repo-list-view.js @@ -6,8 +6,8 @@ import ShareRepoListItem from './share-repo-list-item'; const propTypes = { currentGroup: PropTypes.object, repoList: PropTypes.array.isRequired, - isShowRepoOwner: PropTypes.bool.isRequired, isShowTableThread: PropTypes.bool, + onItemUnshared: PropTypes.func.isRequired, }; class ShareRepoListView extends React.Component { @@ -33,10 +33,10 @@ class ShareRepoListView extends React.Component { ); })} @@ -45,7 +45,6 @@ class ShareRepoListView extends React.Component { } renderPCUI = () => { - let isShowRepoOwner = this.props.isShowRepoOwner; let isShowTableThread = this.props.isShowTableThread !== undefined ? this.props.isShowTableThread : true; return ( @@ -56,11 +55,11 @@ class ShareRepoListView extends React.Component { {/*TODO: sort*/} - - + - {isShowRepoOwner && } + @@ -71,7 +70,6 @@ class ShareRepoListView extends React.Component { } renderMobileUI = () => { - let isShowRepoOwner = this.props.isShowRepoOwner; let isShowTableThread = this.props.isShowTableThread !== undefined ? this.props.isShowTableThread : true; return (
{gettext("Actions")}{gettext("Size")}{gettext("Last Update")} + {gettext("Size")}{gettext("Last Update")} {/*TODO: sort*/} {gettext("Owner")}{gettext("Owner")}
@@ -79,15 +77,11 @@ class ShareRepoListView extends React.Component { diff --git a/frontend/src/pages/groups/group-view.js b/frontend/src/pages/groups/group-view.js index 496a2013c4..c2bf04ed05 100644 --- a/frontend/src/pages/groups/group-view.js +++ b/frontend/src/pages/groups/group-view.js @@ -3,11 +3,13 @@ import PropTypes from 'prop-types'; import { gettext, username, loginUrl } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import Loading from '../../components/loading'; +import ModalPortal from '../../components/modal-portal'; import Group from '../../models/group'; import RepoInfo from '../../models/repoInfo'; import CommonToolbar from '../../components/toolbar/common-toolbar'; -import RepoViewToolbar from '../../components/toolbar/repo-view-toobar'; import CurRepoPath from '../../components/cur-repo-path/'; +import CreateRepoDialog from '../../components/dialog/create-repo-dialog'; +import CreateDepartmentRepoDialog from '../../components/dialog/create-department-repo-dialog'; import ShareRepoListView from '../../components/share-repo-list-view/share-repo-list-view'; const propTypes = { @@ -15,6 +17,8 @@ const propTypes = { onSearchedClick: PropTypes.func.isRequired, }; +const DEPARETMENT_GROUP_ONWER_NAME = 'system admin'; + class GroupView extends React.Component { constructor(props) { @@ -26,8 +30,9 @@ class GroupView extends React.Component { currentGroup: null, isStaff: false, repoList: [], - currentTab: 'group', - isShowRepoOwner: true, + libraryType: 'group', + isCreateRepoDialogShow: false, + isDepartmentGroup: false, } } @@ -47,10 +52,12 @@ class GroupView extends React.Component { let currentGroup = new Group(res.data); let emptyTip = this.getEmptyTip(currentGroup); let isStaff = currentGroup.admins.indexOf(username) > -1; //for item operations + let isDepartmentGroup = currentGroup.owner === DEPARETMENT_GROUP_ONWER_NAME; this.setState({ emptyTip: emptyTip, currentGroup: currentGroup, isStaff: isStaff, + isDepartmentGroup: isDepartmentGroup, }); this.loadRepos(groupID); }).catch((error) => { @@ -141,6 +148,10 @@ class GroupView extends React.Component { return emptyTip; } + onCreateRepoToggle = () => { + this.setState({isCreateRepoDialogShow: !this.state.isCreateRepoDialogShow}); + } + onCreateRepo = (repo) => { let groupId = this.props.groupID; seafileAPI.createGroupRepo(groupId, repo).then(res => { @@ -150,6 +161,7 @@ class GroupView extends React.Component { }).catch(() => { //todo }); + this.onCreateRepoToggle(); } addRepoItem = (repo) => { @@ -158,22 +170,36 @@ class GroupView extends React.Component { return newRepoList; } + onItemUnshared = (repo) => { + let group = this.state.currentGroup; + seafileAPI.unshareRepo(repo.repo_id, {share_type: 'group', group_id: group.id}).then(() => { + let repoList = this.state.repoList.filter(item => { + return item.repo_id !== repo.repo_id; + }); + this.setState({repoList: repoList}); + }); + } + render() { let { errMessage, emptyTip } = this.state; return (
- +
+ +
+ +
+
- +
{this.state.isLoading && } @@ -183,12 +209,29 @@ class GroupView extends React.Component { }
+ {this.state.isCreateRepoDialogShow && !this.state.isDepartmentGroup && ( + + + + )} + {this.state.isCreateRepoDialogShow && this.state.isDepartmentGroup && + + }
); } diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index e3c808ed31..e7acdb2347 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -27,6 +27,7 @@ export const storages = window.app.pageOptions.storages; // storage backends export const enableRepoSnapshotLabel = window.app.pageOptions.enableRepoSnapshotLabel; export const shareLinkExpireDaysMin = window.app.pageOptions.shareLinkExpireDaysMin; export const shareLinkExpireDaysMax = window.app.pageOptions.shareLinkExpireDaysMax; +export const maxFileName = window.app.pageOptions.maxFileName; // wiki export const slug = window.wiki ? window.wiki.config.slug : ''; diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index 7c52d81dd6..3aeb0fb049 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -61,6 +61,7 @@ enableRepoSnapshotLabel: {% if enable_repo_snapshot_label %} true {% else %} false {% endif %}, shareLinkExpireDaysMin: "{{ share_link_expire_days_min }}", shareLinkExpireDaysMax: "{{ share_link_expire_days_max }}", + maxFileName: "{{ max_file_name }}" } };
{gettext("Library Type")} - {isShowRepoOwner ? ( - - {gettext("Sort:")} {/* TODO: sort */} - {gettext("name")} - {gettext("last update")} - - ) : - (gettext('name')) - } + + {gettext("Sort:")} {/* TODO: sort */} + {gettext("name")} + {gettext("last update")} + {gettext("Actions")}