@axinom/mosaic-ui 0.39.1-feat-gs.3 → 0.40.0-rc.1
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.
- package/dist/components/FormStation/Create/Create.d.ts +1 -1
- package/dist/components/FormStation/Create/Create.d.ts.map +1 -1
- package/dist/components/FormStation/Details/Details.d.ts +2 -2
- package/dist/components/FormStation/Details/Details.d.ts.map +1 -1
- package/dist/components/FormStation/FormStation.d.ts +15 -8
- package/dist/components/FormStation/FormStation.d.ts.map +1 -1
- package/dist/components/FormStation/FormStation.models.d.ts +3 -17
- package/dist/components/FormStation/FormStation.models.d.ts.map +1 -1
- package/dist/components/FormStation/StationErrorStateType.d.ts +5 -0
- package/dist/components/FormStation/StationErrorStateType.d.ts.map +1 -0
- package/dist/components/FormStation/index.d.ts +1 -1
- package/dist/components/FormStation/index.d.ts.map +1 -1
- package/dist/components/FormStation/{helpers/useValidationError.d.ts → useValidationError.d.ts} +1 -1
- package/dist/components/FormStation/useValidationError.d.ts.map +1 -0
- package/dist/components/Utils/Postgraphile/getArrayDiff.d.ts.map +1 -1
- package/dist/components/Utils/Postgraphile/getFormDiff.d.ts.map +1 -1
- package/dist/helpers/testing.d.ts +1 -4
- package/dist/helpers/testing.d.ts.map +1 -1
- package/dist/index.es.js +4 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/Actions/Action/Action.scss +0 -1
- package/src/components/FormElements/Tags/Tags.tsx +3 -3
- package/src/components/FormStation/Create/Create.stories.tsx +9 -1
- package/src/components/FormStation/Create/Create.tsx +1 -4
- package/src/components/FormStation/Details/Details.tsx +2 -5
- package/src/components/FormStation/FormStation.models.ts +3 -29
- package/src/components/FormStation/FormStation.scss +70 -0
- package/src/components/FormStation/FormStation.spec.tsx +1 -2
- package/src/components/FormStation/FormStation.stories.tsx +1 -20
- package/src/components/FormStation/FormStation.tsx +403 -68
- package/src/components/FormStation/StationErrorStateType.tsx +5 -0
- package/src/components/FormStation/index.ts +5 -1
- package/src/components/FormStation/{helpers/useValidationError.tsx → useValidationError.tsx} +1 -1
- package/src/components/Utils/Postgraphile/getArrayDiff.ts +6 -7
- package/src/components/Utils/Postgraphile/getFormDiff.ts +1 -2
- package/dist/components/FormStation/FormContentWrapper/FormContentWrapper.d.ts +0 -11
- package/dist/components/FormStation/FormContentWrapper/FormContentWrapper.d.ts.map +0 -1
- package/dist/components/FormStation/FormStationActions/FormStationActions.d.ts +0 -21
- package/dist/components/FormStation/FormStationActions/FormStationActions.d.ts.map +0 -1
- package/dist/components/FormStation/FormStationContext/FormStationContext.d.ts +0 -13
- package/dist/components/FormStation/FormStationContext/FormStationContext.d.ts.map +0 -1
- package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts +0 -10
- package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts.map +0 -1
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts +0 -12
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/mergeData.d.ts +0 -7
- package/dist/components/FormStation/helpers/mergeData.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/useChangeSets.d.ts +0 -12
- package/dist/components/FormStation/helpers/useChangeSets.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/useDataProvider.d.ts +0 -14
- package/dist/components/FormStation/helpers/useDataProvider.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts +0 -7
- package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/useUndo.d.ts +0 -6
- package/dist/components/FormStation/helpers/useUndo.d.ts.map +0 -1
- package/dist/components/FormStation/helpers/useValidationError.d.ts.map +0 -1
- package/src/components/FormStation/FormContentWrapper/FormContentWrapper.scss +0 -66
- package/src/components/FormStation/FormContentWrapper/FormContentWrapper.tsx +0 -77
- package/src/components/FormStation/FormStationActions/FormStationActions.tsx +0 -132
- package/src/components/FormStation/FormStationContext/FormStationContext.ts +0 -22
- package/src/components/FormStation/FormStationContext/FormStationContextProvider.tsx +0 -86
- package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +0 -85
- package/src/components/FormStation/helpers/mergeData.ts +0 -26
- package/src/components/FormStation/helpers/useChangeSets.ts +0 -70
- package/src/components/FormStation/helpers/useDataProvider.ts +0 -169
- package/src/components/FormStation/helpers/useDebouncedFormikValues.ts +0 -22
- 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 +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
|
-
};
|