Skip to content

Commit

Permalink
Merge branch 'main' into FI-2015-enable-get-request-fhir_operation
Browse files Browse the repository at this point in the history
  • Loading branch information
360dgries committed Oct 6, 2023
2 parents d77c0bf + 426ab2c commit 94600a2
Show file tree
Hide file tree
Showing 35 changed files with 314 additions and 156 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# 0.4.20
* FI-2077: Improve colors and contrasts for a11y by @AlyssaWang in
https://github.com/inferno-framework/inferno-core/pull/392
* Revert "FI-2035: Improve error handling for validator errors (#379)" by
@Jammjammjamm in https://github.com/inferno-framework/inferno-core/pull/393

# 0.4.19
* FI-2053: Fix inputs dialog overflow by @AlyssaWang in
https://github.com/inferno-framework/inferno-core/pull/382
* FI-2038: Prevent modal close on edit by @AlyssaWang in
https://github.com/inferno-framework/inferno-core/pull/383
* FI-2094: Improve tooltip a11y by @AlyssaWang in
https://github.com/inferno-framework/inferno-core/pull/386
* FI-2035: Improve error handling for validator errors by @dehall in
https://github.com/inferno-framework/inferno-core/pull/379
* FI-2070: Inferno Framework Documentation Advanced Test Features Information
Fix by @emichaud998 in
https://github.com/inferno-framework/inferno-core/pull/385
* FI-2041: Custom suites with no ids now throw standard error by @alisawallace
in https://github.com/inferno-framework/inferno-core/pull/387
* FI-2156: Dependabot updates by @Jammjammjamm in
https://github.com/inferno-framework/inferno-core/pull/390
* FI-2086: fix errors on webpack shutdown by @alisawallace in
https://github.com/inferno-framework/inferno-core/pull/389

# 0.4.18
* Fix a bug which could prevent some test results from appearing until the page
is reloaded.
Expand Down
26 changes: 12 additions & 14 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
PATH
remote: .
specs:
inferno_core (0.4.18)
activesupport (~> 6.1)
inferno_core (0.4.20)
activesupport (~> 6.1.7.5)
base62-rb (= 0.3.1)
blueprinter (= 0.25.2)
dotenv (~> 2.7)
Expand All @@ -19,7 +19,7 @@ PATH
oj (= 3.11.0)
pry
pry-byebug
puma (~> 5.3)
puma (~> 5.6.7)
rake (~> 13.0)
sequel (~> 5.42.0)
sidekiq (~> 6.5.6)
Expand All @@ -30,7 +30,7 @@ PATH
GEM
remote: https://rubygems.org/
specs:
activesupport (6.1.7.6)
activesupport (6.1.7.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
Expand Down Expand Up @@ -220,11 +220,9 @@ GEM
method_source (~> 1.0)
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
psych (5.1.0)
stringio
public_suffix (5.0.3)
puma (5.6.7)
pry (~> 0.13.0)
public_suffix (4.0.7)
puma (5.6.6)
nio4r (~> 2.0)
racc (1.7.1)
rack (2.2.8)
Expand Down Expand Up @@ -299,11 +297,10 @@ GEM
rexml
simplecov (~> 0.19)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
sqlite3 (1.6.6-arm64-darwin)
sqlite3 (1.6.6-x86_64-darwin)
sqlite3 (1.6.6-x86_64-linux)
stringio (3.0.8)
simplecov_json_formatter (0.1.3)
sqlite3 (1.6.3-arm64-darwin)
sqlite3 (1.6.3-x86_64-darwin)
sqlite3 (1.6.3-x86_64-linux)
strings (0.2.1)
strings-ansi (~> 0.2)
unicode-display_width (>= 1.5, < 3.0)
Expand Down Expand Up @@ -342,6 +339,7 @@ PLATFORMS
arm64-darwin-21
arm64-darwin-22
x86_64-darwin-20
x86_64-darwin-22
x86_64-linux

DEPENDENCIES
Expand Down
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
web: bundle exec puma
worker: bundle exec sidekiq -r ./worker.rb
webpack: npm run start
webpack: ./node_modules/.bin/webpack serve --config ./webpack.config.js --mode=development
19 changes: 11 additions & 8 deletions client/src/components/App/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { render } from '@testing-library/react';

import { vi } from 'vitest';
import { SnackbarProvider } from 'notistack';

Expand All @@ -21,16 +23,17 @@ describe('The App Root Component', () => {
vi.clearAllMocks();
});

it('sets Test Suite state on mount', () => {
it('sets Test Suite state on mount', async () => {
const getTestSuites = vi.spyOn(testSuitesApi, 'getTestSuites');
getTestSuites.mockResolvedValue(testSuites);

render(
<ThemeProvider>
<SnackbarProvider>
<App />
</SnackbarProvider>
</ThemeProvider>
await act(() =>
render(
<ThemeProvider>
<SnackbarProvider>
<App />
</SnackbarProvider>
</ThemeProvider>
)
);

expect(getTestSuites).toBeCalledTimes(1);
Expand Down
5 changes: 4 additions & 1 deletion client/src/components/InputsModal/FieldLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import React, { FC } from 'react';
import LockIcon from '@mui/icons-material/Lock';
import { TestInput } from '~/models/testSuiteModels';
import useStyles from './styles';
import RequiredInputWarning from './RequiredInputWarning';

export interface FieldLabelProps {
requirement: TestInput;
isMissingInput?: boolean;
}

const FieldLabel: FC<FieldLabelProps> = ({ requirement }) => {
const FieldLabel: FC<FieldLabelProps> = ({ requirement, isMissingInput = false }) => {
const { classes } = useStyles();

const fieldLabelText = requirement.title || requirement.name;
Expand All @@ -20,6 +22,7 @@ const FieldLabel: FC<FieldLabelProps> = ({ requirement }) => {

return (
<>
{isMissingInput && <RequiredInputWarning />}
{fieldLabelText}
{requiredLabel}
{lockedIcon}
Expand Down
17 changes: 15 additions & 2 deletions client/src/components/InputsModal/InputCheckboxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const InputCheckboxGroup: FC<InputCheckboxGroupProps> = ({
setInputsMap,
}) => {
const { classes } = useStyles();
const [hasBeenModified, setHasBeenModified] = React.useState(false);

const [values, setValues] = React.useState<CheckboxValues>(() => {
// Default values should be in form ['value'] where all values are checked
Expand Down Expand Up @@ -61,6 +62,9 @@ const InputCheckboxGroup: FC<InputCheckboxGroupProps> = ({
return startingValues as CheckboxValues;
});

const isMissingInput =
hasBeenModified && !requirement.optional && inputsMap.get(requirement.name) === '[]';

useEffect(() => {
// Make sure starting values get set in inputsMap
inputsMap.set(requirement.name, transformValuesToJSONArray(values));
Expand All @@ -75,6 +79,7 @@ const InputCheckboxGroup: FC<InputCheckboxGroupProps> = ({
inputsMap.set(requirement.name, transformValuesToJSONArray(newValues));
setInputsMap(new Map(inputsMap));
setValues(newValues);
setHasBeenModified(true);
};

// Convert map from item name to checked status back to array of checked values
Expand All @@ -93,11 +98,13 @@ const InputCheckboxGroup: FC<InputCheckboxGroupProps> = ({
component="fieldset"
id={`requirement${index}_input`}
disabled={requirement.locked}
required={!requirement.optional}
error={isMissingInput}
fullWidth
className={classes.inputField}
>
<FormLabel required={!requirement.optional} className={classes.inputLabel}>
<FieldLabel requirement={requirement} />
<FormLabel className={classes.inputLabel}>
<FieldLabel requirement={requirement} isMissingInput={isMissingInput} />
</FormLabel>
{requirement.description && (
<FormHelperText sx={{ mx: 0 }}>{requirement.description}</FormHelperText>
Expand All @@ -108,8 +115,14 @@ const InputCheckboxGroup: FC<InputCheckboxGroupProps> = ({
control={
<Checkbox
size="small"
color="secondary"
name={option.value}
checked={values[option.value as keyof CheckboxValues] || false}
onBlur={(e) => {
if (e.currentTarget === e.target) {
setHasBeenModified(true);
}
}}
onChange={handleChange}
/>
}
Expand Down
50 changes: 35 additions & 15 deletions client/src/components/InputsModal/InputOAuthCredentials.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { OAuthCredentials, TestInput } from '~/models/testSuiteModels';
import FieldLabel from './FieldLabel';
import useStyles from './styles';
import RequiredInputWarning from './RequiredInputWarning';

export interface InputOAuthCredentialsProps {
requirement: TestInput;
Expand All @@ -35,22 +36,20 @@ const InputOAuthCredentials: FC<InputOAuthCredentialsProps> = ({
setInputsMap,
}) => {
const { classes } = useStyles();
const [hasBeenModified, setHasBeenModified] = React.useState({});

// Convert OAuth string to Object
// OAuth should be an Object while in this component but should be converted to a string
// before being updated in the inputs map
const oAuthCredentials = (
inputsMap.get(requirement.name)
? JSON.parse(inputsMap.get(requirement.name) as string)
: {
access_token: '',
refresh_token: '',
expires_in: '',
client_id: '',
client_secret: '',
token_url: '',
}
) as OAuthCredentials;
const oAuthCredentials = {
access_token: '',
refresh_token: '',
expires_in: '',
client_id: '',
client_secret: '',
token_url: '',
...JSON.parse((inputsMap.get(requirement.name) as string) || '{}'),
} as OAuthCredentials;

const showRefreshDetails = !!oAuthCredentials.refresh_token;

Expand Down Expand Up @@ -91,23 +90,45 @@ const InputOAuthCredentials: FC<InputOAuthCredentialsProps> = ({
},
];

const getIsMissingInput = (field: InputOAuthField) => {
return (
hasBeenModified[field.name as keyof typeof hasBeenModified] &&
field.required &&
!oAuthCredentials[field.name as keyof OAuthCredentials]
);
};

const oAuthField = (field: InputOAuthField) => {
const fieldLabel = field.required
const fieldName = field.required
? `${(field.label || field.name) as string} (required)`
: field.label || field.name;

const fieldLabel = (
<>
{getIsMissingInput(field) && <RequiredInputWarning />}
{fieldName}
</>
);

return (
<ListItem disabled={field.locked} key={field.name}>
<TextField
disabled={requirement.locked}
required={field.required}
error={field.required && !oAuthCredentials[field.name as keyof OAuthCredentials]}
error={getIsMissingInput(field)}
id={`requirement${index}_${field.name}`}
label={fieldLabel}
helperText={requirement.description}
value={oAuthCredentials[field.name as keyof OAuthCredentials]}
className={classes.inputField}
variant="standard"
color="secondary"
fullWidth
onBlur={(e) => {
if (e.currentTarget === e.target) {
setHasBeenModified({ ...hasBeenModified, [field.name]: true });
}
}}
onChange={(event) => {
const value = event.target.value;
oAuthCredentials[field.name as keyof OAuthCredentials] = value;
Expand All @@ -128,7 +149,6 @@ const InputOAuthCredentials: FC<InputOAuthCredentialsProps> = ({
required={!requirement.optional}
disabled={requirement.locked}
className={classes.inputLabel}
shrink
>
<FieldLabel requirement={requirement} />
</InputLabel>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/InputsModal/InputRadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const InputRadioGroup: FC<InputRadioGroupProps> = ({
{requirement.options?.list_options?.map((option, i) => (
<FormControlLabel
value={option.value}
control={<Radio size="small" />}
control={<Radio size="small" color="secondary" />}
label={option.label}
key={`radio-button-${i}`}
/>
Expand Down
14 changes: 11 additions & 3 deletions client/src/components/InputsModal/InputTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,34 @@ const InputTextArea: FC<InputTextAreaProps> = ({ requirement, index, inputsMap,
const { classes } = useStyles();
const [hasBeenModified, setHasBeenModified] = React.useState(false);

const isMissingInput =
hasBeenModified && !requirement.optional && !inputsMap.get(requirement.name);

return (
<ListItem>
<TextField
disabled={requirement.locked}
required={!requirement.optional}
error={hasBeenModified && !requirement.optional && !inputsMap.get(requirement.name)}
error={isMissingInput}
id={`requirement${index}_input`}
className={classes.inputField}
variant="standard"
color="secondary"
fullWidth
label={<FieldLabel requirement={requirement} />}
label={<FieldLabel requirement={requirement} isMissingInput={isMissingInput} />}
helperText={requirement.description}
value={inputsMap.get(requirement.name)}
multiline
rows={4}
onBlur={(e) => {
if (e.currentTarget === e.target) {
setHasBeenModified(true);
}
}}
onChange={(event) => {
const value = event.target.value;
inputsMap.set(requirement.name, value);
setInputsMap(new Map(inputsMap));
setHasBeenModified(true);
}}
FormHelperTextProps={{
sx: { '&.Mui-disabled': { color: lightTheme.palette.common.grayDark } },
Expand Down
14 changes: 11 additions & 3 deletions client/src/components/InputsModal/InputTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,32 @@ const InputTextField: FC<InputTextFieldProps> = ({
const { classes } = useStyles();
const [hasBeenModified, setHasBeenModified] = React.useState(false);

const isMissingInput =
hasBeenModified && !requirement.optional && !inputsMap.get(requirement.name);

return (
<ListItem>
<TextField
disabled={requirement.locked}
required={!requirement.optional}
error={hasBeenModified && !requirement.optional && !inputsMap.get(requirement.name)}
error={isMissingInput}
id={`requirement${index}_input`}
className={classes.inputField}
variant="standard"
color="secondary"
fullWidth
label={<FieldLabel requirement={requirement} />}
label={<FieldLabel requirement={requirement} isMissingInput={isMissingInput} />}
helperText={requirement.description}
value={inputsMap.get(requirement.name)}
onBlur={(e) => {
if (e.currentTarget === e.target) {
setHasBeenModified(true);
}
}}
onChange={(event) => {
const value = event.target.value;
inputsMap.set(requirement.name, value);
setInputsMap(new Map(inputsMap));
setHasBeenModified(true);
}}
InputLabelProps={{ shrink: true }}
FormHelperTextProps={{
Expand Down
Loading

0 comments on commit 94600a2

Please sign in to comment.