Skip to content

Commit bf8074c

Browse files
authored
[OGUI-1738] Adds to the form the show of difference Highlighting and reset to default value button(#3214)
Implemented difference highlighting by displaying default value below edited fields and introducing a button to reset to default on the right side of the input
1 parent 35f8d32 commit bf8074c

File tree

13 files changed

+232
-8
lines changed

13 files changed

+232
-8
lines changed

Configuration/webapp/app/components/form/Form.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import { useCallback, useState, type FC, type PropsWithChildren } from 'react';
1616
import Accordion from '@mui/material/Accordion';
1717
import AccordionDetails from '@mui/material/AccordionDetails';
1818
import Stack from '@mui/material/Stack';
19-
import { Widget } from './Widget';
20-
import { AccordionHeader } from './AccordionHeader';
19+
import { Widget } from './components/Widget';
20+
import { AccordionHeader } from './components/AccordionHeader';
2121
import { Typography } from '@mui/material';
2222
import type { Control } from 'react-hook-form';
2323
import { type InputsType } from '~/routes/configuration';

Configuration/webapp/app/components/form/AccordionHeader.tsx renamed to Configuration/webapp/app/components/form/components/AccordionHeader.tsx

File renamed without changes.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { Box, Collapse, Typography } from '@mui/material';
16+
import type { ReactNode } from 'react';
17+
18+
/**
19+
* Previous Value Section component.
20+
* @param {PreviousValueSectionProps} props - The props of the previous value section.
21+
* @param {string | number | boolean} props.value - The value of the previous value.
22+
* @param {boolean} props.isDirty - Whether the form is dirty.
23+
* @returns {ReactElement} The previous value section component.
24+
*/
25+
export const PreviousValueSection = ({
26+
value,
27+
isDirty,
28+
}: {
29+
value: string | number | boolean;
30+
isDirty: boolean;
31+
}): ReactNode => (
32+
<Collapse in={isDirty} timeout="auto">
33+
<Box
34+
sx={{
35+
display: 'flex',
36+
flexDirection: 'row',
37+
gap: 1,
38+
}}
39+
>
40+
<Typography variant="caption" fontWeight="bold" color="secondary">
41+
Previous Value:
42+
</Typography>
43+
<Typography variant="caption">{JSON.stringify(value, null, 2)}</Typography>
44+
</Box>
45+
</Collapse>
46+
);

Configuration/webapp/app/components/form/Widget.tsx renamed to Configuration/webapp/app/components/form/components/Widget.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { type FC, type PropsWithChildren, type ReactElement } from 'react';
1616
import { useFormState, type Control } from 'react-hook-form';
1717
import type { InputsType } from '~/routes/configuration';
1818
import { FormTextInput } from './widgets/FormTextInput';
19-
import { FormNumberInput } from './widgets/FormNumberInput';
2019
import { FormToggleInput } from './widgets/FormToggleInput';
2120

2221
export interface WidgetProps extends PropsWithChildren {
@@ -43,7 +42,7 @@ export const Widget: FC<WidgetProps> = ({ type, ...rest }): ReactElement => {
4342
case 'string':
4443
return <FormTextInput {...rest} isDirty={Boolean(isDirty)} />;
4544
case 'number':
46-
return <FormNumberInput {...rest} isDirty={Boolean(isDirty)} />;
45+
return <FormTextInput {...rest} isDirty={Boolean(isDirty)} type="number" />;
4746
case 'boolean':
4847
return <FormToggleInput {...rest} isDirty={Boolean(isDirty)} />;
4948
case 'array':
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { IconButton, type IconButtonProps } from '@mui/material';
16+
import CancelIcon from '@mui/icons-material/Cancel';
17+
18+
/**
19+
* Remove button component.
20+
* @param {IconButtonProps} props - The props of the icon button.
21+
* @param {() => void} props.onClick - The callback to click the remove button.
22+
* @returns {ReactElement} The remove button component.
23+
*/
24+
export const RemoveButton = (props: IconButtonProps) => (
25+
<IconButton color="primary" {...props}>
26+
<CancelIcon />
27+
</IconButton>
28+
);

Configuration/webapp/app/components/form/SaveButton.tsx renamed to Configuration/webapp/app/components/form/components/buttons/SaveButton.tsx

File renamed without changes.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { TextField } from '@mui/material';
16+
import { type ReactElement } from 'react';
17+
import { Controller } from 'react-hook-form';
18+
import type { WidgetProps } from '../Widget';
19+
import { PreviousValueSection } from '../PreviousValueSection';
20+
import { RemoveButton } from '../buttons/RemoveButton';
21+
22+
interface FormTextInputProps extends Omit<WidgetProps, 'type' | 'value'> {
23+
isDirty: boolean;
24+
type?: 'text' | 'number';
25+
}
26+
27+
/**
28+
* Text input widget for the form.
29+
* @param {FormTextInputProps} props - The props of the widget.
30+
* @param {string} props.sectionTitle - The section title of the widget.
31+
* @param {string} props.label - The title of the widget.
32+
* @param {Control<InputsType>} props.control - The control of the widget.
33+
* @param {boolean} props.isDirty - Whether the widget is dirty.
34+
* @param {string} props.type - The type of the input.
35+
* @returns {ReactElement} The text input widget.
36+
*/
37+
export const FormTextInput = ({
38+
sectionPrefix,
39+
label,
40+
control,
41+
isDirty,
42+
type = 'text',
43+
}: FormTextInputProps): ReactElement => (
44+
<Controller
45+
name={sectionPrefix}
46+
control={control}
47+
render={({ field, fieldState: { error }, formState: { defaultValues } }) => (
48+
<TextField
49+
type={type}
50+
label={label}
51+
{...field}
52+
error={Boolean(error)}
53+
color={isDirty ? 'secondary' : 'primary'}
54+
focused={isDirty}
55+
slotProps={{
56+
input: {
57+
endAdornment: isDirty ? (
58+
<RemoveButton
59+
onClick={() => {
60+
field.onChange(defaultValues?.[sectionPrefix] ?? '');
61+
}}
62+
color="secondary"
63+
/>
64+
) : undefined,
65+
},
66+
}}
67+
helperText={
68+
<PreviousValueSection value={defaultValues?.[sectionPrefix] ?? ''} isDirty={isDirty} />
69+
}
70+
/>
71+
)}
72+
/>
73+
);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { FormControlLabel, styled, Switch, switchClasses } from '@mui/material';
16+
import { Controller } from 'react-hook-form';
17+
import type { ReactElement } from 'react';
18+
import type { WidgetProps } from '../Widget';
19+
20+
interface FormToggleInputProps extends Omit<WidgetProps, 'type' | 'value'> {
21+
isDirty: boolean;
22+
}
23+
24+
const StyledSwitch = styled(Switch)<{ isDirty: boolean }>(
25+
({ isDirty, theme }) => `
26+
& .${switchClasses.switchBase} {
27+
${isDirty ? `color: ${theme.palette.secondary.main}` : ''}
28+
}
29+
& .${switchClasses.track} {
30+
${isDirty ? `background-color: ${theme.palette.secondary.main}` : ''}
31+
}
32+
`,
33+
);
34+
35+
export const FormToggleInput = ({
36+
sectionPrefix,
37+
label,
38+
control,
39+
isDirty,
40+
}: FormToggleInputProps): ReactElement => (
41+
<Controller
42+
name={sectionPrefix}
43+
control={control}
44+
render={({ field }) => (
45+
<FormControlLabel
46+
control={
47+
<StyledSwitch
48+
{...field}
49+
checked={Boolean(field.value)}
50+
onChange={field.onChange}
51+
isDirty={isDirty}
52+
/>
53+
}
54+
label={label}
55+
/>
56+
)}
57+
/>
58+
);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
export const useInputCommonProps = () => ({
16+
color: 'primary',
17+
focused: false,
18+
error: false,
19+
helperText: '',
20+
});

Configuration/webapp/app/components/form/widgets/FormNumberInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface FormNumberInputProps extends Omit<WidgetProps, 'type' | 'value'> {
1717
}
1818

1919
import { Controller } from 'react-hook-form';
20-
import type { WidgetProps } from '../Widget';
20+
import type { WidgetProps } from '../components/Widget';
2121
import { TextField } from '@mui/material';
2222
import type { ReactElement } from 'react';
2323

0 commit comments

Comments
 (0)