diff --git a/frontend/src/app.js b/frontend/src/app.js index 45d03eae4c..e7c2c410de 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -18,8 +18,8 @@ import ShareAdminUploadLinks from './pages/share-admin/upload-links'; import SharedLibraries from './pages/shared-libs/shared-libs'; import MyLibraries from './pages/my-libs/my-libs'; import DirView from './components/dir-view/dir-view'; -import Groups from './pages/group/groups'; -import Group from './pages/group/group'; +import Group from './pages/groups/group-view'; +import Groups from './pages/groups/groups-view'; import MainContentWrapper from './components/main-content-wrapper'; import './assets/css/fa-solid.css'; diff --git a/frontend/src/pages/group/group-repo-item.js b/frontend/src/pages/group/group-repo-item.js deleted file mode 100644 index 8f81b4288f..0000000000 --- a/frontend/src/pages/group/group-repo-item.js +++ /dev/null @@ -1,270 +0,0 @@ -import React, { Component } from 'react'; -import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap'; -import moment from 'moment'; -import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; -import { gettext, siteRoot, loginUrl, isPro, folderPermEnabled, username } from '../../utils/constants'; - -class GroupRepoItem extends Component { - - constructor(props) { - super(props); - this.state = { - showOpIcon: false, - operationMenuOpen: false, - unshared: false - }; - - this.handleMouseOver = this.handleMouseOver.bind(this); - this.handleMouseOut = this.handleMouseOut.bind(this); - this.toggleOperationMenu = this.toggleOperationMenu.bind(this); - this.clickOperationMenuToggle = this.clickOperationMenuToggle.bind(this); - - this.share = this.share.bind(this); - this.unshare = this.unshare.bind(this); - - this.deleteItem = this.deleteItem.bind(this); - - this.rename = this.rename.bind(this); - this.folderPerm = this.folderPerm.bind(this); - this.showDetails = this.showDetails.bind(this); - } - - handleMouseOver() { - this.setState({ - showOpIcon: true - }); - } - - handleMouseOut() { - this.setState({ - showOpIcon: false - }); - } - - toggleOperationMenu() { - this.setState({ - operationMenuOpen: !this.state.operationMenuOpen - }); - } - - clickOperationMenuToggle(e) { - e.preventDefault(); - this.toggleOperationMenu(); - } - - share(e) { - e.preventDefault(); - // TODO - } - - unshare(e) { - e.preventDefault(); - // TODO - - const data = this.props.data; - - let request; - if (data.owner_email.indexOf('@seafile_group') == -1) { - let options = { - 'share_type': 'personal', - 'from': data.owner_email - }; - request = seafileAPI.leaveShareRepo(data.repo_id, options); - } else { - request = seafileAPI.leaveShareGroupOwnedRepo(data.repo_id); - } - - request.then((res) => { - this.setState({ - unshared: true - }); - // TODO: show feedback msg - }).catch((error) => { - // TODO: show feedback msg - }); - } - - deleteItem() { - // TODO - const data = this.props.data; - seafileAPI.deleteRepo(data.repo_id).then((res) => { - this.setState({ - deleted: true - }); - // TODO: show feedback msg - }).catch((error) => { - // TODO: show feedback msg - }); - } - - rename() { - } - - folderPerm() { - } - - showDetails() { - } - - render() { - - if (this.state.unshared) { - return null; - } - - const data = this.props.data; - const permission = data.permission; - - const {groupId, isStaff, showRepoOwner} = this.props.extra; - const isRepoOwner = username == data.owner_email; - const isAdmin = data.is_admin; - - let is_readonly = false; - if (permission == 'r' || permission == 'preview') { - is_readonly = true; - } - data.icon_url = Utils.getLibIconUrl({ - is_encrypted: data.encrypted, - is_readonly: is_readonly, - size: Utils.isHiDPI() ? 48 : 24 - }); - data.icon_title = Utils.getLibIconTitle({ - 'encrypted': data.encrypted, - 'is_admin': data.is_admin, - 'permission': permission - }); - data.url = `${siteRoot}#group/${groupId}/lib/${data.repo_id}/`; - - let iconVisibility = this.state.showOpIcon ? '' : ' invisible'; - let shareIconClassName = 'sf2-icon-share sf2-x repo-share-btn op-icon' + iconVisibility; - let unshareIconClassName = 'sf2-icon-x3 sf2-x op-icon' + iconVisibility; - let deleteIconClassName = 'sf2-icon-delete sf2-x op-icon' + iconVisibility; - let operationMenuToggleIconClassName = 'sf2-icon-caret-down item-operation-menu-toggle-icon op-icon'; - if (window.innerWidth >= 768) { - operationMenuToggleIconClassName += iconVisibility; - } - - const commonToggle = ( - - - ); - - const commonOperationsInMenu = ( - - {gettext('Rename')} - {folderPermEnabled ? {gettext('Folder Permission')} : null} - {gettext('Details')} - - ); - - let desktopOperations; - let mobileOperationMenu; - - const share = ; - const unshare = - - const shareDropdownItem = {gettext('Share')}; - const unshareDropdownItem = {gettext('Unshare')}; - - if (isPro) { - if (data.owner_email.indexOf('@seafile_group') != -1) { // group owned repo - if (isStaff) { - if (data.owner_email == groupId + '@seafile_group') { // this repo belongs to the current group - desktopOperations = ( - - {share} - - - {commonToggle} - - {commonOperationsInMenu} - - - - ); - mobileOperationMenu = ( - - {shareDropdownItem} - {gettext('Delete')} - {commonOperationsInMenu} - - ); - } else { - desktopOperations = unshare; - mobileOperationMenu = unshareDropdownItem; - } - } - } else { - desktopOperations = ( - - {isRepoOwner || isAdmin ? share : null} - {isStaff || isRepoOwner || isAdmin ? unshare : null} - - ); - mobileOperationMenu = ( - - {isRepoOwner || isAdmin ? shareDropdownItem : null} - {isStaff || isRepoOwner || isAdmin ? unshareDropdownItem : null} - - ); - } - } else { - desktopOperations = ( - - {isRepoOwner ? share : null} - {isStaff || isRepoOwner ? unshare : null} - - ); - mobileOperationMenu = ( - - {isRepoOwner ? shareDropdownItem : null} - {isStaff || isRepoOwner ? unshareDropdownItem : null} - - ); - } - - const mobileOperations = ( - - {commonToggle} -
-
-
- {mobileOperationMenu} -
-
-
- ); - - const desktopItem = ( - - {data.icon_title} - {data.repo_name} - {desktopOperations} - {Utils.formatSize({bytes: data.size})} - {moment(data.last_modified).fromNow()} - {showRepoOwner ? {data.owner_name} : null} - - ); - - const mobileItem = ( - - {data.icon_title} - - {data.repo_name}
- {showRepoOwner ? {data.owner_name} : null} - {Utils.formatSize({bytes: data.size})} - {moment(data.last_modified).fromNow()} - - {mobileOperations} - - ); - - return window.innerWidth >= 768 ? desktopItem : mobileItem; - } -} - -export default GroupRepoItem; diff --git a/frontend/src/pages/group/group.js b/frontend/src/pages/group/group.js deleted file mode 100644 index 74a78e15a1..0000000000 --- a/frontend/src/pages/group/group.js +++ /dev/null @@ -1,305 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; -import { gettext, siteRoot, loginUrl, username } from '../../utils/constants'; -import Loading from '../../components/loading'; -import GroupRepoItem from './group-repo-item'; -import CommonToolbar from '../../components/toolbar/common-toolbar'; -import RepoViewToolbar from '../../components/toolbar/repo-view-toobar'; - -import '../../css/groups.css'; - -class Header extends Component { - - render() { - const {loading, errorMsg, data} = this.props.data; - - if (loading) { - return ; - } else if (errorMsg) { - return

{errorMsg}

; - } else { - /* - admins: ["lj@1.com"] - avatar_url: "http://127.0.0.1:8000/media/avatars/groups/default.png" - created_at: "2018-10-25T08:18:11+00:00" - id: 2 - name: "g1" - owner: "lj@1.com" - parent_group_id: 0 - wiki_enabled: false - */ - const path = ( -
- {gettext("Groups")} - / - {data.name} - {data.parent_group_id == 0 ? null : - - } -
- ); - - let showSettingsIcon = true; - if (data.parent_group_id != 0 && data.admins.indexOf(username) == -1) { - showSettingsIcon = false; - } - - // TODO: click icon - const toolbar = ( -
- {showSettingsIcon ? : null} - -
- ); - - return ( - - {path} - {toolbar} - - ); - } - } -} - -class Content extends Component { - - render() { - const {loading, errorMsg, items} = this.props.data.repos; - - if (loading) { - return ; - } else if (errorMsg) { - return

{errorMsg}

; - } else { - if (!items) { - return null; - } - - const groupInfo = this.props.data.groupMetaInfo.data; - - let emptyTip; - if (groupInfo.parent_group_id == 0) { - emptyTip = ( -
-

{gettext('No library is shared to this group')}

-

{gettext('You can share libraries by clicking the "New Library" button above or the "Share" icon on your libraries list.')}

-

{gettext('Libraries shared as writable can be downloaded and synced by other group members. Read only libraries can only be downloaded, updates by others will not be uploaded.')}

-
- ); - } else { - if (groupInfo.admins.indexOf(username) == -1) { - emptyTip = ( -
-

{gettext('No libraries')}

-
- ); - } else { - emptyTip = ( -
-

{gettext('No libraries')}

-

{gettext('You can create libraries by clicking the "New Library" button above.')}

-
- ); - } - } - - const desktopThead = ( - - - {gettext("Library Type")} - {gettext("Name")}{/*TODO: sort*/} - {gettext("Actions")} - {gettext("Size")} - {gettext("Last Update")}{/*TODO: sort*/} - {gettext("Owner")} - - - ); - - const mobileThead = ( - - - {gettext("Library Type")} - - {gettext("Sort:")} {/* TODO: sort */} - {gettext("name")} - {gettext("last update")} - - {gettext("Actions")} - - - ); - - const extraData = { - groupId: groupInfo.id, - isStaff: groupInfo.admins.indexOf(username) != -1, - showRepoOwner: true - }; - - const table = ( - - {window.innerWidth >= 768 ? desktopThead : mobileThead} - -
- ); - - return items.length ? table : emptyTip; - } - } -} - -class TableBody extends Component { - - constructor(props) { - super(props); - this.state = { - items: this.props.items - }; - } - - render() { - - let listItems = this.state.items.map(function(item, index) { - return ; - }, this); - - return ( - {listItems} - ); - } -} - -class Group extends Component { - constructor(props) { - super(props); - this.state = { - groupMetaInfo: { - loading: true, - errorMsg: '' - }, - repos: { - loading: false, - errorMsg: '' - } - }; - } - - componentDidMount() { - this.updateGroupRepoList(this.props.groupID); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.groupID !== this.props.groupID) { - this.updateGroupRepoList(nextProps.groupID); - } - } - - updateGroupRepoList = (groupID) => { - seafileAPI.getGroup(groupID).then((res) => { - // res: {data: {...}, status: 200, statusText: "OK", headers: {…}, config: {…}, …} - this.setState({ - groupMetaInfo: { - loading: false, - data: res.data - } - }); - this.listGroupRepos(); - }).catch((error) => { - if (error.response) { - if (error.response.status == 403) { - this.setState({ - groupMetaInfo: { - loading: false, - errorMsg: gettext("Permission denied") - } - }); - location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`; - } else { - this.setState({ - groupMetaInfo: { - loading: false, - errorMsg: gettext("Error") - } - }); - } - } else { - this.setState({ - groupMetaInfo: { - loading: false, - errorMsg: gettext("Please check the network.") - } - }); - } - }); - } - - listGroupRepos() { - seafileAPI.listGroupRepos(this.props.groupID).then((res) => { - // res: {data: [...], status: 200, statusText: "OK", headers: {…}, config: {…}, …} - this.setState({ - repos: { - loading: false, - items: res.data - } - }); - }).catch((error) => { - if (error.response) { - if (error.response.status == 403) { - this.setState({ - repos: { - loading: false, - errorMsg: gettext("Permission denied") - } - }); - location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`; - } else { - this.setState({ - repos: { - loading: false, - errorMsg: gettext("Error") - } - }); - } - } else { - this.setState({ - repos: { - loading: false, - errorMsg: gettext("Please check the network.") - } - }); - } - }); - } - - onCreateRepo = (repo) => { - let groupId = this.props.groupID; - seafileAPI.createGroupRepo(groupId, repo).then(() => { - //todo update group list - }); - } - - render() { - return ( - -
- - -
-
-
-
-
-
-
- -
-
-
-
- ); - } -} - -export default Group; diff --git a/frontend/src/pages/group/groups.js b/frontend/src/pages/group/groups.js deleted file mode 100644 index e12873c1b2..0000000000 --- a/frontend/src/pages/group/groups.js +++ /dev/null @@ -1,178 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { seafileAPI } from '../../utils/seafile-api'; -import { gettext, siteRoot, loginUrl, username } from '../../utils/constants'; -import Loading from '../../components/loading'; -import GroupRepoItem from './group-repo-item'; -import GeneralToolbar from '../../components/toolbar/general-toolbar'; - -import '../../css/groups.css'; - -class Content extends Component { - - render() { - const {loading, errorMsg, items} = this.props.data; - - if (loading) { - return ; - } else if (errorMsg) { - return

{errorMsg}

; - } else { - /* TODO: - {% if user.permissions.can_add_group %} -

{% blocktrans %}Groups allow multiple people to collaborate on libraries. You can create a group by clicking the "New Group" button.{% endblocktrans %}

- {% else %} -

{% trans "Groups allow multiple people to collaborate on libraries. Groups you join will be listed here." %}

- {% endif %} - */ - const emptyTip = ( -
-

{gettext('You are not in any groups')}

-

{gettext('Groups allow multiple people to collaborate on libraries.')}

-
- ); - - let listItems = items.map(function(item, index) { - return ; - }, this); - - const groupItems = ( - - {listItems} - - ); - - return items.length ? groupItems : emptyTip; - } - } -} - -class GroupItem extends Component { - - render() { - - const data = this.props.data; - - const desktopThead = ( - - - {gettext("Library Type")} - {gettext("Name")} - {gettext("Actions")} - {gettext("Size")} - {gettext("Last Update")} - - - ); - - const mobileThead = ( - - - {gettext("Library Type")} - {gettext("name")} - {gettext("Actions")} - - - ); - - const extraData = { - groupId: data.id, - isStaff: data.admins.indexOf(username) != -1, - showRepoOwner: false - }; - - const table = ( - - {window.innerWidth >= 768 ? desktopThead : mobileThead} - -
- ); - - const emptyTip =

{gettext('No libraries')}

; - - const item = ( - -

{data.name}

- {data.repos.length ? table : emptyTip} -
- ); - - return item; - } -} - -class TableBody extends Component { - - render() { - - let listItems = this.props.items.map(function(item, index) { - return ; - }, this); - - return ( - {listItems} - ); - } -} - -class Groups extends Component { - constructor(props) { - super(props); - this.state = { - loading: true, - errorMsg: '', - items: [] - }; - } - - componentDidMount() { - seafileAPI.listGroupsV2({'with_repos': 1}).then((res) => { // TODO: api name - // `{'with_repos': 1}`: list repos of every group - // res: {data: [...], status: 200, statusText: "OK", headers: {…}, config: {…}, …} - this.setState({ - loading: false, - items: res.data - }); - }).catch((error) => { - if (error.response) { - if (error.response.status == 403) { - this.setState({ - loading: false, - errorMsg: gettext("Permission denied") - }); - location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`; - } else { - this.setState({ - loading: false, - errorMsg: gettext("Error") - }); - } - - } else { - this.setState({ - loading: false, - errorMsg: gettext("Please check the network.") - }); - } - }); - } - - render() { - return ( - - -
-
-
-

{gettext("My Groups")}

-
-
- -
-
-
-
- ); - } -} - -export default Groups;