diff --git a/src/components/DateRange.tsx b/src/components/DateRange.tsx index ec22390..c0a76f5 100644 --- a/src/components/DateRange.tsx +++ b/src/components/DateRange.tsx @@ -91,27 +91,24 @@ function ButtonField(props: ButtonFieldProps) { return ( - - - + Ending Date Range diff --git a/src/components/TableTopBar.tsx b/src/components/TableTopBar.tsx new file mode 100644 index 0000000..1532201 --- /dev/null +++ b/src/components/TableTopBar.tsx @@ -0,0 +1,75 @@ +import {Launch} from '@mui/icons-material'; +import {Autocomplete, AutocompleteProps, Box, Grid, IconButton, Stack, TextField, Typography} from '@mui/material'; + +import * as React from 'react'; +import {useNavigate} from 'react-router-dom'; + +export function renderUserOption(props: React.HTMLAttributes, option: any) { + const [displayName, email] = option.split(';'); + return ( +
  • + + + {displayName} + + {email} + + + +
  • + ); +} + +export function TableTopBarAutocomplete({ + defaultValue, + filterOptions = (x) => x, + ...restProps +}: Omit, 'renderInput'>) { + return ( + } + {...restProps} + /> + ); +} + +interface TableTopBarProps { + title: string; + link?: string; + children?: React.ReactNode; +} + +export default function TableTopBar({title, link, children}: TableTopBarProps) { + const navigate = useNavigate(); + return ( + + + + {title} + + {link != null && ( + navigate(link)}> + + + )} + + + {children} + + + ); +} diff --git a/src/pages/apps/List.tsx b/src/pages/apps/List.tsx index 8b6f604..6e92f2d 100644 --- a/src/pages/apps/List.tsx +++ b/src/pages/apps/List.tsx @@ -24,6 +24,7 @@ import CreateUpdateApp from './CreateUpdate'; import {perPage} from '../../helpers'; import {useGetApps} from '../../api/apiComponents'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; export default function ListApps() { const navigate = useNavigate(); @@ -105,96 +106,70 @@ export default function ListApps() { }; return ( - - - - - + + + + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + Name + Description + + + + {rows.map((row) => ( + - - Applications - + + {row.name} + - - - - - - - - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> - + + + {(row.description ?? '').length > 115 + ? row.description?.substring(0, 114) + '...' + : row.description ?? ''} + - - Name - Description - - - - {rows.map((row) => ( - - - - {row.name} - - - - - {(row.description ?? '').length > 115 - ? row.description?.substring(0, 114) + '...' - : row.description ?? ''} - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/groups/Audit.tsx b/src/pages/groups/Audit.tsx index 00b1431..4e4369d 100644 --- a/src/pages/groups/Audit.tsx +++ b/src/pages/groups/Audit.tsx @@ -34,6 +34,7 @@ import Loading from '../../components/Loading'; import Started from '../../components/Started'; import Ending from '../../components/Ending'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {renderUserOption, TableTopBarAutocomplete} from '../../components/TableTopBar'; type OrderBy = 'moniker' | 'created_at' | 'ended_at'; type OrderDirection = 'asc' | 'desc'; @@ -192,251 +193,207 @@ export default function AuditGroup() { }; return ( - - - - - - - - {(group.deleted_at ?? null) != null ? ( - - {group.name} - - ) : ( - - {group.name} - - )}{' '} - Group Audit - - + + + + Member + Owner + + + Active + Inactive + + displayUserName(row) + ';' + row.email.toLowerCase())} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => { + setSearchInput(newInputValue?.split(';')[0] ?? ''); + }} + defaultValue={searchQuery} + renderOption={renderUserOption} + /> + +
    + + + + + User Name + + + User Email + Member or Owner + Direct or via Role + + + Started + + + Added by + + + Ending + + + Removed by + Access Request + Justification + + + + {rows.map((row) => ( + + Object.values(row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at))) + ? palette.highlight.success.main + : palette.highlight.danger.main, + }}> - - Member - Owner - + {(row.user?.deleted_at ?? null) != null ? ( + + {displayUserName(row.user)} + + ) : ( + + {displayUserName(row.user)} + + )} - - - Active - Inactive - + + {(row.user?.deleted_at ?? null) != null ? ( + + {row.user?.email.toLowerCase()} + + ) : ( + + {row.user?.email.toLowerCase()} + + )} - - x} - options={searchRows.map((row) => displayUserName(row) + ';' + row.email.toLowerCase())} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => { - setSearchInput(newInputValue?.split(';')[0] ?? ''); - }} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - renderOption={(props, option, state) => { - const [displayName, email] = option.split(';'); - return ( -
  • - - - {displayName} - - {email} - - - -
  • - ); - }} - /> + {row.is_owner ? 'Owner' : 'Member'} + + {row.role_group_mapping == null ? ( + + ) : ( + navigate(`/roles/${row.role_group_mapping?.role_group?.name}`)} + /> + )} -
    - - - User Name - + - User Email - Member or Owner - Direct or via Role - - Started - + {(row.created_actor?.deleted_at ?? null) != null ? ( + + {displayUserName(row.created_actor)} + + ) : ( + + {displayUserName(row.created_actor)} + + )} - Added by - - Ending - + - Removed by - Access Request - Justification - - - - {rows.map((row) => ( - - Object.values(row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at))) - ? palette.highlight.success.main - : palette.highlight.danger.main, - }}> - - {(row.user?.deleted_at ?? null) != null ? ( - - {displayUserName(row.user)} - - ) : ( - - {displayUserName(row.user)} - - )} - - - {(row.user?.deleted_at ?? null) != null ? ( - - {row.user?.email.toLowerCase()} - - ) : ( - - {row.user?.email.toLowerCase()} - - )} - - {row.is_owner ? 'Owner' : 'Member'} - - {row.role_group_mapping == null ? ( - - ) : ( - navigate(`/roles/${row.role_group_mapping?.role_group?.name}`)} - /> - )} - - - - - - {(row.created_actor?.deleted_at ?? null) != null ? ( + + {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( + (row.ended_actor?.deleted_at ?? null) != null ? ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} ) : ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} - )} - - - - - - {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( - (row.ended_actor?.deleted_at ?? null) != null ? ( - - {displayUserName(row.ended_actor)} - - ) : ( - - {displayUserName(row.ended_actor)} - - ) - ) : ( - '' - )} - - - {row.access_request != null ? ( - - ) : null} - - - {row.created_reason ? : null} - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ) + ) : ( + '' + )} + + + {row.access_request != null ? ( + + ) : null} + + + {row.created_reason ? : null} + + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/groups/Expiring.tsx b/src/pages/groups/Expiring.tsx index 58e665d..3e97b9c 100644 --- a/src/pages/groups/Expiring.tsx +++ b/src/pages/groups/Expiring.tsx @@ -34,6 +34,7 @@ import Loading from '../../components/Loading'; import Started from '../../components/Started'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; import {displayUserName, perPage} from '../../helpers'; +import TableTopBar, {renderUserOption, TableTopBarAutocomplete} from '../../components/TableTopBar'; type OrderBy = 'moniker' | 'ended_at'; type OrderDirection = 'asc' | 'desc'; @@ -205,229 +206,197 @@ export default function ExpiringGroups() { }; return ( - - - - - + + + canManageGroup(currentUser, row.group))} + ownAccess={userId == '@me' || userId == currentUser.id} + /> + + Active + Inactive + + , + }} + /> + displayUserName(row) + ';' + row.email.toLowerCase())} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => { + setSearchInput(newInputValue?.split(';')[0] ?? ''); + }} + defaultValue={searchQuery} + renderOption={renderUserOption} + /> + +
    + + + + + User Name + + + User Email + Group Name + Member or Owner + + Started + + Added by + + + Ending + + + + + + {rows.map((row) => ( + + dayjs(row.ended_at).isAfter(dayjs()) && dayjs(row.ended_at).isBefore(dayjs().add(7, 'day')) + ? highlight.warning.main + : dayjs(row.ended_at).isBefore(dayjs()) + ? highlight.danger.main + : null, + }}> - - Expiring Groups - + {(row.user?.deleted_at ?? null) != null ? ( + + {displayUserName(row.user)} + + ) : ( + + {displayUserName(row.user)} + + )} - canManageGroup(currentUser, row.group))} - ownAccess={userId == '@me' || userId == currentUser.id} - /> + {(row.user?.deleted_at ?? null) != null ? ( + + {row.user?.email.toLowerCase()} + + ) : ( + + {row.user?.email.toLowerCase()} + + )} - - Active - Inactive - - - - , - }} - /> - - - x} - options={searchRows.map((row) => displayUserName(row) + ';' + row.email.toLowerCase())} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => { - setSearchInput(newInputValue?.split(';')[0] ?? ''); - }} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - renderOption={(props, option, state) => { - const [displayName, email] = option.split(';'); - return ( -
  • - - - {displayName} - - {email} - - - -
  • - ); - }} - /> + {(row.group?.deleted_at ?? null) != null ? ( + + {row.group?.name ?? ''} + + ) : ( + + {row.group?.name ?? ''} + + )}
    -
    - + {row.is_owner ? 'Owner' : 'Member'} - - User Name - + - User Email - Group Name - Member or Owner - Started + {(row.created_actor?.deleted_at ?? null) != null ? ( + + {displayUserName(row.created_actor)} + + ) : ( + + {displayUserName(row.created_actor)} + + )} - Added by - - - Ending - + + - - - - {rows.map((row) => ( - - dayjs(row.ended_at).isAfter(dayjs()) && dayjs(row.ended_at).isBefore(dayjs().add(7, 'day')) - ? highlight.warning.main - : dayjs(row.ended_at).isBefore(dayjs()) - ? highlight.danger.main - : null, - }}> - - {(row.user?.deleted_at ?? null) != null ? ( - - {displayUserName(row.user)} - - ) : ( - - {displayUserName(row.user)} - - )} - - - {(row.user?.deleted_at ?? null) != null ? ( - - {row.user?.email.toLowerCase()} - - ) : ( - - {row.user?.email.toLowerCase()} - - )} - - - {(row.group?.deleted_at ?? null) != null ? ( - - {row.group?.name ?? ''} - - ) : ( - - {row.group?.name ?? ''} - - )} + {userId == '@me' || currentUser.id == row.user.id ? ( + + - {row.is_owner ? 'Owner' : 'Member'} - - + ) : ownerId == '@me' || canManageGroup(currentUser, row.group) ? ( + + canManageGroup(currentUser, row.group))} select={row.id} /> - - {(row.created_actor?.deleted_at ?? null) != null ? ( - - {displayUserName(row.created_actor)} - - ) : ( - - {displayUserName(row.created_actor)} - - )} - - - - - {userId == '@me' || currentUser.id == row.user.id ? ( - - - - ) : ownerId == '@me' || canManageGroup(currentUser, row.group) ? ( - - canManageGroup(currentUser, row.group))} select={row.id} /> - - ) : ( - - )} - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ) : ( + + )} + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/groups/List.tsx b/src/pages/groups/List.tsx index 2c269b8..131937e 100644 --- a/src/pages/groups/List.tsx +++ b/src/pages/groups/List.tsx @@ -16,13 +16,13 @@ import TableHead from '@mui/material/TableHead'; import TablePagination from '@mui/material/TablePagination'; import TableRow from '@mui/material/TableRow'; import TextField from '@mui/material/TextField'; -import Typography from '@mui/material/Typography'; import {useCurrentUser} from '../../authentication'; import CreateUpdateGroup from './CreateUpdate'; import {displayGroupType, perPage} from '../../helpers'; import {useGetGroups} from '../../api/apiComponents'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; export default function ListGroups() { const navigate = useNavigate(); @@ -104,102 +104,76 @@ export default function ListGroups() { }; return ( - - - - - + + + + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + Name + Type + Description + + + + {rows.map((row) => ( + - - Groups - + + {row.name} + - + + {displayGroupType(row)} + - - + + + {(row.description?.length ?? 0) > 115 + ? row.description?.substring(0, 114) + '...' ?? '' + : row.description} + - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> - - - - Name - Type - Description - - - {rows.map((row) => ( - - - - {row.name} - - - - - {displayGroupType(row)} - - - - - {(row.description?.length ?? 0) > 115 - ? row.description?.substring(0, 114) + '...' ?? '' - : row.description} - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/requests/List.tsx b/src/pages/requests/List.tsx index e3cddc5..153fedc 100644 --- a/src/pages/requests/List.tsx +++ b/src/pages/requests/List.tsx @@ -27,6 +27,7 @@ import CreateRequest from './Create'; import {useGetRequests} from '../../api/apiComponents'; import {displayUserName, perPage} from '../../helpers'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; dayjs.extend(RelativeTime); @@ -124,189 +125,168 @@ export default function ListRequests() { }; return ( - - - - - + + + + + row.id + + ';' + + displayUserName(row.requester) + + ';' + + row.request_ownership + + ';' + + (row.requested_group?.name ?? '') + + ';' + + (row.status ?? '') + + ';' + + displayUserName(row.resolver), + )} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => { + setSearchInput(newInputValue?.split(';')[0] ?? ''); + }} + defaultValue={searchQuery} + renderOption={(props, option, state) => { + const [id, displayName, ownership, group, status, resolver] = option.split(';'); + return ( +
  • + + + + {displayName} {ownership == 'true' ? 'ownership of' : 'membership to'} {group} + + + {status} {status == 'PENDING' || resolver == '' ? '' : 'by ' + resolver} + + + +
  • + ); + }} + /> +
    +
    + + + Requester + Request + Resolver + Status + Created + + + + {rows.map((row) => ( + + row.status == 'APPROVED' + ? highlight.success.main + : row.status == 'REJECTED' + ? highlight.danger.main + : 'inherit', + }}> - - Access Requests - + {(row.requester?.deleted_at ?? null) != null ? ( + + {displayUserName(row.requester)} + + ) : ( + + {displayUserName(row.requester)} + + )} - - - - x} - options={searchRows.map( - (row) => - row.id + - ';' + - displayUserName(row.requester) + - ';' + - row.request_ownership + - ';' + - (row.requested_group?.name ?? '') + - ';' + - (row.status ?? '') + - ';' + - displayUserName(row.resolver), - )} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => { - setSearchInput(newInputValue?.split(';')[0] ?? ''); - }} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - renderOption={(props, option, state) => { - const [id, displayName, ownership, group, status, resolver] = option.split(';'); - return ( -
  • - - - - {displayName} {ownership == 'true' ? 'ownership of' : 'membership to'} {group} - - - {status} {status == 'PENDING' || resolver == '' ? '' : 'by ' + resolver} - - - -
  • - ); - }} - /> -
    -
    - - Requester - Request - Resolver - Status - Created - - - - {rows.map((row) => ( - - row.status == 'APPROVED' - ? highlight.success.main - : row.status == 'REJECTED' - ? highlight.danger.main - : 'inherit', - }}> - - {(row.requester?.deleted_at ?? null) != null ? ( - - {displayUserName(row.requester)} - - ) : ( - - {displayUserName(row.requester)} - - )} - - - {row.request_ownership ? 'Ownership of ' : 'Membership to '} - {(row.requested_group?.deleted_at ?? null) != null ? ( - - {row.requested_group?.name ?? ''} - - ) : ( - - {row.requested_group?.name ?? ''} - - )} - - - {row.resolver == null && row.status != 'PENDING' ? ( - 'Access' - ) : (row.resolver?.deleted_at ?? null) != null ? ( - - {displayUserName(row.resolver)} - - ) : ( - - {displayUserName(row.resolver)} - - )} - - + {row.request_ownership ? 'Ownership of ' : 'Membership to '} + {(row.requested_group?.deleted_at ?? null) != null ? ( + + {row.requested_group?.name ?? ''} + + ) : ( - {row.status} + {row.requested_group?.name ?? ''} - - + )} + + + {row.resolver == null && row.status != 'PENDING' ? ( + 'Access' + ) : (row.resolver?.deleted_at ?? null) != null ? ( + {displayUserName(row.resolver)} + + ) : ( + - {dayjs(row.created_at).startOf('second').fromNow()} + {displayUserName(row.resolver)} - - - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + )} + + + + {row.status} + + + + + {dayjs(row.created_at).startOf('second').fromNow()} + + + + + + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/roles/Audit.tsx b/src/pages/roles/Audit.tsx index ab11885..c832f37 100644 --- a/src/pages/roles/Audit.tsx +++ b/src/pages/roles/Audit.tsx @@ -31,6 +31,7 @@ import Loading from '../../components/Loading'; import Started from '../../components/Started'; import Ending from '../../components/Ending'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; type OrderBy = 'moniker' | 'created_at' | 'ended_at'; type OrderDirection = 'asc' | 'desc'; @@ -187,205 +188,173 @@ export default function AuditRole() { }; return ( - - - - - + + + + Active + Inactive + + + Member + Owner + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + + + Group Name + + + Group Type + Member or Owner + + + Started + + + Added by + + + Ending + + + Removed by + Justification + + + + {rows.map((row) => ( + + row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at)) + ? highlight.success.main + : highlight.danger.main, + }}> - - {(role.deleted_at ?? null) != null ? ( - - {role.name} - - ) : ( - - {role.name} - - )}{' '} - Role Audit - + {(row.group?.deleted_at ?? null) != null ? ( + + {row.group?.name ?? ''} + + ) : ( + + {row.group?.name ?? ''} + + )} - - Active - Inactive - - - - - Member - Owner - + {(row.group?.deleted_at ?? null) != null ? ( + displayGroupType(row.group) + ) : ( + + {displayGroupType(row.group)} + + )} - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> - - - + {row.is_owner ? 'Owner' : 'Member'} - - Group Name - + - Group Type - Member or Owner - - Started - + {(row.created_actor?.deleted_at ?? null) != null ? ( + + {displayUserName(row.created_actor)} + + ) : ( + + {displayUserName(row.created_actor)} + + )} - Added by - - Ending - + - Removed by - Justification - - - - {rows.map((row) => ( - - row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at)) - ? highlight.success.main - : highlight.danger.main, - }}> - - {(row.group?.deleted_at ?? null) != null ? ( - - {row.group?.name ?? ''} - - ) : ( - - {row.group?.name ?? ''} - - )} - - - {(row.group?.deleted_at ?? null) != null ? ( - displayGroupType(row.group) - ) : ( - - {displayGroupType(row.group)} - - )} - - {row.is_owner ? 'Owner' : 'Member'} - - - - - {(row.created_actor?.deleted_at ?? null) != null ? ( + + {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( + (row.ended_actor?.deleted_at ?? null) != null ? ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} ) : ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} - )} - - - - - - {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( - (row.ended_actor?.deleted_at ?? null) != null ? ( - - {displayUserName(row.ended_actor)} - - ) : ( - - {displayUserName(row.ended_actor)} - - ) - ) : ( - '' - )} - - - {row.created_reason ? : null} - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ) + ) : ( + '' + )} + + {row.created_reason ? : null} + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/roles/Expiring.tsx b/src/pages/roles/Expiring.tsx index 1acbb5b..0005a61 100644 --- a/src/pages/roles/Expiring.tsx +++ b/src/pages/roles/Expiring.tsx @@ -32,6 +32,7 @@ import Loading from '../../components/Loading'; import Started from '../../components/Started'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; import {displayUserName, perPage} from '../../helpers'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; type OrderBy = 'moniker' | 'ended_at'; type OrderDirection = 'asc' | 'desc'; @@ -209,211 +210,192 @@ export default function ExpiringRoless() { }; return ( - - - - - + + + canManageGroup(currentUser, row.group))} /> + + Active + Inactive + + {ownerId ? ( + + + + Default Owner + + + + + All Owned + + + + ) : null} + , + }} + /> + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + Role Name + + + Group Name + + + Group Type + Member or Owner + + Started + + Added by + + + Ending + + + + + + {rows.map((row) => ( + + dayjs(row.ended_at).isAfter(dayjs()) && dayjs(row.ended_at).isBefore(dayjs().add(7, 'day')) + ? highlight.warning.main + : dayjs(row.ended_at).isBefore(dayjs()) + ? highlight.danger.main + : null, + }}> - - Expiring Roles - + {(row.group?.deleted_at ?? null) != null ? ( + + {row.role_group?.name ?? ''} + + ) : ( + + {row.role_group?.name ?? ''} + + )} - canManageGroup(currentUser, row.group))} /> + {(row.group?.deleted_at ?? null) != null ? ( + + {row.group?.name ?? ''} + + ) : ( + + {row.group?.name ?? ''} + + )} - - Active - Inactive - - - {ownerId ? ( - - - - - Default Owner - - - - - All Owned - - - - - ) : null} - - , - }} - /> - - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> + {row.group?.type == 'okta_group' ? 'Group' : 'app_group' ? 'App Group' : 'Role Group'} - - - Role Name + {row.is_owner ? 'Owner' : 'Member'} - - Group Name - + - Group Type - Member or Owner - Started + {(row.created_actor?.deleted_at ?? null) != null ? ( + + {displayUserName(row.created_actor)} + + ) : ( + + {displayUserName(row.created_actor)} + + )} - Added by - - - Ending - + + - - - - {rows.map((row) => ( - - dayjs(row.ended_at).isAfter(dayjs()) && dayjs(row.ended_at).isBefore(dayjs().add(7, 'day')) - ? highlight.warning.main - : dayjs(row.ended_at).isBefore(dayjs()) - ? highlight.danger.main - : null, - }}> - - {(row.group?.deleted_at ?? null) != null ? ( - - {row.role_group?.name ?? ''} - - ) : ( - - {row.role_group?.name ?? ''} - - )} - - - {(row.group?.deleted_at ?? null) != null ? ( - - {row.group?.name ?? ''} - - ) : ( - - {row.group?.name ?? ''} - - )} - - - {row.group?.type == 'okta_group' ? 'Group' : 'app_group' ? 'App Group' : 'Role Group'} - - {row.is_owner ? 'Owner' : 'Member'} - - + {ownerId == '@me' || canManageGroup(currentUser, row.group) ? ( + + canManageGroup(currentUser, row.group))} select={row.id} /> - - {(row.created_actor?.deleted_at ?? null) != null ? ( - - {displayUserName(row.created_actor)} - - ) : ( - - {displayUserName(row.created_actor)} - - )} - - - - - {ownerId == '@me' || canManageGroup(currentUser, row.group) ? ( - - canManageGroup(currentUser, row.group))} select={row.id} /> - - ) : ( - - )} - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ) : ( + + )} + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/roles/List.tsx b/src/pages/roles/List.tsx index 8fbbbb5..37607a9 100644 --- a/src/pages/roles/List.tsx +++ b/src/pages/roles/List.tsx @@ -24,6 +24,7 @@ import CreateUpdateGroup from '../groups/CreateUpdate'; import {perPage} from '../../helpers'; import {useGetRoles} from '../../api/apiComponents'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; export default function ListRoles() { const navigate = useNavigate(); @@ -105,102 +106,70 @@ export default function ListRoles() { }; return ( - - - - - + + + + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + Name + Description + + + + {rows.map((row) => ( + - - Roles - + + {row.name} + - - - - - - - - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> - + + + {(row.description?.length ?? 0) > 115 + ? row.description?.substring(0, 114) + '...' ?? '' + : row.description} + - - Name - Description - - - - {rows.map((row) => ( - - - - {row.name} - - - - - {(row.description?.length ?? 0) > 115 - ? row.description?.substring(0, 114) + '...' ?? '' - : row.description} - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/tags/List.tsx b/src/pages/tags/List.tsx index 97a2577..4e9db00 100644 --- a/src/pages/tags/List.tsx +++ b/src/pages/tags/List.tsx @@ -22,6 +22,7 @@ import CreateUpdateTag from './CreateUpdate'; import {perPage} from '../../helpers'; import {useGetTags} from '../../api/apiComponents'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; export default function ListTags() { const navigate = useNavigate(); @@ -103,91 +104,67 @@ export default function ListTags() { }; return ( - - - - - + + + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + Name + Description + + + + {rows.map((row) => ( + - - Tags - + + {row.name} + - - - - - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> - + + + {(row.description ?? '').length > 115 + ? row.description?.substring(0, 114) + '...' + : row.description ?? ''} + - - Name - Description - - - - {rows.map((row) => ( - - - - {row.name} - - - - - {(row.description ?? '').length > 115 - ? row.description?.substring(0, 114) + '...' - : row.description ?? ''} - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/users/Audit.tsx b/src/pages/users/Audit.tsx index f3339e0..595fdca 100644 --- a/src/pages/users/Audit.tsx +++ b/src/pages/users/Audit.tsx @@ -32,6 +32,7 @@ import Loading from '../../components/Loading'; import Started from '../../components/Started'; import Ending from '../../components/Ending'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; +import TableTopBar, {TableTopBarAutocomplete} from '../../components/TableTopBar'; type OrderBy = 'moniker' | 'created_at' | 'ended_at'; type OrderDirection = 'asc' | 'desc'; @@ -189,229 +190,199 @@ export default function AuditUser() { }; return ( - - - - - - - - {(user.deleted_at ?? null) != null ? ( - - {displayUserName(user)} - - ) : ( - - {displayUserName(user)} - - )}{' '} - Audit - - + + + + Member + Owner + + + Active + Inactive + + row.name)} + onChange={handleSearchSubmit} + onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} + defaultValue={searchQuery} + /> + +
    + + + + + Group Name + + + Group Type + Member or Owner + Direct or via Role + + + Started + + + Added by + + + Ending + + + Removed by + Access Request + Justification + + + + {rows.map((row) => ( + + row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at)) + ? highlight.success.main + : highlight.danger.main, + }}> - - Member - Owner - + {(row.group?.deleted_at ?? null) != null ? ( + + {row.group?.name ?? ''} + + ) : ( + + {row.group?.name ?? ''} + + )} - - - Active - Inactive - + + {(row.group?.deleted_at ?? null) != null ? ( + displayGroupType(row.group) + ) : ( + + {displayGroupType(row.group)} + + )} - - x} - options={searchRows.map((row) => row.name)} - onChange={handleSearchSubmit} - onInputChange={(event, newInputValue) => setSearchInput(newInputValue)} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - /> + {row.is_owner ? 'Owner' : 'Member'} + + {row.role_group_mapping == null ? ( + + ) : ( + navigate(`/roles/${row.role_group_mapping?.role_group?.name}`)} + /> + )} - - - - Group Name - + - Group Type - Member or Owner - Direct or via Role - - Started - + {(row.created_actor?.deleted_at ?? null) != null ? ( + + {displayUserName(row.created_actor)} + + ) : ( + + {displayUserName(row.created_actor)} + + )} - Added by - - Ending - + - Removed by - Access Request - Justification - - - - {rows.map((row) => ( - - row.ended_at == null || dayjs().isBefore(dayjs(row.ended_at)) - ? highlight.success.main - : highlight.danger.main, - }}> - - {(row.group?.deleted_at ?? null) != null ? ( - - {row.group?.name ?? ''} - - ) : ( - - {row.group?.name ?? ''} - - )} - - - {(row.group?.deleted_at ?? null) != null ? ( - displayGroupType(row.group) - ) : ( - - {displayGroupType(row.group)} - - )} - - {row.is_owner ? 'Owner' : 'Member'} - - {row.role_group_mapping == null ? ( - - ) : ( - navigate(`/roles/${row.role_group_mapping?.role_group?.name}`)} - /> - )} - - - - - - {(row.created_actor?.deleted_at ?? null) != null ? ( + + {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( + (row.ended_actor?.deleted_at ?? null) != null ? ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} ) : ( - {displayUserName(row.created_actor)} + {displayUserName(row.ended_actor)} - )} - - - - - - {row.ended_at != null && dayjs().isAfter(dayjs(row.ended_at)) ? ( - (row.ended_actor?.deleted_at ?? null) != null ? ( - - {displayUserName(row.ended_actor)} - - ) : ( - - {displayUserName(row.ended_actor)} - - ) - ) : ( - '' - )} - - - {row.access_request != null ? ( - - ) : null} - - - {row.created_reason ? : null} - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ) + ) : ( + '' + )} + + + {row.access_request != null ? ( + + ) : null} + + + {row.created_reason ? : null} + + + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); } diff --git a/src/pages/users/List.tsx b/src/pages/users/List.tsx index fb13120..20a04c3 100644 --- a/src/pages/users/List.tsx +++ b/src/pages/users/List.tsx @@ -22,6 +22,8 @@ import {useGetUsers} from '../../api/apiComponents'; import TablePaginationActions from '../../components/actions/TablePaginationActions'; import UserAvatar from './UserAvatar'; import {displayUserName, perPage} from '../../helpers'; +import {Stack} from '@mui/material'; +import TableTopBar, {renderUserOption, TableTopBarAutocomplete} from '../../components/TableTopBar'; export default function ListUsers() { const navigate = useNavigate(); @@ -102,110 +104,83 @@ export default function ListUsers() { }; return ( - - - - - + + + displayUserName(row) + ';' + row.email.toLowerCase())} + onInputChange={(event, newInputValue) => { + setSearchInput(newInputValue?.split(';')[0] ?? ''); + }} + onChange={handleSearchSubmit} + defaultValue={searchQuery} + key={searchQuery} + renderOption={renderUserOption} + /> + +
    + + + + Name + Email + + + + {rows.map((row) => ( + - - Users - + + + - - - x} - options={searchRows.map((row) => displayUserName(row) + ';' + row.email.toLowerCase())} - onInputChange={(event, newInputValue) => { - setSearchInput(newInputValue?.split(';')[0] ?? ''); - }} - onChange={handleSearchSubmit} - defaultValue={searchQuery} - key={searchQuery} - renderInput={(params) => } - renderOption={(props, option, state) => { - const [displayName, email] = option.split(';'); - return ( -
  • - - - {displayName} - - {email} - - - -
  • - ); - }} - /> + + + {displayUserName(row)} + + + + + {row.email.toLowerCase()} +
    - - - Name - Email - - - - {rows.map((row) => ( - - - - - - - - - {displayUserName(row)} - - - - - {row.email.toLowerCase()} - - - - ))} - {emptyRows > 0 && ( - - - - )} - - - - + ))} + {emptyRows > 0 && ( + + - -
    -
    -
    + )} + + + + + + + + ); }