1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import { connect } from 'react-redux';
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';
24 type CssRules = "root" | "content";
26 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
31 // reserve space for the tab bar
32 height: `calc(100% - ${theme.spacing.unit * 7}px)`,
36 export enum GroupDetailsPanelMembersColumnNames {
38 USERNAME = "Username",
39 STATUS = "Account Status",
40 VISIBLE = "Visible to other members",
41 PERMISSION = "Permission",
45 export enum GroupDetailsPanelPermissionsColumnNames {
47 PERMISSION = "Permission",
52 const MEMBERS_DEFAULT_MESSAGE = 'Members list is empty.';
53 const PERMISSIONS_DEFAULT_MESSAGE = 'Permissions list is empty.';
55 export const groupDetailsMembersPanelColumns: DataColumns<string, PermissionResource> = [
57 name: GroupDetailsPanelMembersColumnNames.FULL_NAME,
60 filters: createTree(),
61 render: uuid => <ResourceLinkTail uuid={uuid} />
64 name: GroupDetailsPanelMembersColumnNames.USERNAME,
67 filters: createTree(),
68 render: uuid => <ResourceLinkTailUsername uuid={uuid} />
71 name: GroupDetailsPanelMembersColumnNames.STATUS,
74 filters: createTree(),
75 render: uuid => <ResourceLinkTailAccountStatus uuid={uuid} />
78 name: GroupDetailsPanelMembersColumnNames.VISIBLE,
81 filters: createTree(),
82 render: uuid => <ResourceLinkTailIsVisible uuid={uuid} />
85 name: GroupDetailsPanelMembersColumnNames.PERMISSION,
88 filters: createTree(),
89 render: uuid => <ResourceLinkTailPermissionLevel uuid={uuid} />
92 name: GroupDetailsPanelMembersColumnNames.REMOVE,
95 filters: createTree(),
96 render: uuid => <ResourceLinkDelete uuid={uuid} />
100 export const groupDetailsPermissionsPanelColumns: DataColumns<string, PermissionResource> = [
102 name: GroupDetailsPanelPermissionsColumnNames.NAME,
105 filters: createTree(),
106 render: uuid => <ResourceLinkHead uuid={uuid} />
109 name: GroupDetailsPanelPermissionsColumnNames.PERMISSION,
112 filters: createTree(),
113 render: uuid => <ResourceLinkHeadPermissionLevel uuid={uuid} />
116 name: GroupDetailsPanelPermissionsColumnNames.UUID,
119 filters: createTree(),
120 render: uuid => <ResourceLinkHeadUuid uuid={uuid} />
123 name: GroupDetailsPanelPermissionsColumnNames.REMOVE,
126 filters: createTree(),
127 render: uuid => <ResourceLinkDelete uuid={uuid} />
131 const mapStateToProps = (state: RootState) => {
132 const groupUuid = getCurrentGroupDetailsPanelUuid(state.properties);
133 const group = getResource<GroupResource>(groupUuid || '')(state.resources);
134 const userUuid = getUserUuid(state);
137 resources: state.resources,
138 groupCanManage: userUuid && !isBuiltinGroup(group?.uuid || '')
144 const mapDispatchToProps = {
145 onContextMenu: openContextMenu,
146 onAddUser: openAddGroupMembersDialog,
149 export interface GroupDetailsPanelProps {
150 onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
151 onAddUser: () => void;
152 resources: ResourcesState;
153 groupCanManage: boolean;
156 export const GroupDetailsPanel = withStyles(styles)(connect(
157 mapStateToProps, mapDispatchToProps
159 class GroupDetailsPanel extends React.Component<GroupDetailsPanelProps & WithStyles<CssRules>> {
164 componentDidMount() {
165 this.setState({ value: 0 });
169 const { value } = this.state;
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" />
176 <div className={this.props.classes.content}>
179 id={GROUP_DETAILS_MEMBERS_PANEL_ID}
180 data-cy="group-members-data-explorer"
182 onRowDoubleClick={noop}
184 contextMenuColumn={false}
185 defaultViewIcon={UserPanelIcon}
186 defaultViewMessages={[MEMBERS_DEFAULT_MESSAGE]}
190 this.props.groupCanManage &&
191 <Grid container justify='flex-end'>
193 data-cy="group-member-add"
196 onClick={this.props.onAddUser}>
207 id={GROUP_DETAILS_PERMISSIONS_PANEL_ID}
208 data-cy="group-permissions-data-explorer"
210 onRowDoubleClick={noop}
212 contextMenuColumn={false}
213 defaultViewIcon={KeyIcon}
214 defaultViewMessages={[PERMISSIONS_DEFAULT_MESSAGE]}
226 handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
227 this.setState({ value });