Merge branch '21128-toolbar-context-menu'
[arvados-workbench2.git] / src / views / group-details-panel / group-details-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import { connect } from 'react-redux';
7
8 import { DataExplorer } from "views-components/data-explorer/data-explorer";
9 import { DataColumns } from 'components/data-table/data-table';
10 import { ResourceLinkHeadUuid, ResourceLinkTailUsername, ResourceLinkHeadPermissionLevel, ResourceLinkTailPermissionLevel, ResourceLinkHead, ResourceLinkTail, ResourceLinkDelete, ResourceLinkTailAccountStatus, ResourceLinkTailIsVisible } from 'views-components/data-explorer/renderers';
11 import { createTree } from 'models/tree';
12 import { noop } from 'lodash/fp';
13 import { RootState } from 'store/store';
14 import { GROUP_DETAILS_MEMBERS_PANEL_ID, GROUP_DETAILS_PERMISSIONS_PANEL_ID, openAddGroupMembersDialog, getCurrentGroupDetailsPanelUuid } from 'store/group-details-panel/group-details-panel-actions';
15 import { openContextMenu } from 'store/context-menu/context-menu-actions';
16 import { ResourcesState, getResource } from 'store/resources/resources';
17 import { Grid, Button, Tabs, Tab, Paper, WithStyles, withStyles, StyleRulesCallback } from '@material-ui/core';
18 import { AddIcon, UserPanelIcon, KeyIcon } from 'components/icon/icon';
19 import { getUserUuid } from 'common/getuser';
20 import { GroupResource, isBuiltinGroup } from 'models/group';
21 import { ArvadosTheme } from 'common/custom-theme';
22 import { PermissionResource } from 'models/permission';
23
24 type CssRules = "root" | "content";
25
26 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
27     root: {
28         width: '100%',
29     },
30     content: {
31         // reserve space for the tab bar
32         height: `calc(100% - ${theme.spacing.unit * 7}px)`,
33     }
34 });
35
36 export enum GroupDetailsPanelMembersColumnNames {
37     FULL_NAME = "Name",
38     USERNAME = "Username",
39     STATUS = "Account Status",
40     VISIBLE = "Visible to other members",
41     PERMISSION = "Permission",
42     REMOVE = "Remove",
43 }
44
45 export enum GroupDetailsPanelPermissionsColumnNames {
46     NAME = "Name",
47     PERMISSION = "Permission",
48     UUID = "UUID",
49     REMOVE = "Remove",
50 }
51
52 const MEMBERS_DEFAULT_MESSAGE = 'Members list is empty.';
53 const PERMISSIONS_DEFAULT_MESSAGE = 'Permissions list is empty.';
54
55 export const groupDetailsMembersPanelColumns: DataColumns<string, PermissionResource> = [
56     {
57         name: GroupDetailsPanelMembersColumnNames.FULL_NAME,
58         selected: true,
59         configurable: true,
60         filters: createTree(),
61         render: uuid => <ResourceLinkTail uuid={uuid} />
62     },
63     {
64         name: GroupDetailsPanelMembersColumnNames.USERNAME,
65         selected: true,
66         configurable: true,
67         filters: createTree(),
68         render: uuid => <ResourceLinkTailUsername uuid={uuid} />
69     },
70     {
71         name: GroupDetailsPanelMembersColumnNames.STATUS,
72         selected: true,
73         configurable: true,
74         filters: createTree(),
75         render: uuid => <ResourceLinkTailAccountStatus uuid={uuid} />
76     },
77     {
78         name: GroupDetailsPanelMembersColumnNames.VISIBLE,
79         selected: true,
80         configurable: true,
81         filters: createTree(),
82         render: uuid => <ResourceLinkTailIsVisible uuid={uuid} />
83     },
84     {
85         name: GroupDetailsPanelMembersColumnNames.PERMISSION,
86         selected: true,
87         configurable: true,
88         filters: createTree(),
89         render: uuid => <ResourceLinkTailPermissionLevel uuid={uuid} />
90     },
91     {
92         name: GroupDetailsPanelMembersColumnNames.REMOVE,
93         selected: true,
94         configurable: true,
95         filters: createTree(),
96         render: uuid => <ResourceLinkDelete uuid={uuid} />
97     },
98 ];
99
100 export const groupDetailsPermissionsPanelColumns: DataColumns<string, PermissionResource> = [
101     {
102         name: GroupDetailsPanelPermissionsColumnNames.NAME,
103         selected: true,
104         configurable: true,
105         filters: createTree(),
106         render: uuid => <ResourceLinkHead uuid={uuid} />
107     },
108     {
109         name: GroupDetailsPanelPermissionsColumnNames.PERMISSION,
110         selected: true,
111         configurable: true,
112         filters: createTree(),
113         render: uuid => <ResourceLinkHeadPermissionLevel uuid={uuid} />
114     },
115     {
116         name: GroupDetailsPanelPermissionsColumnNames.UUID,
117         selected: true,
118         configurable: true,
119         filters: createTree(),
120         render: uuid => <ResourceLinkHeadUuid uuid={uuid} />
121     },
122     {
123         name: GroupDetailsPanelPermissionsColumnNames.REMOVE,
124         selected: true,
125         configurable: true,
126         filters: createTree(),
127         render: uuid => <ResourceLinkDelete uuid={uuid} />
128     },
129 ];
130
131 const mapStateToProps = (state: RootState) => {
132     const groupUuid = getCurrentGroupDetailsPanelUuid(state.properties);
133     const group = getResource<GroupResource>(groupUuid || '')(state.resources);
134     const userUuid = getUserUuid(state);
135
136     return {
137         resources: state.resources,
138         groupCanManage: userUuid && !isBuiltinGroup(group?.uuid || '')
139             ? group?.canManage
140             : false,
141     };
142 };
143
144 const mapDispatchToProps = {
145     onContextMenu: openContextMenu,
146     onAddUser: openAddGroupMembersDialog,
147 };
148
149 export interface GroupDetailsPanelProps {
150     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
151     onAddUser: () => void;
152     resources: ResourcesState;
153     groupCanManage: boolean;
154 }
155
156 export const GroupDetailsPanel = withStyles(styles)(connect(
157     mapStateToProps, mapDispatchToProps
158 )(
159     class GroupDetailsPanel extends React.Component<GroupDetailsPanelProps & WithStyles<CssRules>> {
160         state = {
161             value: 0,
162         };
163
164         componentDidMount() {
165             this.setState({ value: 0 });
166         }
167
168         render() {
169             const { value } = this.state;
170             return (
171                 <Paper className={this.props.classes.root}>
172                     <Tabs value={value} onChange={this.handleChange} variant="fullWidth">
173                         <Tab data-cy="group-details-members-tab" label="MEMBERS" />
174                         <Tab data-cy="group-details-permissions-tab" label="PERMISSIONS" />
175                     </Tabs>
176                     <div className={this.props.classes.content}>
177                         {value === 0 &&
178                             <DataExplorer
179                                 id={GROUP_DETAILS_MEMBERS_PANEL_ID}
180                                 data-cy="group-members-data-explorer"
181                                 onRowClick={noop}
182                                 onRowDoubleClick={noop}
183                                 onContextMenu={noop}
184                                 contextMenuColumn={false}
185                                 defaultViewIcon={UserPanelIcon}
186                                 defaultViewMessages={[MEMBERS_DEFAULT_MESSAGE]}
187                                 hideColumnSelector
188                                 hideSearchInput
189                                 actions={
190                                     this.props.groupCanManage &&
191                                     <Grid container justify='flex-end'>
192                                         <Button
193                                             data-cy="group-member-add"
194                                             variant="contained"
195                                             color="primary"
196                                             onClick={this.props.onAddUser}>
197                                             <AddIcon /> Add user
198                                         </Button>
199                                     </Grid>
200                                 }
201                                 paperProps={{
202                                     elevation: 0,
203                                 }} />
204                         }
205                         {value === 1 &&
206                             <DataExplorer
207                                 id={GROUP_DETAILS_PERMISSIONS_PANEL_ID}
208                                 data-cy="group-permissions-data-explorer"
209                                 onRowClick={noop}
210                                 onRowDoubleClick={noop}
211                                 onContextMenu={noop}
212                                 contextMenuColumn={false}
213                                 defaultViewIcon={KeyIcon}
214                                 defaultViewMessages={[PERMISSIONS_DEFAULT_MESSAGE]}
215                                 hideColumnSelector
216                                 hideSearchInput
217                                 paperProps={{
218                                     elevation: 0,
219                                 }} />
220                         }
221                     </div>
222                 </Paper>
223             );
224         }
225
226         handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
227             this.setState({ value });
228         }
229     }));