diff --git a/frontend/src/components/dialog/leave-share-table-dialog.js b/frontend/src/components/dialog/leave-share-table-dialog.js deleted file mode 100644 index 2f7398e03f..0000000000 --- a/frontend/src/components/dialog/leave-share-table-dialog.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { gettext } from '../../utils/constants'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; - -const propTypes = { - currentTable: PropTypes.object.isRequired, - leaveShareCancel: PropTypes.func.isRequired, - handleSubmit: PropTypes.func.isRequired, -}; - -class LeaveShareTableDialog extends React.Component { - - toggle = () => { - this.props.leaveShareCancel(); - }; - - render() { - let currentTable = this.props.currentTable; - let name = currentTable.name; - - return ( - - {gettext('Leave Share Table')} - -

{gettext('Are you sure to leave share')}{' '}{name} ?

-
- - - - -
- ); - } -} - -LeaveShareTableDialog.propTypes = propTypes; - -export default LeaveShareTableDialog; diff --git a/frontend/src/pages/dtable/dtable.js b/frontend/src/pages/dtable/dtable.js index a1163b260c..e42e249aa9 100644 --- a/frontend/src/pages/dtable/dtable.js +++ b/frontend/src/pages/dtable/dtable.js @@ -9,9 +9,10 @@ import CommonToolbar from '../../components/toolbar/common-toolbar'; import Loading from '../../components/loading'; import CreateTableDialog from '../../components/dialog/create-table-dialog'; import DeleteTableDialog from '../../components/dialog/delete-table-dialog'; -import LeaveShareTableDialog from '../../components/dialog/leave-share-table-dialog'; -import ShareTableDialog from '../../components/dialog/share-table-dialog' +import ShareTableDialog from '../../components/dialog/share-table-dialog'; +import ShareTableItem from './list-share-table'; import Rename from '../../components/rename'; + import '../../css/dtable-page.css'; moment.locale(window.app.config.lang); @@ -22,13 +23,10 @@ const tablePropTypes = { workspaceID: PropTypes.number.isRequired, renameTable: PropTypes.func.isRequired, deleteTable: PropTypes.func.isRequired, - leaveShareTable: PropTypes.func.isRequired, onUnfreezedItem: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired, isItemFreezed: PropTypes.bool.isRequired, - fromShare: PropTypes.bool.isRequired, - fromPersonal: PropTypes.bool.isRequired, - fromGroup: PropTypes.bool.isRequired, + isPersonal: PropTypes.bool.isRequired, }; class Table extends Component { @@ -39,7 +37,6 @@ class Table extends Component { isTableRenaming: false, isTableDeleting: false, isTableSharing: false, - isTableLeaveSharing: false, dropdownOpen: false, active: false, }; @@ -61,26 +58,15 @@ class Table extends Component { this.props.onUnfreezedItem(); } - onShareTableCancel = () => { - this.setState({isTableSharing: !this.state.isTableSharing}); - this.props.onUnfreezedItem(); - } - - onLeaveShareTableCancel = () => { - this.setState({isTableLeaveSharing: !this.state.isTableLeaveSharing}); - this.props.onUnfreezedItem(); - } - onDeleteTableSubmit = () => { let tableName = this.props.table.name; this.props.deleteTable(tableName); this.onDeleteTableCancel(); } - onLeaveShareTableSubmit = () => { - let tableName = this.props.table.name; - this.props.leaveShareTable(tableName); - this.onLeaveShareTableCancel(); + onShareTableCancel = () => { + this.setState({isTableSharing: !this.state.isTableSharing}); + this.props.onUnfreezedItem(); } dropdownToggle = () => { @@ -116,9 +102,6 @@ class Table extends Component { let table = this.props.table; let tableHref = siteRoot + 'workspace/' + this.props.workspaceID + '/dtable/' + table.name + '/'; - let fromShare = this.props.fromShare; - let fromPersonal = this.props.fromPersonal; - let fromGroup = this.props.fromGroup; return ( @@ -145,23 +128,16 @@ class Table extends Component { tag='i' className='fa fa-ellipsis-v cursor-pointer attr-action-icon' title={gettext('More Operations')} - data-toggle="dropdown" + data-toggle="dropdown" aria-expanded={this.state.dropdownOpen} > - {(fromPersonal || fromGroup) && {gettext('Rename')} - } - {(fromPersonal || fromGroup) && {gettext('Delete')} - } - {fromPersonal && + {this.props.isPersonal && {gettext('Share')} } - {fromShare && - {gettext('Leave Share')} - } } @@ -172,13 +148,6 @@ class Table extends Component { handleSubmit={this.onDeleteTableSubmit} /> } - {this.state.isTableLeaveSharing && - - } {this.state.isTableSharing && { this.setState({isItemFreezed: true}); } - + onUnfreezedItem = () => { this.setState({isItemFreezed: false}); } @@ -249,21 +217,6 @@ class Workspace extends Component { }); } - leaveShareTable = (tableName) => { - let email = username; - let workspaceID = this.props.workspace.id; - seafileAPI.deleteShareTable(workspaceID, tableName, email).then(() => { - let tableList = this.state.tableList.filter(table => { - return table.name !== tableName; - }); - this.setState({tableList: tableList}); - }).catch((error) => { - if(error.response) { - this.setState({errorMsg: gettext('Error')}); - } - }); - } - componentWillReceiveProps(nextProps) { if (nextProps.workspace.table_list !== this.props.workspace.table_list) { this.setState({ @@ -274,16 +227,11 @@ class Workspace extends Component { render() { let workspace = this.props.workspace; - let fromShare = this.props.fromShare; - let fromPersonal = !fromShare && workspace.owner_type === 'Personal'; - let fromGroup = !fromShare && workspace.owner_type === 'Group'; + let isPersonal = workspace.owner_type === 'Personal'; return(
- {fromPersonal ? -
{gettext('My Tables')}
: -
{workspace.owner_name}
- } +
{isPersonal ? gettext('My Tables') : workspace.owner_name}
@@ -297,13 +245,10 @@ class Workspace extends Component { workspaceID={workspace.id} renameTable={this.renameTable} deleteTable={this.deleteTable} - leaveShareTable={this.leaveShareTable} onFreezedItem={this.onFreezedItem} onUnfreezedItem={this.onUnfreezedItem} isItemFreezed={this.state.isItemFreezed} - fromShare={fromShare} - fromPersonal={fromPersonal} - fromGroup={fromGroup} + isPersonal={isPersonal} /> ); })} @@ -377,17 +322,37 @@ class DTable extends Component { seafileAPI.listShareTable().then((res) => { this.setState({ shareTableLoading: false, - shareTableList: res.data.share_list, + shareTableList: res.data.table_list, }); }).catch((error) => { if (error.response) { this.setState({ - loading: false, + shareTableLoading: false, errorMsg: gettext('Error') }); } else { this.setState({ - loading: false, + shareTableLoading: false, + errorMsg: gettext('Please check the network.') + }); + } + }); + }; + + leaveShareTable = (table) => { + let email = username; + let tableName = table.name; + let workspaceID = table.workspace_id; + seafileAPI.deleteShareTable(workspaceID, tableName, email).then(() => { + let shareTableList = this.state.shareTableList.filter(table => { + return table.name !== tableName; + }); + this.setState({shareTableList: shareTableList}); + }).catch((error) => { + if(error.response) { + this.setState({errorMsg: gettext('Error')}); + } else { + this.setState({ errorMsg: gettext('Please check the network.') }); } @@ -399,11 +364,34 @@ class DTable extends Component { this.listShareTable(); } + renderShareTablePanel = () => { + return ( +
+
{gettext('Shared with me')}
+
+ + + + + {this.state.shareTableList.map((table, index) => { + return ( + + ); + })} + +
+
+ ); + }; + render() { let personalWorkspace = this.state.workspaceList.filter(workspace => { return workspace.owner_type === 'Personal'; }).pop(); - let groupWorkspaceList = this.state.workspaceList.filter(workspace => { return workspace.owner_type === 'Group'; }); @@ -433,42 +421,26 @@ class DTable extends Component {
{this.state.loading && } - {(!this.state.loading && this.state.errorMsg) && + {(!this.state.loading && this.state.errorMsg) &&

{this.state.errorMsg}

} {!this.state.loading && } {(!this.state.shareTableLoading && this.state.shareTableList.length > 0) && - -
{gettext('Shared with me')}
- {this.state.shareTableList.map((workspace, index) => { - return ( - - );}) - } -
+ this.renderShareTablePanel() } - {(!this.state.loading && groupWorkspaceList.length > 0) && - -
{gettext('Shared with groups')}
- {groupWorkspaceList.map((workspace, index) => { + {!this.state.loading && + groupWorkspaceList.map((workspace, index) => { return ( ); - })} -
+ }) } {(!this.state.loading && this.state.isShowAddDTableDialog) &&
diff --git a/frontend/src/pages/dtable/list-share-table.js b/frontend/src/pages/dtable/list-share-table.js new file mode 100644 index 0000000000..b087ec5d30 --- /dev/null +++ b/frontend/src/pages/dtable/list-share-table.js @@ -0,0 +1,65 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import moment from 'moment'; +import {gettext, siteRoot} from '../../utils/constants'; + +import '../../css/dtable-page.css'; + + +const shareTableItemPropTypes = { + table: PropTypes.object.isRequired, + leaveShareTable: PropTypes.func.isRequired, +}; + +class ShareTableItem extends Component { + + constructor(props) { + super(props); + this.state = { + active: false, + }; + } + + onLeaveShareTableSubmit = () => { + let table = this.props.table; + this.props.leaveShareTable(table); + }; + + onMouseEnter = () => { + this.setState({ + active: true + }); + }; + + onMouseLeave = () => { + this.setState({ + active: false + }); + }; + + render() { + let table = this.props.table; + let tableHref = siteRoot + 'workspace/' + table.workspace_id + '/dtable/' + table.name + '/'; + + return ( + + + {table.name} + {table.from_user_name} + {moment(table.updated_at).fromNow()} + + + + + + ); + } +} + +ShareTableItem.propTypes = shareTableItemPropTypes; + +export default ShareTableItem; diff --git a/seahub/dtable/api.py b/seahub/dtable/api.py index 763ba28070..49fa7670e1 100644 --- a/seahub/dtable/api.py +++ b/seahub/dtable/api.py @@ -48,49 +48,29 @@ class ShareDTablesView(APIView): error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - share_list = list() - workspace_ids = set([item.dtable.workspace_id for item in share_queryset]) + table_list = list() - for workspace_id in workspace_ids: - dtable_share_queryset = share_queryset.filter(dtable__workspace_id=workspace_id) + for item in share_queryset: + from_user = item.from_user + permission = item.permission + dtable = item.dtable - workspace = dtable_share_queryset[0].dtable.workspace - if GROUP_DOMAIN in workspace.owner: - group_id = int(workspace.owner.split('@')[0]) - owner_name = group_id_to_name(group_id) - owner_type = "Group" - else: - owner_name = email2nickname(workspace.owner) - owner_type = "Personal" + dtable_info = dict() + dtable_info['id'] = dtable.pk + dtable_info['workspace_id'] = dtable.workspace_id + dtable_info['uuid'] = dtable.uuid + dtable_info['name'] = dtable.name + dtable_info['creator'] = email2nickname(dtable.creator) + dtable_info['modifier'] = email2nickname(dtable.modifier) + dtable_info['created_at'] = datetime_to_isoformat_timestr(dtable.created_at) + dtable_info['updated_at'] = datetime_to_isoformat_timestr(dtable.updated_at) + dtable_info['permission'] = permission + dtable_info['from_user'] = from_user + dtable_info['from_user_name'] = email2nickname(from_user) - workspace_info = workspace.to_dict() - workspace_info["owner_name"] = owner_name - workspace_info["owner_type"] = owner_type - workspace_info['table_list'] = list() + table_list.append(dtable_info) - for item in dtable_share_queryset: - from_user = item.from_user - permission = item.permission - dtable = item.dtable - - dtable_info = dict() - dtable_info['id'] = dtable.pk - dtable_info['workspace_id'] = dtable.workspace_id - dtable_info['uuid'] = dtable.uuid - dtable_info['name'] = dtable.name - dtable_info['creator'] = email2nickname(dtable.creator) - dtable_info['modifier'] = email2nickname(dtable.modifier) - dtable_info['created_at'] = datetime_to_isoformat_timestr(dtable.created_at) - dtable_info['updated_at'] = datetime_to_isoformat_timestr(dtable.updated_at) - dtable_info['permission'] = permission - dtable_info['from_user'] = from_user - dtable_info['from_user_name'] = email2nickname(from_user) - - workspace_info['table_list'].append(dtable_info) - - share_list.append(workspace_info) - - return Response({'share_list': share_list}) + return Response({'table_list': table_list}) class ShareDTableView(APIView): diff --git a/seahub/dtable/models.py b/seahub/dtable/models.py index a566475694..d1832d2e9a 100644 --- a/seahub/dtable/models.py +++ b/seahub/dtable/models.py @@ -158,7 +158,7 @@ class ShareDTableManager(models.Manager): return self.filter(dtable=dtable) def list_by_to_user(self, to_user): - return self.filter(to_user=to_user).select_related('dtable', 'dtable__workspace') + return self.filter(to_user=to_user).select_related('dtable') def get_by_dtable_and_to_user(self, dtable, to_user): qs = self.filter(dtable=dtable, to_user=to_user) diff --git a/tests/seahub/dtable/test_api.py b/tests/seahub/dtable/test_api.py index d3a2260b2a..3168002f39 100644 --- a/tests/seahub/dtable/test_api.py +++ b/tests/seahub/dtable/test_api.py @@ -46,24 +46,19 @@ class ShareDTablesViewTest(BaseTestCase): resp = self.client.get(self.url) self.assertEqual(200, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["share_list"] - assert json_resp["share_list"][0] - assert json_resp["share_list"][0]['owner_type'] == 'Personal' - assert json_resp["share_list"][0]['repo_id'] == self.repo.id - assert json_resp["share_list"][0]['id'] == self.workspace.id - assert json_resp["share_list"][0]['owner_name'] == email2nickname(self.user.username) - assert json_resp["share_list"][0]['table_list'] - assert json_resp["share_list"][0]['table_list'][0]['workspace_id'] == self.workspace.id - assert json_resp["share_list"][0]['table_list'][0]['uuid'] - assert json_resp["share_list"][0]['table_list'][0]['creator'] == email2nickname(self.user.username) - assert json_resp["share_list"][0]['table_list'][0]['created_at'] - assert json_resp["share_list"][0]['table_list'][0]['permission'] == 'rw' - assert json_resp["share_list"][0]['table_list'][0]['updated_at'] - assert json_resp["share_list"][0]['table_list'][0]['from_user'] == self.user.username - assert json_resp["share_list"][0]['table_list'][0]['from_user_name'] == email2nickname(self.user.username) - assert json_resp["share_list"][0]['table_list'][0]['modifier'] == email2nickname(self.user.username) - assert json_resp["share_list"][0]['table_list'][0]['id'] - assert json_resp["share_list"][0]['table_list'][0]['name'] == 'dtable1' + assert json_resp["table_list"] + assert json_resp["table_list"][0] + assert json_resp['table_list'][0]['workspace_id'] == self.workspace.id + assert json_resp['table_list'][0]['uuid'] + assert json_resp['table_list'][0]['creator'] == email2nickname(self.user.username) + assert json_resp['table_list'][0]['created_at'] + assert json_resp['table_list'][0]['permission'] == 'rw' + assert json_resp['table_list'][0]['updated_at'] + assert json_resp['table_list'][0]['from_user'] == self.user.username + assert json_resp['table_list'][0]['from_user_name'] == email2nickname(self.user.username) + assert json_resp['table_list'][0]['modifier'] == email2nickname(self.user.username) + assert json_resp['table_list'][0]['id'] + assert json_resp['table_list'][0]['name'] == 'dtable1' class ShareDTableViewTest(BaseTestCase):