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