Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIMS-680/1294: Admin Users View UI & Access Request Submission #2168

Merged
merged 54 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
ba21f1a
Basic re-usable data card implemented
GrahamS-Quartech Jan 31, 2024
84e6f52
Partial fetch and api hooks implementation
GrahamS-Quartech Jan 31, 2024
c0c2297
Implemented a basic placeholder api hook based off the fetch implemen…
GrahamS-Quartech Feb 1, 2024
4561469
Added an auth context which has keycloak data only for now, and imple…
GrahamS-Quartech Feb 1, 2024
f41d451
Added a useDataLoader hook to support both automatically and manually…
GrahamS-Quartech Feb 1, 2024
8d8dd60
Merge branch 'main' into PIMS-1260-ApiHooks
GrahamS-Quartech Feb 2, 2024
04a65fd
Updated formatting on various parts of the components and implemetned…
GrahamS-Quartech Feb 2, 2024
1c233aa
Made some reusable dialog components and implemented the delete user …
GrahamS-Quartech Feb 2, 2024
dfd802c
Implemented the update forms for the user detail page
GrahamS-Quartech Feb 3, 2024
a82532d
Fixed some circular dependencies and updated the typeorm npm script t…
GrahamS-Quartech Feb 5, 2024
2ad9b3b
Merge branch 'main' into PIMS-1260-ApiHooks
dbarkowsky Feb 6, 2024
d9058a9
Added some extra comments/docstrings
GrahamS-Quartech Feb 6, 2024
d010fa6
lint fixes
GrahamS-Quartech Feb 6, 2024
19d2b78
Updated access services and entities to use keycloak guid instead of …
GrahamS-Quartech Feb 6, 2024
f4b20e6
Implemented an endpoint that will let the current keycloak user refle…
GrahamS-Quartech Feb 7, 2024
a4196ea
Fixed some issues with collecting the user context and implemented th…
GrahamS-Quartech Feb 7, 2024
0c67ea3
Included missing position and notes fields in request submission
GrahamS-Quartech Feb 7, 2024
7bd6bc2
Merge branch 'main' into PIMS-1294-AccessRequestWorkflow
GrahamS-Quartech Feb 8, 2024
e0caee0
Missed some merge markers
GrahamS-Quartech Feb 8, 2024
f55bbf6
Merge branch 'main' into PIMS-680-AdminUsersViewUI
GrahamS-Quartech Feb 8, 2024
2941516
Merge branch 'PIMS-1294-AccessRequestWorkflow' into PIMS-680-AdminUse…
GrahamS-Quartech Feb 8, 2024
c17809f
Implemented additional api hooks and wired them up to the users page …
GrahamS-Quartech Feb 8, 2024
7b02db7
Implemented delete operation, button is disabled if you are viewing t…
GrahamS-Quartech Feb 8, 2024
b33a9fe
Form now has basic validation, you cannot submit the form if there ar…
GrahamS-Quartech Feb 9, 2024
4d21035
Fixed some linter issues
GrahamS-Quartech Feb 9, 2024
53b5377
linter fixes
GrahamS-Quartech Feb 9, 2024
8a0fc17
Fixed several unit and set some of the access request ones to ignore …
GrahamS-Quartech Feb 9, 2024
7be2299
Merge branch 'main' into PIMS-680-AdminUsersViewUI
GrahamS-Quartech Feb 12, 2024
d5f444f
Added migration for status enum
GrahamS-Quartech Feb 12, 2024
cec1a28
Users table will grab the agency name now
GrahamS-Quartech Feb 13, 2024
2542d44
Merge branch 'PIMS-1294-AccessRequestWorkflow' into PIMS-680-AdminUse…
GrahamS-Quartech Feb 13, 2024
abbe285
Merge branch 'main' into PIMS-680-AdminUsersViewUI
GrahamS-Quartech Feb 13, 2024
293837a
Missed a merge marker
GrahamS-Quartech Feb 13, 2024
7f89620
Added in an agencies API hook. Not completely fleshed out but fine fo…
GrahamS-Quartech Feb 13, 2024
80e525f
Commented out all the likely deprecated access request tests and rela…
GrahamS-Quartech Feb 13, 2024
1d1896b
added more test coverage to reach threshold
GrahamS-Quartech Feb 13, 2024
b0f6926
Fixed a compile time error
GrahamS-Quartech Feb 13, 2024
96532ab
Merge branch 'main' into PIMS-680-AdminUsersViewUI
GrahamS-Quartech Feb 13, 2024
1a571d7
Added default text for delete button dialog
GrahamS-Quartech Feb 13, 2024
558e6ed
Merge branch 'PIMS-680-AdminUsersViewUI' of github.com:bcgov/PIMS int…
GrahamS-Quartech Feb 13, 2024
f694abd
Fixed minor issue where MUI would raise an error on changing autocomp…
GrahamS-Quartech Feb 14, 2024
705e050
dockercompose and nginx fix
dbarkowsky Feb 15, 2024
344613f
Merge branch 'PIMS-680-AdminUsersViewUI' of https://github.com/bcgov/…
dbarkowsky Feb 15, 2024
629930c
Update keycloak package
dbarkowsky Feb 15, 2024
490d7a8
AccessRequest conditional render change
dbarkowsky Feb 15, 2024
aea06bd
Using entities array instead of paths
dbarkowsky Feb 15, 2024
4100b93
Use preferred username
dbarkowsky Feb 15, 2024
688a9e2
getAgencies using keycloak roles only
dbarkowsky Feb 15, 2024
b3aeacc
Changed getUser to not throw.
GrahamS-Quartech Feb 15, 2024
c0e5f94
Merge branch 'main' into PIMS-680-AdminUsersViewUI
dbarkowsky Feb 15, 2024
000a865
NGINX config merge fix
dbarkowsky Feb 15, 2024
817b2d1
Merge branch 'PIMS-680-AdminUsersViewUI' of https://github.com/bcgov/…
dbarkowsky Feb 15, 2024
79d751a
Fixed on hold label
GrahamS-Quartech Feb 15, 2024
921aaf5
Merge branch 'PIMS-680-AdminUsersViewUI' of github.com:bcgov/PIMS int…
GrahamS-Quartech Feb 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions react-app/src/components/dialog/BaseDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
import React, { PropsWithChildren } from 'react';

export interface IBaseDialog extends PropsWithChildren {
open: boolean;
title: string;
actions: JSX.Element;
}

const BaseDialog = (props: IBaseDialog) => {
const { open, title, children, actions } = props;
return (
<Dialog PaperProps={{ sx: { padding: '2rem' } }} open={open}>
<DialogTitle variant="h2">{title}</DialogTitle>
<DialogContent>{children}</DialogContent>
<DialogActions sx={{ alignSelf: 'center' }}>{actions}</DialogActions>
</Dialog>
);
};

export default BaseDialog;
36 changes: 36 additions & 0 deletions react-app/src/components/dialog/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ButtonProps } from '@mui/material';
import BaseDialog from './BaseDialog';
import DualActionButtons from './DualActionButtons';
import React, { PropsWithChildren } from 'react';

interface IConfirmDialog extends PropsWithChildren {
title: string;
open: boolean;
onConfirm: () => void;
onCancel: () => void;
confirmButtonText?: string;
confirmButtonProps?: ButtonProps;
}

const ConfirmDialog = (props: IConfirmDialog) => {
const { title, open, onConfirm, onCancel, confirmButtonProps, confirmButtonText, children } = props;
return (
<BaseDialog
open={open}
title={title}
actions={
<DualActionButtons
onCancel={onCancel}
onConfirm={onConfirm}
cancelText={'Cancel'}
confirmButtonProps={confirmButtonProps}
confirmText={confirmButtonText ?? 'Confirm'}
/>
}
>
{children}
</BaseDialog>
);
};

export default ConfirmDialog;
40 changes: 40 additions & 0 deletions react-app/src/components/dialog/DeleteDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from 'react';
import { Box, TextField, Typography } from '@mui/material';
import ConfirmDialog from './ConfirmDialog';

interface IDeleteDialog {
open: boolean;
title: string;
message: string;
deleteText?: string;
onDelete: () => void;
onClose: () => void;
}

const DeleteDialog = (props: IDeleteDialog) => {
const { open, title, message, deleteText, onDelete, onClose } = props;
const [textFieldValue, setTextFieldValue] = useState('');
return (
<ConfirmDialog
open={open}
title={title}
onConfirm={onDelete}
onCancel={onClose}
confirmButtonText={deleteText}
GrahamS-Quartech marked this conversation as resolved.
Show resolved Hide resolved
confirmButtonProps={{ color: 'warning', disabled: textFieldValue.toLowerCase() != 'delete' }}
>
<Box display={'flex'} flexDirection={'column'} gap={'1rem'}>
<Typography>{message}</Typography>
<Typography>To confirm deletion, please type Delete below.</Typography>
<TextField
value={textFieldValue}
onChange={(event) => {
setTextFieldValue(event.target.value);
}}
/>
</Box>
</ConfirmDialog>
);
};

export default DeleteDialog;
35 changes: 35 additions & 0 deletions react-app/src/components/dialog/DualActionButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Box, Button, ButtonProps } from '@mui/material';
import React from 'react';

interface IDualActionButtons {
onCancel: () => void;
onConfirm: () => void;
confirmText: string;
cancelText: string;
confirmButtonProps?: ButtonProps;
}

const DualActionButtons = (props: IDualActionButtons) => {
const { onConfirm, onCancel, confirmText, cancelText, confirmButtonProps } = props;
return (
<Box display={'flex'} gap={'1rem'}>
<Button
variant="outlined"
style={{ fontWeight: 'bold', color: 'black', border: '1px solid lightgrey' }}
onClick={() => onCancel()}
>
{cancelText}
</Button>
<Button
sx={{ fontWeight: 'bold' }}
variant="contained"
onClick={() => onConfirm()}
{...confirmButtonProps}
>
{confirmText}
</Button>
</Box>
);
};

export default DualActionButtons;
68 changes: 68 additions & 0 deletions react-app/src/components/display/DataCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { columnNameFormatter, dateFormatter } from '@/utils/formatters';
import { Box, Button, CardContent, CardHeader, Divider, Typography } from '@mui/material';
import Card from '@mui/material/Card';
import React from 'react';

interface IDataCard<T> {
values: T;
title: string;
onEdit: () => void;
customFormatter?: (key: keyof T, value: any) => string | JSX.Element | undefined;
}

const DataCard = <T,>(props: IDataCard<T>) => {
const { values, title, customFormatter, onEdit } = props;

const defaultFormatter = (key: keyof T, val: any) => {
const customFormat = customFormatter?.(key, val);
if (customFormat) {
return customFormat;
}

if (val instanceof Date) {
return <Typography>{dateFormatter(val)}</Typography>;
}

return <Typography>{val}</Typography>;
};

return (
<Card variant="outlined" sx={{ padding: '2rem', minWidth: '34rem', backgroundColor: 'white' }}>
<CardHeader
titleTypographyProps={{ variant: 'h1' }}
sx={{
'.MuiCardHeader-action': {
alignSelf: 'center',
marginRight: '0px',
},
mb: '1rem',
}}
title={title}
action={
<Button
sx={{ minWidth: '50px', fontWeight: 'bold' }}
onClick={() => onEdit()}
color={'primary'}
>
Edit
</Button>
}
/>
<CardContent>
{Object.keys(values).map((key, idx) => (
<React.Fragment key={`card-data-fragment-${idx}-${key}`}>
<Box display={'flex'} flexDirection={'row'}>
<Typography width={'150px'} fontWeight={'bold'}>
{columnNameFormatter(key)}
</Typography>
{defaultFormatter(key as keyof T, values[key])}
</Box>
{idx < Object.keys(values).length - 1 && <Divider sx={{ mt: '1rem', mb: '1rem' }} />}
</React.Fragment>
))}
</CardContent>
</Card>
);
};

export default DataCard;
33 changes: 33 additions & 0 deletions react-app/src/components/form/AutocompleteField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { render } from '@testing-library/react';
import React from 'react';
import '@testing-library/jest-dom';
import AutocompleteFormField from './AutocompleteFormField';

jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
Controller: () => <></>,
useForm: () => ({
control: () => ({}),
handleSubmit: () => jest.fn(),
}),
useFormContext: () => ({
control: () => ({}),
}),
}));

describe('', () => {
it('should render', () => {
render(
<AutocompleteFormField
name={'test'}
label={'test'}
options={[
{
label: 'a',
value: 'a',
},
]}
/>,
);
});
});
5 changes: 3 additions & 2 deletions react-app/src/components/form/AutocompleteFormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IAutocompleteProps {
}

const AutocompleteFormField = (props: IAutocompleteProps) => {
const { control } = useFormContext();
const { control, getValues } = useFormContext();
const { name, options, label, sx } = props;
return (
<Controller
Expand All @@ -20,12 +20,13 @@ const AutocompleteFormField = (props: IAutocompleteProps) => {
render={({ field: { onChange } }) => (
<Autocomplete
freeSolo={false}
disablePortal
disablePortal={false}
id={`autocompleteinput-${label}`}
options={options}
sx={sx}
renderInput={(params) => <TextField {...params} label={label} />}
onChange={(_, data) => onChange(data.value)}
defaultValue={options.find((option) => option.value === getValues()[name])}
{...props}
/>
)}
Expand Down
Loading
Loading