Skip to content

Commit

Permalink
PIMS-1430 User Table Tidy (#2253)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbarkowsky authored Mar 15, 2024
1 parent ff58c46 commit 5114b19
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 44 deletions.
14 changes: 13 additions & 1 deletion react-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Routes, Route } from 'react-router-dom';
import { Routes, Route, useNavigate } from 'react-router-dom';
import Home from '@/pages/Home';
import React from 'react';
import '@/App.css';
Expand All @@ -13,8 +13,10 @@ import { AccessRequest } from './pages/AccessRequest';
import UsersManagement from './pages/UsersManagement';
import { ErrorBoundary } from 'react-error-boundary';
import ErrorFallback from '@/pages/ErrorFallback';
import UserDetail from '@/components/users/UserDetail';

const Router = () => {
const navigate = useNavigate();
return (
<Routes>
<Route
Expand Down Expand Up @@ -56,6 +58,16 @@ const Router = () => {
</BaseLayout>
}
/>
<Route
path="users/:id"
element={
<BaseLayout>
<AuthRouteGuard>
<UserDetail onClose={() => navigate('/admin/users')} />
</AuthRouteGuard>
</BaseLayout>
}
/>
</Route>
</Routes>
);
Expand Down
2 changes: 1 addition & 1 deletion react-app/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const Header: React.FC = () => {
<Link underline="none" href="#" variant="h5">
Disposal Inventory
</Link>
<Link component={RouterLink} underline="none" to="/admin/users" variant="h5">
<Link underline="none" href="/admin/users" variant="h5">
Users
</Link>
</>
Expand Down
1 change: 1 addition & 0 deletions react-app/src/components/property/PropertyTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ const PropertyTable = () => {
excelTitle={'Properties'}
columns={columns}
rows={rows}
addTooltip="Add a new property"
/>
</Box>
);
Expand Down
13 changes: 5 additions & 8 deletions react-app/src/components/table/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import FilterAltOffIcon from '@mui/icons-material/FilterAltOff';
import DownloadIcon from '@mui/icons-material/Download';
import AddIcon from '@mui/icons-material/Add';
import { GridApiCommunity } from '@mui/x-data-grid/internals';
import { GridInitialStateCommunity } from '@mui/x-data-grid/models/gridStateCommunity';

type RenderCellParams = GridRenderCellParams<any, any, any, GridTreeNodeWithRender>;

Expand Down Expand Up @@ -157,6 +158,8 @@ type FilterSearchDataGridProps = {
presetFilterSelectOptions: JSX.Element[];
tableHeader: string;
excelTitle: string;
addTooltip: string;
initialState?: GridInitialStateCommunity;
} & DataGridProps;

export const FilterSearchDataGrid = (props: FilterSearchDataGridProps) => {
Expand Down Expand Up @@ -218,11 +221,7 @@ export const FilterSearchDataGrid = (props: FilterSearchDataGridProps) => {
onChange={updateSearchValue}
optionalExternalState={[keywordSearchContents, setKeywordSearchContents]}
/>
<Tooltip
title={
'Adding a new user from this table is not supported yet. Please advise users to use the sign-up form.'
}
>
<Tooltip title={props.addTooltip}>
<span>
<IconButton disabled>
<AddIcon />
Expand Down Expand Up @@ -268,9 +267,7 @@ export const FilterSearchDataGrid = (props: FilterSearchDataGridProps) => {
apiRef={tableApiRef}
initialState={{
pagination: { paginationModel: { pageSize: 10 } },
sorting: {
sortModel: [{ field: 'created', sort: 'desc' }],
},
...props.initialState,
}}
pageSizeOptions={[10, 20, 30, 100]} // DataGrid max is 100
disableRowSelectionOnClick
Expand Down
19 changes: 10 additions & 9 deletions react-app/src/components/users/UserDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ import { Agency } from '@/hooks/api/useAgencyApi';
import { Role } from '@/hooks/api/useRolesApi';
import DetailViewNavigation from '../display/DetailViewNavigation';
import { useGroupedAgenciesApi } from '@/hooks/api/useGroupedAgenciesApi';
import { useParams } from 'react-router-dom';

interface IUserDetail {
userId: string;
onClose: () => void;
}

const UserDetail = ({ userId, onClose }: IUserDetail) => {
const UserDetail = ({ onClose }: IUserDetail) => {
const { id } = useParams();
const { pimsUser } = useContext(AuthContext);
const api = usePimsApi();

const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
const [openProfileDialog, setOpenProfileDialog] = useState(false);
const [openStatusDialog, setOpenStatusDialog] = useState(false);

const { data, refreshData } = useDataLoader(() => api.users.getUserById(userId));
const { data, refreshData } = useDataLoader(() => api.users.getUserById(id));

const { data: rolesData, loadOnce: loadRoles } = useDataLoader(api.roles.getInternalRoles);
loadRoles();
Expand Down Expand Up @@ -93,7 +94,7 @@ const UserDetail = ({ userId, onClose }: IUserDetail) => {

useEffect(() => {
refreshData();
}, [userId]);
}, [id]);

useEffect(() => {
profileFormMethods.reset({
Expand Down Expand Up @@ -124,7 +125,7 @@ const UserDetail = ({ userId, onClose }: IUserDetail) => {
deleteTitle={'Delete Account'}
onDeleteClick={() => setOpenDeleteDialog(true)}
onBackClick={() => onClose()}
deleteButtonProps={{ disabled: pimsUser.data.Id === userId }}
deleteButtonProps={{ disabled: pimsUser.data?.Id === id }}
/>
<DataCard
customFormatter={customFormatterStatus}
Expand All @@ -144,7 +145,7 @@ const UserDetail = ({ userId, onClose }: IUserDetail) => {
message={deleteAccountConfirmText}
deleteText="Delete Account"
onDelete={async () => {
api.users.deleteUser(userId).then(() => {
api.users.deleteUser(id).then(() => {
setOpenDeleteDialog(false);
onClose();
});
Expand All @@ -158,7 +159,7 @@ const UserDetail = ({ userId, onClose }: IUserDetail) => {
const isValid = await profileFormMethods.trigger();
if (isValid) {
api.users
.updateUser(userId, { Id: userId, ...profileFormMethods.getValues() })
.updateUser(id, { Id: id, ...profileFormMethods.getValues() })
.then(() => refreshData());
setOpenProfileDialog(false);
}
Expand Down Expand Up @@ -201,8 +202,8 @@ const UserDetail = ({ userId, onClose }: IUserDetail) => {
if (isValid) {
await api.users.updateUserRole(data.Username, statusFormMethods.getValues().Role);
api.users
.updateUser(userId, {
Id: userId,
.updateUser(id, {
Id: id,
Status: statusFormMethods.getValues().Status,
})
.then(() => refreshData());
Expand Down
64 changes: 52 additions & 12 deletions react-app/src/components/users/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ const UsersTable = (props: IUsersTable) => {
// All Status filters
case 'Active':
case 'Pending':
case 'Hold':
case 'On Hold':
case 'Disabled':
ref.current.setFilterModel({
items: [
{
Expand All @@ -92,6 +93,18 @@ const UsersTable = (props: IUsersTable) => {
// All Role filters
case 'User':
case 'Admin':
case 'Auditor':
ref.current.setFilterModel({
items: [
{
value,
operator: 'contains',
field: 'Role',
},
],
});
break;
case 'No Role':
ref.current.setFilterModel({
items: [
{
Expand All @@ -112,12 +125,14 @@ const UsersTable = (props: IUsersTable) => {
headerName: 'First Name',
flex: 1,
minWidth: 125,
maxWidth: 200,
},
{
field: 'LastName',
headerName: 'Last Name',
flex: 1,
minWidth: 125,
maxWidth: 200,
},
{
field: 'Status',
Expand All @@ -126,19 +141,29 @@ const UsersTable = (props: IUsersTable) => {
if (!params.value) return <></>;
return statusChipFormatter(params.value);
},
minWidth: 150,
width: 150,
},
{
field: 'Email',
headerName: 'Email Address',
minWidth: 150,
minWidth: 200,
flex: 1,
},
{
field: 'DisplayName',
headerName: 'IDIR/BCeID',
minWidth: 150,
flex: 1,
field: 'Username',
headerName: 'Provider',
width: 125,
valueGetter: (params) => {
const username: string = params.value;
if (!username.includes('@')) return undefined;
const provider = username.split('@').at(1);
switch (provider) {
case 'idir':
return 'IDIR';
default:
return 'BCeID';
}
},
},
{
field: 'Agency',
Expand All @@ -156,7 +181,7 @@ const UsersTable = (props: IUsersTable) => {
{
field: 'Role',
headerName: 'Role',
minWidth: 100,
minWidth: 150,
flex: 1,
valueGetter: (params) => params.value?.Name ?? `No Role`,
},
Expand Down Expand Up @@ -193,13 +218,19 @@ const UsersTable = (props: IUsersTable) => {
defaultFilter="All Users"
tableHeader="Users Overview"
excelTitle="Users Table"
addTooltip="Adding a new user from this table is not supported yet. Please advise users to use the access request form."
getRowId={(row) => row.Id}
columns={columns}
rows={users}
loading={isLoading}
initialState={{
sorting: {
sortModel: [{ field: 'CreatedOn', sort: 'desc' }],
},
}}
onPresetFilterChange={selectPresetFilter}
presetFilterSelectOptions={[
<CustomMenuItem key={'AllUsers'} value={'All Users'}>
<CustomMenuItem key={'All Users'} value={'All Users'}>
All Users
</CustomMenuItem>,
<CustomListSubheader key={'Status'}>Status</CustomListSubheader>,
Expand All @@ -209,16 +240,25 @@ const UsersTable = (props: IUsersTable) => {
<CustomMenuItem key={'Pending'} value={'Pending'}>
Pending
</CustomMenuItem>,
<CustomMenuItem key={'Hold'} value={'Hold'}>
Hold
<CustomMenuItem key={'On Hold'} value={'On Hold'}>
On Hold
</CustomMenuItem>,
<CustomMenuItem key={'Disabled'} value={'Disabled'}>
Disabled
</CustomMenuItem>,
<CustomListSubheader key={'Role'}>Role</CustomListSubheader>,
<CustomMenuItem key={'User'} value={'User'}>
User
General User
</CustomMenuItem>,
<CustomMenuItem key={'Admin'} value={'Admin'}>
System Admin
</CustomMenuItem>,
<CustomMenuItem key={'Auditor'} value={'Auditor'}>
Auditor
</CustomMenuItem>,
<CustomMenuItem key={'No Role'} value={'No Role'}>
No Role
</CustomMenuItem>,
]}
/>
</Box>
Expand Down
25 changes: 12 additions & 13 deletions react-app/src/pages/UsersManagement.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import UserDetail from '@/components/users/UserDetail';
import UsersTable from '@/components/users/UsersTable';
import useDataLoader from '@/hooks/useDataLoader';
import usePimsApi from '@/hooks/usePimsApi';
import React, { useState } from 'react';
import React from 'react';
import { useNavigate } from 'react-router-dom';

const UsersManagement = () => {
const [selectedUserId, setSelectedUserId] = useState('');
const navigate = useNavigate();
// Getting data from API
const usersApi = usePimsApi();
const { data, refreshData, isLoading, error } = useDataLoader(usersApi.users.getAllUsers);
return selectedUserId ? (
<UserDetail
userId={selectedUserId}
onClose={() => {
setSelectedUserId('');
refreshData();
}}
/>
) : (

return (
<UsersTable
rowClickHandler={(params) => setSelectedUserId(params.row.Id)}
rowClickHandler={(params) => {
// Checking length of selection so it only navigates if user isn't trying to select something
const selection = window.getSelection().toString();
if (!selection.length) {
navigate(`/admin/users/${params.id}`);
}
}}
data={data}
refreshData={refreshData}
isLoading={isLoading}
Expand Down

0 comments on commit 5114b19

Please sign in to comment.