Merge branch '18123-group-edit-page-rebase1' into main. Closes #18123
authorStephen Smith <stephen@curii.com>
Thu, 16 Dec 2021 17:27:26 +0000 (12:27 -0500)
committerStephen Smith <stephen@curii.com>
Thu, 16 Dec 2021 17:27:26 +0000 (12:27 -0500)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

1  2 
src/components/data-explorer/data-explorer.tsx
src/components/icon/icon.tsx
src/views/group-details-panel/group-details-panel.tsx
src/views/groups-panel/groups-panel.tsx
src/views/workbench/workbench.tsx

index 05125f12c7311b8a4fe700a7dd61923ce6e682c8,928d3ed4867e68388ed1a416e25b51f4018a1c31..55840ae9fd52a752f8b90e73c1f3cc06370c19b9
@@@ -106,22 -94,19 +106,23 @@@ export const DataExplorer = withStyles(
                  rowsPerPage, rowsPerPageOptions, onColumnToggle, searchLabel, searchValue, onSearch,
                  items, itemsAvailable, onRowClick, onRowDoubleClick, classes,
                  dataTableDefaultView, hideColumnSelector, actions, paperProps, hideSearchInput,
 -                paperKey, fetchMode, currentItemUuid, title
 +                paperKey, fetchMode, currentItemUuid, title,
 +                doHidePanel, doMaximizePanel, panelName, panelMaximized
              } = this.props;
-             return <Paper className={classes.root} {...paperProps} key={paperKey}>
 +
 -                {title && <div className={classes.title}>{title}</div>}
 -                {(!hideColumnSelector || !hideSearchInput || !!actions) && <Toolbar className={title ? classes.toolbarUnderTitle : classes.toolbar}>
+             const dataCy = this.props["data-cy"];
+             return <Paper className={classes.root} {...paperProps} key={paperKey} data-cy={dataCy}>
-                 {(!hideColumnSelector || !hideSearchInput) && <Grid item xs><Toolbar className={title ? classes.toolbarUnderTitle : classes.toolbar}>
 +                <Grid container direction="column" wrap="nowrap" className={classes.container}>
 +                {title && <Grid item xs className={classes.title}>{title}</Grid>}
++                {(!hideColumnSelector || !hideSearchInput || !!actions) && <Grid item xs><Toolbar className={title ? classes.toolbarUnderTitle : classes.toolbar}>
                      <Grid container justify="space-between" wrap="nowrap" alignItems="center">
-                         <div className={classes.searchBox}>
+                         {!hideSearchInput && <div className={classes.searchBox}>
                              {!hideSearchInput && <SearchInput
                                  label={searchLabel}
                                  value={searchValue}
 +                                selfClearProp={currentItemUuid}
                                  onSearch={onSearch} />}
-                         </div>
+                         </div>}
                          {actions}
                          {!hideColumnSelector && <ColumnSelector
                              columns={columns}
index 523eefbd10c7b75bb0e6904f59a1abf62555f563,4543d8d9a688cb148aff742d8c75e9736970a168..15a9f02d7339ab9c05411135d00d8190f06a0a92
@@@ -59,15 -59,14 +59,17 @@@ import SettingsEthernet from '@material
  import Star from '@material-ui/icons/Star';
  import StarBorder from '@material-ui/icons/StarBorder';
  import Warning from '@material-ui/icons/Warning';
 +import Visibility from '@material-ui/icons/Visibility';
 +import VisibilityOff from '@material-ui/icons/VisibilityOff';
  import VpnKey from '@material-ui/icons/VpnKey';
  import LinkOutlined from '@material-ui/icons/LinkOutlined';
+ import RemoveRedEye from '@material-ui/icons/RemoveRedEye';
+ import Computer from '@material-ui/icons/Computer';
  
  // Import FontAwesome icons
  import { library } from '@fortawesome/fontawesome-svg-core';
- import { faPencilAlt, faSlash } from '@fortawesome/free-solid-svg-icons';
+ import { faPencilAlt, faSlash, faUsers } from '@fortawesome/free-solid-svg-icons';
 +import { CropFreeSharp } from '@material-ui/icons';
  library.add(
      faPencilAlt,
      faSlash,
index d0f7973675acbd7e92d852215db35efe1b81d8a7,e47ff8c0cc114eef30147b75ffa434b366a12398..ce3f34c75348d39c4dbd1ee63df9b2e06a70d73c
@@@ -11,25 -11,33 +11,42 @@@ import { ResourceLinkHeadUuid, Resource
  import { createTree } from 'models/tree';
  import { noop } from 'lodash/fp';
  import { RootState } from 'store/store';
- import { GROUP_DETAILS_PANEL_ID, openAddGroupMembersDialog } from 'store/group-details-panel/group-details-panel-actions';
+ import { GROUP_DETAILS_MEMBERS_PANEL_ID, GROUP_DETAILS_PERMISSIONS_PANEL_ID, openAddGroupMembersDialog, getCurrentGroupDetailsPanelUuid } from 'store/group-details-panel/group-details-panel-actions';
  import { openContextMenu } from 'store/context-menu/context-menu-actions';
  import { ResourcesState, getResource } from 'store/resources/resources';
- import { ContextMenuKind } from 'views-components/context-menu/context-menu';
- import { PermissionResource } from 'models/permission';
- import { Grid, Button } from '@material-ui/core';
 -import { Grid, Button, Tabs, Tab, Paper } from '@material-ui/core';
++import { Grid, Button, Tabs, Tab, Paper, WithStyles, withStyles, StyleRulesCallback } from '@material-ui/core';
  import { AddIcon } from 'components/icon/icon';
- export enum GroupDetailsPanelColumnNames {
-     FIRST_NAME = "First name",
-     LAST_NAME = "Last name",
-     UUID = "UUID",
-     EMAIL = "Email",
+ import { getUserUuid } from 'common/getuser';
+ import { GroupResource, isBuiltinGroup } from 'models/group';
++import { ArvadosTheme } from 'common/custom-theme';
 +
++type CssRules = "root";
++
++const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
++    root: {
++        width: '100%',
++    }
++});
+ export enum GroupDetailsPanelMembersColumnNames {
+     FULL_NAME = "Name",
      USERNAME = "Username",
+     ACTIVE = "User Active",
+     VISIBLE = "Visible to other members",
+     PERMISSION = "Permission",
+     REMOVE = "Remove",
+ }
+ export enum GroupDetailsPanelPermissionsColumnNames {
+     NAME = "Name",
+     PERMISSION = "Permission",
+     UUID = "UUID",
+     REMOVE = "Remove",
  }
  
- export const groupDetailsPanelColumns: DataColumns<string> = [
+ export const groupDetailsMembersPanelColumns: DataColumns<string> = [
      {
-         name: GroupDetailsPanelColumnNames.FIRST_NAME,
+         name: GroupDetailsPanelMembersColumnNames.FULL_NAME,
          selected: true,
          configurable: true,
          filters: createTree(),
@@@ -80,47 -133,74 +142,74 @@@ export interface GroupDetailsPanelProp
      onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
      onAddUser: () => void;
      resources: ResourcesState;
+     groupCanManage: boolean;
  }
  
--export const GroupDetailsPanel = connect(
++export const GroupDetailsPanel = withStyles(styles)(connect(
      mapStateToProps, mapDispatchToProps
  )(
--    class GroupDetailsPanel extends React.Component<GroupDetailsPanelProps> {
++    class GroupDetailsPanel extends React.Component<GroupDetailsPanelProps & WithStyles<CssRules>> {
+         state = {
+           value: 0,
+         };
+         componentDidMount() {
+             this.setState({ value: 0 });
+         }
  
          render() {
+             const { value } = this.state;
              return (
-                 <DataExplorer
-                     id={GROUP_DETAILS_PANEL_ID}
-                     onRowClick={noop}
-                     onRowDoubleClick={noop}
-                     onContextMenu={this.handleContextMenu}
-                     contextMenuColumn={true}
-                     hideColumnSelector
-                     hideSearchInput
-                     actions={
-                         <Grid container justify='flex-end'>
-                             <Button
-                                 variant="contained"
-                                 color="primary"
-                                 onClick={this.props.onAddUser}>
-                                 <AddIcon /> Add user
-                         </Button>
-                         </Grid>
-                     } />
 -                <Paper>
++                <Paper className={this.props.classes.root}>
+                   <Tabs value={value} onChange={this.handleChange} variant="fullWidth">
+                       <Tab data-cy="group-details-members-tab" label="MEMBERS" />
+                       <Tab data-cy="group-details-permissions-tab" label="PERMISSIONS" />
+                   </Tabs>
+                   {value === 0 &&
+                       <DataExplorer
+                           id={GROUP_DETAILS_MEMBERS_PANEL_ID}
+                           data-cy="group-members-data-explorer"
+                           onRowClick={noop}
+                           onRowDoubleClick={noop}
+                           onContextMenu={noop}
+                           contextMenuColumn={false}
+                           hideColumnSelector
+                           hideSearchInput
+                           actions={
+                                 this.props.groupCanManage &&
+                                 <Grid container justify='flex-end'>
+                                     <Button
+                                       data-cy="group-member-add"
+                                       variant="contained"
+                                       color="primary"
+                                       onClick={this.props.onAddUser}>
+                                       <AddIcon /> Add user
+                                     </Button>
+                                 </Grid>
+                           }
+                           paperProps={{
+                               elevation: 0,
+                           }} />
+                   }
+                   {value === 1 &&
+                       <DataExplorer
+                           id={GROUP_DETAILS_PERMISSIONS_PANEL_ID}
+                           data-cy="group-permissions-data-explorer"
+                           onRowClick={noop}
+                           onRowDoubleClick={noop}
+                           onContextMenu={noop}
+                           contextMenuColumn={false}
+                           hideColumnSelector
+                           hideSearchInput
+                           paperProps={{
+                               elevation: 0,
+                           }} />
+                   }
+                 </Paper>
              );
          }
  
-         handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
-             const resource = getResource<PermissionResource>(resourceUuid)(this.props.resources);
-             if (resource) {
-                 this.props.onContextMenu(event, {
-                     name: '',
-                     uuid: resource.uuid,
-                     ownerUuid: resource.ownerUuid,
-                     kind: resource.kind,
-                     menuKind: ContextMenuKind.GROUP_MEMBER
-                 });
-             }
+         handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
+             this.setState({ value });
          }
--    });
++    }));
index faefab107de3b0365f37a917eaf1f4a3c41cb673,c96c06775376ae0eb47e35e464ce52b6cba54885..3251c729eee32d6df8d75a4c298d38d9bb0e8c4b
@@@ -21,16 -21,6 +21,15 @@@ import { RootState } from 'store/store'
  import { openContextMenu } from 'store/context-menu/context-menu-actions';
  import { ResourceKind } from 'models/resource';
  import { LinkClass, LinkResource } from 'models/link';
- import { navigateToGroupDetails } from 'store/navigation/navigation-action';
 +import { ArvadosTheme } from 'common/custom-theme';
 +
 +type CssRules = "root";
 +
 +const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 +    root: {
 +        width: '100%',
 +    }
 +});
  
  export enum GroupsPanelColumnNames {
      GROUP = "Name",
@@@ -90,10 -77,11 +86,11 @@@ export const GroupsPanel = withStyles(s
  
          render() {
              return (
 -                <DataExplorer
 +                <div className={this.props.classes.root}><DataExplorer
                      id={GROUPS_PANEL_ID}
+                     data-cy="groups-panel-data-explorer"
                      onRowClick={noop}
-                     onRowDoubleClick={this.props.onRowDoubleClick}
+                     onRowDoubleClick={noop}
                      onContextMenu={this.handleContextMenu}
                      contextMenuColumn={true}
                      hideColumnSelector
Simple merge