@axinom/mosaic-ui 0.39.1-feat-gs.2 → 0.40.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/components/FormStation/Create/Create.d.ts +1 -1
  2. package/dist/components/FormStation/Create/Create.d.ts.map +1 -1
  3. package/dist/components/FormStation/Details/Details.d.ts +2 -2
  4. package/dist/components/FormStation/Details/Details.d.ts.map +1 -1
  5. package/dist/components/FormStation/FormStation.d.ts +15 -8
  6. package/dist/components/FormStation/FormStation.d.ts.map +1 -1
  7. package/dist/components/FormStation/FormStation.models.d.ts +3 -17
  8. package/dist/components/FormStation/FormStation.models.d.ts.map +1 -1
  9. package/dist/components/FormStation/StationErrorStateType.d.ts +5 -0
  10. package/dist/components/FormStation/StationErrorStateType.d.ts.map +1 -0
  11. package/dist/components/FormStation/index.d.ts +1 -1
  12. package/dist/components/FormStation/index.d.ts.map +1 -1
  13. package/dist/components/FormStation/{helpers/useValidationError.d.ts → useValidationError.d.ts} +1 -1
  14. package/dist/components/FormStation/useValidationError.d.ts.map +1 -0
  15. package/dist/components/Utils/Postgraphile/getArrayDiff.d.ts.map +1 -1
  16. package/dist/components/Utils/Postgraphile/getFormDiff.d.ts.map +1 -1
  17. package/dist/helpers/testing.d.ts +1 -4
  18. package/dist/helpers/testing.d.ts.map +1 -1
  19. package/dist/index.es.js +4 -4
  20. package/dist/index.es.js.map +1 -1
  21. package/dist/index.js +4 -4
  22. package/dist/index.js.map +1 -1
  23. package/package.json +4 -3
  24. package/src/components/Actions/Action/Action.scss +0 -1
  25. package/src/components/FormElements/Tags/Tags.tsx +3 -3
  26. package/src/components/FormStation/Create/Create.stories.tsx +9 -1
  27. package/src/components/FormStation/Create/Create.tsx +1 -4
  28. package/src/components/FormStation/Details/Details.tsx +2 -5
  29. package/src/components/FormStation/FormStation.models.ts +3 -29
  30. package/src/components/FormStation/FormStation.scss +70 -0
  31. package/src/components/FormStation/FormStation.spec.tsx +1 -2
  32. package/src/components/FormStation/FormStation.stories.tsx +1 -20
  33. package/src/components/FormStation/FormStation.tsx +403 -68
  34. package/src/components/FormStation/StationErrorStateType.tsx +5 -0
  35. package/src/components/FormStation/index.ts +5 -1
  36. package/src/components/FormStation/{helpers/useValidationError.tsx → useValidationError.tsx} +1 -1
  37. package/src/components/Utils/Postgraphile/getArrayDiff.ts +6 -7
  38. package/src/components/Utils/Postgraphile/getFormDiff.ts +1 -2
  39. package/dist/components/FormStation/FormContentWrapper/FormContentWrapper.d.ts +0 -11
  40. package/dist/components/FormStation/FormContentWrapper/FormContentWrapper.d.ts.map +0 -1
  41. package/dist/components/FormStation/FormStationActions/FormStationActions.d.ts +0 -21
  42. package/dist/components/FormStation/FormStationActions/FormStationActions.d.ts.map +0 -1
  43. package/dist/components/FormStation/FormStationContext/FormStationContext.d.ts +0 -13
  44. package/dist/components/FormStation/FormStationContext/FormStationContext.d.ts.map +0 -1
  45. package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts +0 -10
  46. package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts.map +0 -1
  47. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts +0 -12
  48. package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +0 -1
  49. package/dist/components/FormStation/helpers/mergeData.d.ts +0 -7
  50. package/dist/components/FormStation/helpers/mergeData.d.ts.map +0 -1
  51. package/dist/components/FormStation/helpers/useChangeSets.d.ts +0 -12
  52. package/dist/components/FormStation/helpers/useChangeSets.d.ts.map +0 -1
  53. package/dist/components/FormStation/helpers/useDataProvider.d.ts +0 -14
  54. package/dist/components/FormStation/helpers/useDataProvider.d.ts.map +0 -1
  55. package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts +0 -7
  56. package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts.map +0 -1
  57. package/dist/components/FormStation/helpers/useUndo.d.ts +0 -6
  58. package/dist/components/FormStation/helpers/useUndo.d.ts.map +0 -1
  59. package/dist/components/FormStation/helpers/useValidationError.d.ts.map +0 -1
  60. package/src/components/FormStation/FormContentWrapper/FormContentWrapper.scss +0 -66
  61. package/src/components/FormStation/FormContentWrapper/FormContentWrapper.tsx +0 -77
  62. package/src/components/FormStation/FormStationActions/FormStationActions.tsx +0 -132
  63. package/src/components/FormStation/FormStationContext/FormStationContext.ts +0 -22
  64. package/src/components/FormStation/FormStationContext/FormStationContextProvider.tsx +0 -86
  65. package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +0 -85
  66. package/src/components/FormStation/helpers/mergeData.ts +0 -26
  67. package/src/components/FormStation/helpers/useChangeSets.ts +0 -70
  68. package/src/components/FormStation/helpers/useDataProvider.ts +0 -169
  69. package/src/components/FormStation/helpers/useDebouncedFormikValues.ts +0 -22
  70. package/src/components/FormStation/helpers/useUndo.ts +0 -43
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormStationContextProvider.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/FormStationContext/FormStationContextProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAqB,MAAM,OAAO,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAMtC,UAAU,+BAA+B,CAAC,OAAO,SAAS,IAAI;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;CAC7D;AAED,eAAO,MAAM,0BAA0B,yJAOnC,WAiEH,CAAC"}
@@ -1,12 +0,0 @@
1
- import React from 'react';
2
- import { PageHeaderProps } from '../../PageHeader';
3
- /**
4
- * Handles showRefresh and cancel buttons based on form states
5
- */
6
- export declare const FormStationHeader: React.FC<Omit<PageHeaderProps, 'title'> & {
7
- titleProperty?: string;
8
- defaultTitle?: string;
9
- cancelNavigationUrl?: string;
10
- isFormSubmitting?: boolean;
11
- }>;
12
- //# sourceMappingURL=FormStationHeader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormStationHeader.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/FormStationHeader/FormStationHeader.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAGL,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAG1B;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CACtC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,GAAG;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAgEF,CAAC"}
@@ -1,7 +0,0 @@
1
- import { Data } from '../../../types';
2
- export declare const mergeData: <TValues extends Data>(initialValues: TValues, currentValues: TValues, updatedValues?: Partial<TValues> | undefined) => {
3
- newInitialValues: TValues;
4
- newCurrentValues: TValues;
5
- shouldUpdateCurrentValues: boolean;
6
- };
7
- //# sourceMappingURL=mergeData.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mergeData.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/mergeData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGtC,eAAO,MAAM,SAAS;;;+BAOO,OAAO;CAenC,CAAC"}
@@ -1,12 +0,0 @@
1
- export interface ChangeSet<T> {
2
- prev: Partial<T>;
3
- next: Partial<T>;
4
- }
5
- export declare const useChangeSets: <T>(initialValues: T) => {
6
- changeSets: ChangeSet<T>[];
7
- push: (value: ChangeSet<T>) => number;
8
- pop: () => ChangeSet<T> | undefined;
9
- clear: () => Partial<T>;
10
- getAggregatedChanges: () => T;
11
- };
12
- //# sourceMappingURL=useChangeSets.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useChangeSets.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/useChangeSets.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAClB;AAED,eAAO,MAAM,aAAa;;mCAIO,MAAM;;;;CA0DtC,CAAC"}
@@ -1,14 +0,0 @@
1
- import { FormikHelpers } from 'formik';
2
- import { Dispatch, SetStateAction } from 'react';
3
- import { Data } from '../../../types';
4
- import type { InitialFormData, SaveDataFunction, StationErrorStateType } from '../FormStation.models';
5
- export type FormStationDataProvider = <TValues extends Data, TSubmitResponse>(initialData: InitialFormData<TValues>, saveData: SaveDataFunction<TValues, TSubmitResponse>, currentDataRef: React.MutableRefObject<TValues>) => {
6
- onSubmit: (values: TValues, formikHelpers: FormikHelpers<TValues>, initialFormData?: InitialFormData<TValues>) => Promise<TSubmitResponse> | void;
7
- stationError?: StationErrorStateType;
8
- setStationError: Dispatch<SetStateAction<StationErrorStateType | undefined>>;
9
- isFormSubmitting: boolean;
10
- lastSubmittedResponse: React.MutableRefObject<TSubmitResponse | undefined>;
11
- initialValues: TValues | null | undefined;
12
- };
13
- export declare const useDataProvider: FormStationDataProvider;
14
- //# sourceMappingURL=useDataProvider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDataProvider.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/useDataProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EACL,QAAQ,EACR,cAAc,EAKf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAItC,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAG/B,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,SAAS,IAAI,EAAE,eAAe,EAC1E,WAAW,EAAE,eAAe,CAAC,OAAO,CAAC,EACrC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,EACpD,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,KAC5C;IACH,QAAQ,EAAE,CACR,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,EACrC,eAAe,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,KACvC,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;IACrC,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,eAAe,EAAE,QAAQ,CAAC,cAAc,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC,CAAC;IAC7E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,KAAK,CAAC,gBAAgB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IAC3E,aAAa,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,uBAkI7B,CAAC"}
@@ -1,7 +0,0 @@
1
- import { FormikContextType } from 'formik';
2
- export declare const useDebouncedFormikValues: <TValues>(autosaveDelay?: number) => {
3
- debouncedValues: TValues;
4
- } & import("formik").FormikSharedConfig<{}> & import("formik").FormikState<TValues> & import("formik").FormikHelpers<TValues> & import("formik").FormikHandlers & import("formik").FormikComputedProps<TValues> & import("formik").FormikRegistration & {
5
- submitForm: () => Promise<any>;
6
- } & Pick<import("formik").FormikConfig<TValues>, "validate" | "validationSchema">;
7
- //# sourceMappingURL=useDebouncedFormikValues.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDebouncedFormikValues.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/useDebouncedFormikValues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,QAAQ,CAAC;AAI7D,eAAO,MAAM,wBAAwB,4BACnB,MAAM;;;;iFAgBvB,CAAC"}
@@ -1,6 +0,0 @@
1
- export declare const useUndo: () => {
2
- undoOnce: () => void;
3
- undoAll: () => void;
4
- showUndo: boolean;
5
- };
6
- //# sourceMappingURL=useUndo.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useUndo.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/useUndo.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,OAAO;cACR,MAAM,IAAI;aACX,MAAM,IAAI;cACT,OAAO;CAmClB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useValidationError.d.ts","sourceRoot":"","sources":["../../../../src/components/FormStation/helpers/useValidationError.tsx"],"names":[],"mappings":"AACA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAenE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,qBAAqB,GAAG,SAAS,EAC/C,eAAe,EAAE,KAAK,CAAC,QAAQ,CAC7B,KAAK,CAAC,cAAc,CAAC,qBAAqB,GAAG,SAAS,CAAC,CACxD,GACA;IACD,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC;CAChC,CAyBA"}
@@ -1,66 +0,0 @@
1
- @import '../../../styles/common.scss';
2
-
3
- // Extend all components, except PageHeader, to the bottom
4
- // Enable scrolling children
5
- .children {
6
- overflow-y: auto;
7
- display: grid;
8
- grid-template-columns: 1fr auto;
9
-
10
- overflow: hidden;
11
-
12
- .main {
13
- display: grid;
14
- grid: 1fr / minmax(740px, 1fr) auto;
15
-
16
- overflow-y: auto;
17
- scrollbar-width: thin; //for Firefox only
18
-
19
- .formWrapper {
20
- display: grid;
21
- grid: 1fr / 1fr;
22
-
23
- &.hasMessage {
24
- grid: min-content 1fr / 1fr;
25
- }
26
- }
27
- }
28
-
29
- //Custom scrollbar for Chrome, Safari and Edge
30
- ::-webkit-scrollbar {
31
- width: var(--scrollbar-size, $scrollbar-size);
32
- height: var(--scrollbar-size, $scrollbar-size);
33
- }
34
- ::-webkit-scrollbar-track {
35
- background: var(--scrollbar-track-color, $scrollbar-track-color);
36
- }
37
-
38
- ::-webkit-scrollbar-thumb {
39
- background: var(--scrollbar-thumb-color, $scrollbar-thumb-color);
40
- }
41
-
42
- ::-webkit-scrollbar-thumb:hover {
43
- background: var(
44
- --scrollbar-thumb-hover-color,
45
- $scrollbar-thumb-hover-color
46
- );
47
- }
48
-
49
- ::-webkit-scrollbar-corner {
50
- background: var(--scrollbar-corner-color, $scrollbar-corner-color);
51
- }
52
-
53
- .formContainer {
54
- padding: 30px;
55
- }
56
-
57
- .loadingError {
58
- display: grid;
59
- grid: 1fr / 1fr;
60
- }
61
- }
62
-
63
- .errorMessage {
64
- grid-row: 2 / 3;
65
- grid-column: 1 / -1;
66
- }
@@ -1,77 +0,0 @@
1
- import clsx from 'clsx';
2
- import { Form } from 'formik';
3
- import React from 'react';
4
- import type { Data } from '../../../types';
5
- import { MessageBar } from '../../MessageBar';
6
- import type { FormStationProps } from '../FormStation';
7
- import type { StationErrorStateType } from '../FormStation.models';
8
- import classes from './FormContentWrapper.scss';
9
-
10
- interface FormContentWrapperProps
11
- extends Pick<
12
- FormStationProps<Data>,
13
- 'stationMessage' | 'edgeToEdgeContent' | 'infoPanel' | 'initialData'
14
- > {
15
- stationError?: StationErrorStateType;
16
- setStationError: React.Dispatch<
17
- React.SetStateAction<StationErrorStateType | undefined>
18
- >;
19
- }
20
-
21
- export const FormContentWrapper: React.FC<FormContentWrapperProps> = ({
22
- stationMessage,
23
- edgeToEdgeContent,
24
- infoPanel,
25
- initialData,
26
- stationError,
27
- setStationError,
28
- children,
29
- }) => (
30
- <>
31
- {stationError && (
32
- <div className={classes.errorMessage}>
33
- <MessageBar
34
- type="error"
35
- title={String(stationError.title)}
36
- onClose={() => setStationError(undefined)}
37
- >
38
- {stationError?.body}
39
- </MessageBar>
40
- </div>
41
- )}
42
- {initialData.loading ? (
43
- // TODO: Loading skeleton of the page
44
- <></>
45
- ) : initialData.error ||
46
- initialData.data === null ||
47
- initialData.entityNotFound ? (
48
- // Error on loading - we can't show the form
49
- <div className={classes.loadingError}></div>
50
- ) : (
51
- <div className={classes.children}>
52
- <div className={classes.main}>
53
- <div
54
- className={clsx(classes.formWrapper, {
55
- [classes.hasMessage]: stationMessage,
56
- })}
57
- >
58
- {stationMessage && <MessageBar {...stationMessage} />}
59
- <div
60
- className={clsx({
61
- [classes.formContainer]: !edgeToEdgeContent,
62
- })}
63
- >
64
- <Form>
65
- {children}
66
- {/* Adding a invisible text input here to prevent the browser from submitting on "Enter" when there is only a single text input field in the form
67
- See: https://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2 */}
68
- <input type="text" style={{ display: 'none' }} />
69
- </Form>
70
- </div>
71
- </div>
72
- {infoPanel}
73
- </div>
74
- </div>
75
- )}
76
- </>
77
- );
@@ -1,132 +0,0 @@
1
- import { useFormikContext } from 'formik';
2
- import React, { PropsWithChildren, useMemo } from 'react';
3
- import { OptionalObjectSchema } from 'yup/lib/object';
4
- import { ErrorTypeToStationError } from '../../../utils/ErrorTypeToStationError';
5
- import { Actions, ActionsProps } from '../../Actions';
6
- import { isNavigationAction } from '../../Actions/Action/Action';
7
- import { ErrorType, StationError } from '../../models';
8
- import { FormActionData, ObjectSchemaDefinition } from '../FormStation.models';
9
-
10
- interface FormActionProps<T, Y> extends Omit<ActionsProps, 'actions'> {
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- validationSchema?: OptionalObjectSchema<ObjectSchemaDefinition<any>>;
13
- actions?: FormActionData<T, Y>[];
14
- setStationError: (error: StationError) => void;
15
- setValidationError: () => void;
16
- submitResponse?: React.MutableRefObject<Y | undefined>;
17
- alwaysSubmitBeforeAction?: boolean;
18
- className?: string;
19
- isFormSubmitting?: boolean;
20
- }
21
-
22
- /**
23
- * Saves the form before the action is performed.
24
- */
25
- export const FormStationActions = <T, Y>(
26
- props: PropsWithChildren<FormActionProps<T, Y>>,
27
- ): JSX.Element => {
28
- const {
29
- actions,
30
- validationSchema,
31
- setStationError,
32
- submitResponse,
33
- alwaysSubmitBeforeAction,
34
- className = '',
35
- } = props;
36
- const {
37
- submitForm,
38
- resetForm,
39
- values,
40
- validateForm,
41
- isValid,
42
- dirty,
43
- isSubmitting,
44
- } = useFormikContext<T>();
45
-
46
- const updatedActions = useMemo(() => {
47
- return actions?.map((action) => {
48
- const { onActionSelected } = action;
49
-
50
- return isNavigationAction(action)
51
- ? action
52
- : {
53
- ...action,
54
- isDisabled: action.isDisabled || isSubmitting,
55
- onActionSelected: () => {
56
- (async () => {
57
- //TODO: Busy indicator (disable form?)
58
- if (dirty || alwaysSubmitBeforeAction) {
59
- // We can't rely on 'isValid' alone, since that will only evaluate if the form is touched or 'submitForm' is called.
60
- // On a create station though the from might not be touched but still being invalid.
61
- // Also the validation on submitForm in here will not help, since the value of isValid is already bound to that method and will not change
62
- // anymore while this method executes - even if it changes on the context!
63
- if (
64
- !isValid ||
65
- (await validationSchema?.isValid(values)) === false
66
- ) {
67
- // eslint-disable-next-line no-console
68
- console.log('form invalid, action not performed');
69
- // Making sure that the fields will actually show the validation messages (they won't if the from was not touched yet - e.g. on a create station)
70
- validateForm();
71
- return;
72
- }
73
-
74
- try {
75
- await submitForm();
76
-
77
- // Committing the changed values to the form to get the current version as the new "reset" state.
78
- resetForm({ values });
79
- } catch (error) {
80
- // we will abort the action if saving is not successful
81
- // a station error is already set by the "onSubmit"
82
- return;
83
- }
84
- }
85
-
86
- try {
87
- const result =
88
- onActionSelected &&
89
- (await onActionSelected({
90
- values,
91
- submitResponse: submitResponse?.current,
92
- }));
93
- if (result !== undefined) {
94
- setStationError(
95
- ErrorTypeToStationError(
96
- result,
97
- 'An error occurred when trying to execute the action.',
98
- ),
99
- );
100
- }
101
- } catch (error) {
102
- const stationError = ErrorTypeToStationError(
103
- error as ErrorType,
104
- 'An error occurred when trying to execute the action.',
105
- );
106
- setStationError(stationError);
107
- }
108
- })();
109
- },
110
- };
111
- });
112
- }, [
113
- actions,
114
- alwaysSubmitBeforeAction,
115
- dirty,
116
- isSubmitting,
117
- isValid,
118
- resetForm,
119
- setStationError,
120
- submitForm,
121
- submitResponse,
122
- validateForm,
123
- validationSchema,
124
- values,
125
- ]);
126
-
127
- return (
128
- <div className={className}>
129
- <Actions actions={updatedActions} />
130
- </div>
131
- );
132
- };
@@ -1,22 +0,0 @@
1
- import type { FormikValues } from 'formik';
2
- import React from 'react';
3
- import { noop } from '../../../helpers/utils';
4
- import { ChangeSet } from '../helpers/useChangeSets';
5
-
6
- export interface FormStationContextType {
7
- changeSets: ChangeSet<FormikValues>[];
8
- pushChangeSet: (value: never) => void;
9
- popChangeSet: () => ChangeSet<FormikValues> | undefined;
10
- clearChangeSets: () => FormikValues;
11
- lastUndoneValue: React.MutableRefObject<FormikValues>;
12
- autosave: boolean;
13
- }
14
-
15
- export const FormStationContext = React.createContext<FormStationContextType>({
16
- changeSets: [],
17
- pushChangeSet: noop,
18
- popChangeSet: () => ({ prev: {}, next: {} }),
19
- clearChangeSets: () => ({}),
20
- lastUndoneValue: { current: {} },
21
- autosave: false,
22
- });
@@ -1,86 +0,0 @@
1
- import React, { PropsWithChildren, useEffect, useRef } from 'react';
2
- import { Data } from '../../../types';
3
- import { getFormDiff } from '../../Utils';
4
- import { useChangeSets } from '../helpers/useChangeSets';
5
- import { useDebouncedFormikValues } from '../helpers/useDebouncedFormikValues';
6
- import { FormStationContext } from './FormStationContext';
7
-
8
- interface FormStationContextProviderProps<TValues extends Data> {
9
- autosave?: boolean;
10
- autosaveDelay?: number;
11
- currentValuesRef?: React.MutableRefObject<Partial<TValues>>;
12
- }
13
-
14
- export const FormStationContextProvider = <TValues extends Data>({
15
- children,
16
- autosave = false,
17
- autosaveDelay,
18
- currentValuesRef,
19
- }: PropsWithChildren<
20
- FormStationContextProviderProps<TValues>
21
- >): JSX.Element => {
22
- const {
23
- debouncedValues,
24
- initialValues,
25
- dirty,
26
- isSubmitting,
27
- submitForm,
28
- isValid,
29
- values,
30
- } = useDebouncedFormikValues<TValues>(autosaveDelay);
31
-
32
- if (currentValuesRef) {
33
- currentValuesRef.current = values;
34
- }
35
-
36
- // We use this to track the last value that was undone so we can avoid pushing it to the changeSets
37
- const lastUndoneValue = useRef<Partial<TValues>>({});
38
-
39
- const {
40
- changeSets,
41
- push: pushChangeSet,
42
- pop: popChangeSet,
43
- clear: clearChangeSets,
44
- getAggregatedChanges,
45
- } = useChangeSets(initialValues);
46
-
47
- useEffect(() => {
48
- if (dirty && !isSubmitting && debouncedValues !== lastUndoneValue.current) {
49
- let previousValues = initialValues;
50
-
51
- if (!autosave) {
52
- previousValues = getAggregatedChanges();
53
- }
54
-
55
- const next = getFormDiff(debouncedValues, previousValues);
56
- const prev: Partial<TValues> = {};
57
-
58
- Object.keys(next).forEach((key) => {
59
- prev[key as keyof TValues] = previousValues[key];
60
- });
61
-
62
- pushChangeSet({ next, prev });
63
-
64
- if (autosave && isValid) {
65
- submitForm();
66
- }
67
- }
68
- // This effect should only be run when we have new debounced values. This is done to simplify the logic.
69
- // eslint-disable-next-line react-hooks/exhaustive-deps
70
- }, [debouncedValues]);
71
-
72
- return (
73
- <FormStationContext.Provider
74
- value={{
75
- changeSets,
76
- pushChangeSet,
77
- popChangeSet,
78
- clearChangeSets,
79
- lastUndoneValue,
80
- autosave,
81
- }}
82
- >
83
- {children}
84
- </FormStationContext.Provider>
85
- );
86
- };
@@ -1,85 +0,0 @@
1
- import { FormikValues, useFormikContext } from 'formik';
2
- import React from 'react';
3
- import { useHistory } from 'react-router-dom';
4
- import { IconName } from '../../Icons';
5
- import {
6
- PageHeader,
7
- PageHeaderActionType,
8
- PageHeaderProps,
9
- } from '../../PageHeader';
10
- import { useUndo } from '../helpers/useUndo';
11
-
12
- /**
13
- * Handles showRefresh and cancel buttons based on form states
14
- */
15
- export const FormStationHeader: React.FC<
16
- Omit<PageHeaderProps, 'title'> & {
17
- titleProperty?: string;
18
- defaultTitle?: string;
19
- cancelNavigationUrl?: string;
20
- isFormSubmitting?: boolean;
21
- }
22
- > = ({
23
- titleProperty,
24
- defaultTitle,
25
- subtitle,
26
- cancelNavigationUrl,
27
- isFormSubmitting,
28
- }) => {
29
- const { values, resetForm } = useFormikContext<FormikValues>();
30
-
31
- const history = useHistory();
32
-
33
- const { undoOnce, undoAll, showUndo } = useUndo();
34
-
35
- const title =
36
- titleProperty && values[titleProperty] !== ''
37
- ? values[titleProperty]
38
- : defaultTitle ?? '';
39
-
40
- return (
41
- <PageHeader
42
- title={title}
43
- subtitle={subtitle}
44
- actions={[
45
- ...(showUndo
46
- ? [
47
- {
48
- label: 'Undo Once',
49
- icon: IconName.Undo,
50
- actionType: PageHeaderActionType.Context,
51
- onClick: () => {
52
- undoOnce();
53
- },
54
- disabled: isFormSubmitting,
55
- },
56
- {
57
- label: 'Undo All',
58
- icon: IconName.Undo,
59
- actionType: PageHeaderActionType.Context,
60
- onClick: () => {
61
- undoAll();
62
- },
63
- disabled: isFormSubmitting,
64
- },
65
- ]
66
- : []),
67
- ...(cancelNavigationUrl // add cancel action if applicable
68
- ? [
69
- {
70
- label: 'Cancel',
71
- icon: IconName.X,
72
- onClick: () => {
73
- resetForm();
74
- // If the form has errors, Navigation needs to be wrapped in a promise or timeout.
75
- Promise.resolve().then(() =>
76
- history.push(cancelNavigationUrl),
77
- );
78
- },
79
- },
80
- ]
81
- : []),
82
- ]}
83
- />
84
- );
85
- };
@@ -1,26 +0,0 @@
1
- import { Data } from '../../../types';
2
- import { getFormDiff } from '../../Utils';
3
-
4
- export const mergeData = <TValues extends Data>(
5
- initialValues: TValues,
6
- currentValues: TValues,
7
- updatedValues?: Partial<TValues>,
8
- ): {
9
- newInitialValues: TValues;
10
- newCurrentValues: TValues;
11
- shouldUpdateCurrentValues: boolean;
12
- } => {
13
- const diff = getFormDiff(initialValues, currentValues);
14
-
15
- return {
16
- newInitialValues: {
17
- ...initialValues,
18
- ...updatedValues,
19
- },
20
- newCurrentValues: {
21
- ...currentValues,
22
- ...updatedValues,
23
- },
24
- shouldUpdateCurrentValues: Object.keys(diff).length > 0,
25
- };
26
- };
@@ -1,70 +0,0 @@
1
- import { useCallback, useState } from 'react';
2
-
3
- export interface ChangeSet<T> {
4
- prev: Partial<T>;
5
- next: Partial<T>;
6
- }
7
-
8
- export const useChangeSets = <T>(
9
- initialValues: T,
10
- ): {
11
- changeSets: ChangeSet<T>[];
12
- push: (value: ChangeSet<T>) => number;
13
- pop: () => ChangeSet<T> | undefined;
14
- clear: () => Partial<T>;
15
- getAggregatedChanges: () => T;
16
- } => {
17
- const [changeSets, setChangeSets] = useState<ChangeSet<T>[]>([]);
18
-
19
- const push = useCallback(
20
- (value: ChangeSet<T>): number => {
21
- setChangeSets((prev) => [...prev, value]);
22
- return changeSets.length;
23
- },
24
- [changeSets],
25
- );
26
-
27
- const pop = useCallback((): ChangeSet<T> | undefined => {
28
- if (changeSets.length > 0) {
29
- const lastChangeSet = changeSets[changeSets.length - 1];
30
- setChangeSets((prev) => prev.slice(0, -1));
31
- return lastChangeSet;
32
- }
33
- }, [changeSets]);
34
-
35
- const clear = useCallback((): T => {
36
- const allChanges = changeSets
37
- .slice()
38
- .reverse()
39
- .reduce((acc, changeSet) => {
40
- return {
41
- ...acc,
42
- ...changeSet.prev,
43
- };
44
- }, {} as T);
45
-
46
- setChangeSets([]);
47
- return { ...initialValues, ...allChanges };
48
- }, [changeSets, initialValues]);
49
-
50
- const getAggregatedChanges = useCallback(
51
- (): T => ({
52
- ...initialValues,
53
- ...changeSets.reduce((acc, changeSet) => {
54
- return {
55
- ...acc,
56
- ...changeSet.next,
57
- };
58
- }, {} as T),
59
- }),
60
- [changeSets, initialValues],
61
- );
62
-
63
- return {
64
- changeSets,
65
- push,
66
- pop,
67
- clear,
68
- getAggregatedChanges,
69
- };
70
- };