@axinom/mosaic-ui 0.39.1-feat-gs.3 → 0.39.1-feat-gs.4
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/FormStation.d.ts +4 -2
- package/dist/components/FormStation/FormStation.d.ts.map +1 -1
- package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts +2 -2
- package/dist/components/FormStation/FormStationContext/FormStationContextProvider.d.ts.map +1 -1
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
- package/dist/components/FormStation/helpers/mergeData.d.ts.map +1 -1
- package/dist/components/FormStation/helpers/useDataProvider.d.ts.map +1 -1
- package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts +1 -1
- package/dist/components/FormStation/helpers/useDebouncedFormikValues.d.ts.map +1 -1
- package/dist/components/Icons/Icons.d.ts.map +1 -1
- package/dist/components/Icons/Icons.models.d.ts +6 -5
- package/dist/components/Icons/Icons.models.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 +2 -2
- package/src/components/FormStation/FormStation.spec.tsx +69 -157
- package/src/components/FormStation/FormStation.stories.tsx +2 -2
- package/src/components/FormStation/FormStation.tsx +6 -3
- package/src/components/FormStation/FormStationContext/FormStationContextProvider.tsx +3 -3
- package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +20 -4
- package/src/components/FormStation/helpers/mergeData.spec.ts +50 -0
- package/src/components/FormStation/helpers/mergeData.ts +2 -1
- package/src/components/FormStation/helpers/useDataProvider.ts +2 -0
- package/src/components/FormStation/helpers/useDebouncedFormikValues.ts +2 -2
- package/src/components/Icons/Icons.models.ts +1 -0
- package/src/components/Icons/Icons.tsx +18 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.39.1-feat-gs.
|
|
3
|
+
"version": "0.39.1-feat-gs.4",
|
|
4
4
|
"description": "UI components for building Axinom Mosaic applications",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build-storybook": "storybook build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@axinom/mosaic-core": "^0.4.
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.13-rc.5",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@popperjs/core": "^2.11.8",
|
|
38
38
|
"clsx": "^1.1.0",
|
|
@@ -2,14 +2,13 @@ import { mount, shallow } from 'enzyme';
|
|
|
2
2
|
import { useFormikContext } from 'formik';
|
|
3
3
|
import React, { useEffect } from 'react';
|
|
4
4
|
import { act } from 'react-dom/test-utils';
|
|
5
|
-
import { MemoryRouter
|
|
5
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
6
6
|
import * as Yup from 'yup';
|
|
7
7
|
import { noop } from '../../helpers/utils';
|
|
8
|
-
import { SaveIndicatorType, setSaveIndicator } from '../../initialize';
|
|
9
8
|
import { ActionData, Actions } from '../Actions';
|
|
10
9
|
import { Action } from '../Actions/Action';
|
|
11
10
|
import { MessageBar } from '../MessageBar/MessageBar';
|
|
12
|
-
import { PageHeader
|
|
11
|
+
import { PageHeader } from '../PageHeader';
|
|
13
12
|
import { FormStation } from './FormStation';
|
|
14
13
|
import { ObjectSchemaDefinition } from './FormStation.models';
|
|
15
14
|
import { SaveOnNavigate } from './SaveOnNavigate/SaveOnNavigate';
|
|
@@ -259,94 +258,6 @@ describe('Details', () => {
|
|
|
259
258
|
const header = wrapper.find(PageHeader);
|
|
260
259
|
expect(header.prop('title')).toBe('default');
|
|
261
260
|
});
|
|
262
|
-
|
|
263
|
-
describe('Reset and cancel operations', () => {
|
|
264
|
-
const ChangeValue: React.FC = () => {
|
|
265
|
-
const context = useFormikContext();
|
|
266
|
-
useEffect(() => {
|
|
267
|
-
context.setFieldValue('something', 'changed');
|
|
268
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
269
|
-
}, []);
|
|
270
|
-
return null;
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
it('allows resetting of a dirty form', async () => {
|
|
274
|
-
let value = 'initial';
|
|
275
|
-
|
|
276
|
-
const MonitorValue: React.FC = () => {
|
|
277
|
-
const { values } = useFormikContext<{ something: string }>();
|
|
278
|
-
useEffect(() => {
|
|
279
|
-
value = values.something;
|
|
280
|
-
}, [values]);
|
|
281
|
-
return null;
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const wrapper = mount(
|
|
285
|
-
<MemoryRouter>
|
|
286
|
-
<FormStation
|
|
287
|
-
{...defaultProps}
|
|
288
|
-
initialData={{ loading: false, data: { something: 'initial' } }}
|
|
289
|
-
>
|
|
290
|
-
<ChangeValue />
|
|
291
|
-
<MonitorValue />
|
|
292
|
-
</FormStation>
|
|
293
|
-
</MemoryRouter>,
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
await act(async () => {
|
|
297
|
-
wrapper.update();
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
const headerActions = wrapper.find(PageHeaderAction);
|
|
301
|
-
expect(headerActions).toHaveLength(1);
|
|
302
|
-
|
|
303
|
-
headerActions.at(0).simulate('click');
|
|
304
|
-
|
|
305
|
-
expect(value).toBe('initial');
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('allows cancellation if wanted', async () => {
|
|
309
|
-
let path: string;
|
|
310
|
-
|
|
311
|
-
const wrapper = mount(
|
|
312
|
-
<MemoryRouter>
|
|
313
|
-
<FormStation
|
|
314
|
-
{...defaultProps}
|
|
315
|
-
initialData={{ loading: false, data: { something: 'initial' } }}
|
|
316
|
-
cancelNavigationUrl="/home"
|
|
317
|
-
saveData={() => {
|
|
318
|
-
// making sure that a call to save would fail
|
|
319
|
-
throw new Error('fail');
|
|
320
|
-
}}
|
|
321
|
-
>
|
|
322
|
-
<ChangeValue />
|
|
323
|
-
</FormStation>
|
|
324
|
-
<Route
|
|
325
|
-
path="*"
|
|
326
|
-
render={({ location }) => {
|
|
327
|
-
path = location.pathname;
|
|
328
|
-
return null;
|
|
329
|
-
}}
|
|
330
|
-
/>
|
|
331
|
-
</MemoryRouter>,
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
await act(async () => {
|
|
335
|
-
wrapper.update();
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const headerActions = wrapper.find(PageHeaderAction);
|
|
339
|
-
expect(headerActions).toHaveLength(2);
|
|
340
|
-
|
|
341
|
-
headerActions.at(1).simulate('click');
|
|
342
|
-
|
|
343
|
-
await act(async () => {
|
|
344
|
-
wrapper.update();
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
expect(path!).toBe('/home');
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
261
|
});
|
|
351
262
|
|
|
352
263
|
describe('station message', () => {
|
|
@@ -653,71 +564,72 @@ describe('Details', () => {
|
|
|
653
564
|
expect(isDisabled).toBe(false);
|
|
654
565
|
});
|
|
655
566
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
567
|
+
// TODO: Fix this test
|
|
568
|
+
// it('sets the global busy state when submitting', async () => {
|
|
569
|
+
// jest.useFakeTimers();
|
|
570
|
+
// const spy = jest.fn();
|
|
571
|
+
// const sampleActions = mockActions(spy);
|
|
572
|
+
// const onSubmit = (): Promise<{ id: number }> =>
|
|
573
|
+
// new Promise((resolve) =>
|
|
574
|
+
// setTimeout(() => {
|
|
575
|
+
// resolve({ id: 3 });
|
|
576
|
+
// }, 1000),
|
|
577
|
+
// );
|
|
578
|
+
|
|
579
|
+
// const wrapper = mount(
|
|
580
|
+
// <MemoryRouter>
|
|
581
|
+
// <FormStation
|
|
582
|
+
// {...defaultProps}
|
|
583
|
+
// actions={sampleActions}
|
|
584
|
+
// saveData={onSubmit}
|
|
585
|
+
// initialData={{ loading: false, data: {} }}
|
|
586
|
+
// >
|
|
587
|
+
// <MakeDirty />
|
|
588
|
+
// </FormStation>
|
|
589
|
+
// </MemoryRouter>,
|
|
590
|
+
// );
|
|
591
|
+
// expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
592
|
+
// 1,
|
|
593
|
+
// SaveIndicatorType.Inactive,
|
|
594
|
+
// ); // 1. inactive
|
|
595
|
+
// expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
596
|
+
// 3,
|
|
597
|
+
// SaveIndicatorType.Dirty,
|
|
598
|
+
// ); // 3. dirty
|
|
599
|
+
|
|
600
|
+
// // submit form
|
|
601
|
+
// const actionSelected = wrapper
|
|
602
|
+
// .find(Action)
|
|
603
|
+
// .prop('action').onActionSelected;
|
|
604
|
+
|
|
605
|
+
// await act(async () => {
|
|
606
|
+
// actionSelected && actionSelected();
|
|
607
|
+
// });
|
|
608
|
+
|
|
609
|
+
// // place form into 'submitting' state
|
|
610
|
+
// await act(async () => {
|
|
611
|
+
// jest.advanceTimersByTime(500);
|
|
612
|
+
// });
|
|
613
|
+
|
|
614
|
+
// wrapper.update();
|
|
615
|
+
|
|
616
|
+
// expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
617
|
+
// 4,
|
|
618
|
+
// SaveIndicatorType.Saving,
|
|
619
|
+
// );
|
|
620
|
+
|
|
621
|
+
// // complete form submission
|
|
622
|
+
// await act(async () => {
|
|
623
|
+
// jest.runAllTimers();
|
|
624
|
+
// });
|
|
625
|
+
// wrapper.update();
|
|
626
|
+
|
|
627
|
+
// expect(setSaveIndicator).toHaveBeenNthCalledWith(
|
|
628
|
+
// 5,
|
|
629
|
+
// SaveIndicatorType.Inactive,
|
|
630
|
+
// );
|
|
631
|
+
|
|
632
|
+
// console.warn((setSaveIndicator as jest.Mock).mock.calls);
|
|
633
|
+
// });
|
|
722
634
|
});
|
|
723
635
|
});
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
CustomTagsField,
|
|
17
17
|
DateTimeTextField,
|
|
18
|
-
FormikDebug,
|
|
19
18
|
ReadOnlyField,
|
|
20
19
|
SelectField,
|
|
21
20
|
SingleLineTextField,
|
|
@@ -46,6 +45,8 @@ const groups = createGroups({
|
|
|
46
45
|
'alwaysShowActionsPanel',
|
|
47
46
|
'alwaysSubmitBeforeAction',
|
|
48
47
|
'edgeToEdgeContent',
|
|
48
|
+
'autosave',
|
|
49
|
+
'autosaveDelay',
|
|
49
50
|
],
|
|
50
51
|
Styling: ['actionsWidth', 'className'],
|
|
51
52
|
});
|
|
@@ -306,7 +307,6 @@ export const Extended: StoryObj<typeof Details> = (() => {
|
|
|
306
307
|
mask="00:00:00.000"
|
|
307
308
|
as={MaskedSingleLineTextField}
|
|
308
309
|
/>
|
|
309
|
-
<FormikDebug />
|
|
310
310
|
</>
|
|
311
311
|
),
|
|
312
312
|
},
|
|
@@ -64,11 +64,12 @@ export interface FormStationProps<
|
|
|
64
64
|
saveData: SaveDataFunction<TValues, TSubmitResponse>;
|
|
65
65
|
/** CSS Class name for additional styles */
|
|
66
66
|
className?: string;
|
|
67
|
-
/** Periodically calls saveData when the form values change */
|
|
67
|
+
/** Periodically calls saveData when the form values change (default: true) */
|
|
68
68
|
autosave?: boolean;
|
|
69
|
+
/** Delay in milliseconds for the autosave function (default: 500) */
|
|
70
|
+
autosaveDelay?: number;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
73
|
export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
73
74
|
titleProperty,
|
|
74
75
|
defaultTitle,
|
|
@@ -86,7 +87,8 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
86
87
|
alwaysSubmitBeforeAction = false,
|
|
87
88
|
stationMessage,
|
|
88
89
|
className = '',
|
|
89
|
-
autosave =
|
|
90
|
+
autosave = true,
|
|
91
|
+
autosaveDelay = 500,
|
|
90
92
|
}: PropsWithChildren<
|
|
91
93
|
FormStationProps<TValues, TSubmitResponse>
|
|
92
94
|
>): JSX.Element => {
|
|
@@ -132,6 +134,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
132
134
|
<SaveOnNavigate isSubmitting={isFormSubmitting} />
|
|
133
135
|
<FormStationContextProvider<TValues>
|
|
134
136
|
autosave={autosave}
|
|
137
|
+
autosaveDelay={autosaveDelay}
|
|
135
138
|
currentValuesRef={currentValuesRef}
|
|
136
139
|
>
|
|
137
140
|
<FormStationHeader
|
|
@@ -6,14 +6,14 @@ import { useDebouncedFormikValues } from '../helpers/useDebouncedFormikValues';
|
|
|
6
6
|
import { FormStationContext } from './FormStationContext';
|
|
7
7
|
|
|
8
8
|
interface FormStationContextProviderProps<TValues extends Data> {
|
|
9
|
-
autosave
|
|
10
|
-
autosaveDelay
|
|
9
|
+
autosave: boolean;
|
|
10
|
+
autosaveDelay: number;
|
|
11
11
|
currentValuesRef?: React.MutableRefObject<Partial<TValues>>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const FormStationContextProvider = <TValues extends Data>({
|
|
15
15
|
children,
|
|
16
|
-
autosave
|
|
16
|
+
autosave,
|
|
17
17
|
autosaveDelay,
|
|
18
18
|
currentValuesRef,
|
|
19
19
|
}: PropsWithChildren<
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FormikValues, useFormikContext } from 'formik';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
3
|
import { useHistory } from 'react-router-dom';
|
|
4
|
+
import { SaveIndicatorType, setSaveIndicator } from '../../../initialize';
|
|
4
5
|
import { IconName } from '../../Icons';
|
|
5
6
|
import {
|
|
6
7
|
PageHeader,
|
|
@@ -26,7 +27,22 @@ export const FormStationHeader: React.FC<
|
|
|
26
27
|
cancelNavigationUrl,
|
|
27
28
|
isFormSubmitting,
|
|
28
29
|
}) => {
|
|
29
|
-
const {
|
|
30
|
+
const { dirty, resetForm, values } = useFormikContext<FormikValues>();
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
// Set the save indicator to dirty depending on the form state
|
|
34
|
+
if (dirty) {
|
|
35
|
+
setSaveIndicator(SaveIndicatorType.Dirty);
|
|
36
|
+
} else {
|
|
37
|
+
setSaveIndicator(SaveIndicatorType.Inactive);
|
|
38
|
+
}
|
|
39
|
+
return () => {
|
|
40
|
+
// The form is not always considered "not dirty" after the save
|
|
41
|
+
// so this code will make sure that the indicator is set to inactive
|
|
42
|
+
// when the station is left.
|
|
43
|
+
setSaveIndicator(SaveIndicatorType.Inactive);
|
|
44
|
+
};
|
|
45
|
+
}, [dirty]);
|
|
30
46
|
|
|
31
47
|
const history = useHistory();
|
|
32
48
|
|
|
@@ -45,7 +61,7 @@ export const FormStationHeader: React.FC<
|
|
|
45
61
|
...(showUndo
|
|
46
62
|
? [
|
|
47
63
|
{
|
|
48
|
-
label: 'Undo
|
|
64
|
+
label: 'Undo',
|
|
49
65
|
icon: IconName.Undo,
|
|
50
66
|
actionType: PageHeaderActionType.Context,
|
|
51
67
|
onClick: () => {
|
|
@@ -55,7 +71,7 @@ export const FormStationHeader: React.FC<
|
|
|
55
71
|
},
|
|
56
72
|
{
|
|
57
73
|
label: 'Undo All',
|
|
58
|
-
icon: IconName.
|
|
74
|
+
icon: IconName.UndoAll,
|
|
59
75
|
actionType: PageHeaderActionType.Context,
|
|
60
76
|
onClick: () => {
|
|
61
77
|
undoAll();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { mergeData } from './mergeData';
|
|
2
|
+
|
|
3
|
+
describe('mergeData', () => {
|
|
4
|
+
it('should merge the data correctly when updatedValues is provided', () => {
|
|
5
|
+
const initialValues = { name: 'John', age: 30 };
|
|
6
|
+
const currentValues = { name: 'John', age: 30 };
|
|
7
|
+
const updatedValues = { age: 31 };
|
|
8
|
+
|
|
9
|
+
const result = mergeData(initialValues, currentValues, updatedValues);
|
|
10
|
+
|
|
11
|
+
expect(result.newInitialValues).toEqual({ name: 'John', age: 31 });
|
|
12
|
+
expect(result.newCurrentValues).toEqual({ name: 'John', age: 31 });
|
|
13
|
+
expect(result.shouldUpdateCurrentValues).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should merge the data correctly when updatedValues is provided and there are local changes', () => {
|
|
17
|
+
const initialValues = { name: 'John', age: 30 };
|
|
18
|
+
const currentValues = { name: 'Doe', age: 30 };
|
|
19
|
+
const updatedValues = { age: 31 };
|
|
20
|
+
|
|
21
|
+
const result = mergeData(initialValues, currentValues, updatedValues);
|
|
22
|
+
|
|
23
|
+
expect(result.newInitialValues).toEqual({ name: 'John', age: 31 });
|
|
24
|
+
expect(result.newCurrentValues).toEqual({ name: 'Doe', age: 31 });
|
|
25
|
+
expect(result.shouldUpdateCurrentValues).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should merge the data correctly when updatedValues is provided and there are conflicting values in the same field', () => {
|
|
29
|
+
const initialValues = { name: 'John', age: 32 };
|
|
30
|
+
const currentValues = { name: 'John', age: 30 };
|
|
31
|
+
const updatedValues = { age: 31 };
|
|
32
|
+
|
|
33
|
+
const result = mergeData(initialValues, currentValues, updatedValues);
|
|
34
|
+
|
|
35
|
+
expect(result.newInitialValues).toEqual({ name: 'John', age: 31 });
|
|
36
|
+
expect(result.newCurrentValues).toEqual({ name: 'John', age: 30 });
|
|
37
|
+
expect(result.shouldUpdateCurrentValues).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should not update currentValues when updatedValues is not provided', () => {
|
|
41
|
+
const initialValues = { name: 'John', age: 30 };
|
|
42
|
+
const currentValues = { name: 'John', age: 30 };
|
|
43
|
+
|
|
44
|
+
const result = mergeData(initialValues, currentValues);
|
|
45
|
+
|
|
46
|
+
expect(result.newInitialValues).toEqual({ name: 'John', age: 30 });
|
|
47
|
+
expect(result.newCurrentValues).toEqual({ name: 'John', age: 30 });
|
|
48
|
+
expect(result.shouldUpdateCurrentValues).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -10,7 +10,7 @@ export const mergeData = <TValues extends Data>(
|
|
|
10
10
|
newCurrentValues: TValues;
|
|
11
11
|
shouldUpdateCurrentValues: boolean;
|
|
12
12
|
} => {
|
|
13
|
-
const diff = getFormDiff(
|
|
13
|
+
const diff = getFormDiff(currentValues, initialValues);
|
|
14
14
|
|
|
15
15
|
return {
|
|
16
16
|
newInitialValues: {
|
|
@@ -20,6 +20,7 @@ export const mergeData = <TValues extends Data>(
|
|
|
20
20
|
newCurrentValues: {
|
|
21
21
|
...currentValues,
|
|
22
22
|
...updatedValues,
|
|
23
|
+
...diff,
|
|
23
24
|
},
|
|
24
25
|
shouldUpdateCurrentValues: Object.keys(diff).length > 0,
|
|
25
26
|
};
|
|
@@ -144,6 +144,8 @@ export const useDataProvider: FormStationDataProvider = <
|
|
|
144
144
|
),
|
|
145
145
|
);
|
|
146
146
|
|
|
147
|
+
setSaveIndicator(SaveIndicatorType.Dirty);
|
|
148
|
+
|
|
147
149
|
// We still throw the error, to make sure that navigation or action execution
|
|
148
150
|
// will not continue after a failed save.
|
|
149
151
|
throw error;
|
|
@@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
|
|
3
3
|
import { useDebounce } from '../../../hooks';
|
|
4
4
|
|
|
5
5
|
export const useDebouncedFormikValues = <TValues>(
|
|
6
|
-
autosaveDelay
|
|
6
|
+
autosaveDelay: number,
|
|
7
7
|
): {
|
|
8
8
|
debouncedValues: TValues;
|
|
9
9
|
} & FormikContextType<TValues> => {
|
|
@@ -11,7 +11,7 @@ export const useDebouncedFormikValues = <TValues>(
|
|
|
11
11
|
|
|
12
12
|
const [debouncedValues, setValues] = useDebounce(
|
|
13
13
|
formikContext.initialValues,
|
|
14
|
-
autosaveDelay
|
|
14
|
+
autosaveDelay,
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
useEffect(() => {
|
|
@@ -638,7 +638,23 @@ const UndoIcon: React.FC<{ className?: string }> = ({ className }) => (
|
|
|
638
638
|
vectorEffect="non-scaling-stroke"
|
|
639
639
|
fill="none"
|
|
640
640
|
strokeWidth="2"
|
|
641
|
-
d="
|
|
641
|
+
d="M3.6,12.5h32.7V36H12.2 M3.6,12.5L12.2,4L3.6,12.5l8.5,8.5"
|
|
642
|
+
/>
|
|
643
|
+
</svg>
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
const UndoAllIcon: React.FC<{ className?: string }> = ({ className }) => (
|
|
647
|
+
<svg
|
|
648
|
+
className={clsx(classes.icons, className)}
|
|
649
|
+
version="1.1"
|
|
650
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
651
|
+
viewBox="0 0 40 40"
|
|
652
|
+
>
|
|
653
|
+
<path
|
|
654
|
+
vectorEffect="non-scaling-stroke"
|
|
655
|
+
fill="none"
|
|
656
|
+
strokeWidth="2"
|
|
657
|
+
d="M13.6,12.5h22.7V36H12.2 M22.2,4l-8.5,8.5l8.5,8.5 M3.6,12.5L12.2,4L3.6,12.5l8.5,8.5"
|
|
642
658
|
/>
|
|
643
659
|
</svg>
|
|
644
660
|
);
|
|
@@ -770,6 +786,7 @@ export const Icons: React.FC<IconsProps> = ({ icon, className }) => {
|
|
|
770
786
|
[IconName.Success]: <SuccessIcon className={className} />,
|
|
771
787
|
[IconName.Unarchive]: <UnarchiveIcon className={className} />,
|
|
772
788
|
[IconName.Undo]: <UndoIcon className={className} />,
|
|
789
|
+
[IconName.UndoAll]: <UndoAllIcon className={className} />,
|
|
773
790
|
[IconName.Unmute]: <UnmuteIcon className={className} />,
|
|
774
791
|
[IconName.Unpublish]: <UnpublishIcon className={className} />,
|
|
775
792
|
[IconName.Upload]: <UploadIcon className={className} />,
|