Skip to content

Commit 29e42b7

Browse files
react-material: Reset data in anyOf renderer for incompatible data types (#2175)
Reset data in anyOfRenderer if data types dont match Co-authored-by: Lucas Koehler <[email protected]>
1 parent 1e44159 commit 29e42b7

File tree

3 files changed

+126
-51
lines changed

3 files changed

+126
-51
lines changed

packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,22 @@
2525
import React, { useCallback, useState } from 'react';
2626

2727
import {
28+
CombinatorRendererProps,
2829
createCombinatorRenderInfos,
30+
createDefaultValue,
2931
isAnyOfControl,
3032
JsonSchema,
3133
RankedTester,
3234
rankWith,
33-
StatePropsOfCombinator,
3435
} from '@jsonforms/core';
3536
import { JsonFormsDispatch, withJsonFormsAnyOfProps } from '@jsonforms/react';
3637
import { Hidden, Tab, Tabs } from '@mui/material';
3738
import CombinatorProperties from './CombinatorProperties';
39+
import isEmpty from 'lodash/isEmpty';
40+
import { TabSwitchConfirmDialog } from './TabSwitchConfirmDialog';
3841

3942
export const MaterialAnyOfRenderer = ({
43+
handleChange,
4044
schema,
4145
rootSchema,
4246
indexOfFittingSchema,
@@ -46,12 +50,44 @@ export const MaterialAnyOfRenderer = ({
4650
cells,
4751
uischema,
4852
uischemas,
49-
}: StatePropsOfCombinator) => {
53+
id,
54+
data,
55+
}: CombinatorRendererProps) => {
5056
const [selectedAnyOf, setSelectedAnyOf] = useState(indexOfFittingSchema || 0);
51-
const handleChange = useCallback(
52-
(_ev: any, value: number) => setSelectedAnyOf(value),
53-
[setSelectedAnyOf]
57+
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
58+
const [newSelectedIndex, setNewSelectedIndex] = useState(0);
59+
60+
const handleClose = useCallback(
61+
() => setConfirmDialogOpen(false),
62+
[setConfirmDialogOpen]
63+
);
64+
65+
const handleTabChange = useCallback(
66+
(_event: any, newIndex: number) => {
67+
if (
68+
isEmpty(data) ||
69+
typeof data ===
70+
typeof createDefaultValue(anyOfRenderInfos[newIndex].schema)
71+
) {
72+
setSelectedAnyOf(newIndex);
73+
} else {
74+
setNewSelectedIndex(newIndex);
75+
setConfirmDialogOpen(true);
76+
}
77+
},
78+
[setConfirmDialogOpen, setSelectedAnyOf, data]
5479
);
80+
81+
const openNewTab = (newIndex: number) => {
82+
handleChange(path, createDefaultValue(anyOfRenderInfos[newIndex].schema));
83+
setSelectedAnyOf(newIndex);
84+
};
85+
86+
const confirm = useCallback(() => {
87+
openNewTab(newSelectedIndex);
88+
setConfirmDialogOpen(false);
89+
}, [handleChange, createDefaultValue, newSelectedIndex]);
90+
5591
const anyOf = 'anyOf';
5692
const anyOfRenderInfos = createCombinatorRenderInfos(
5793
(schema as JsonSchema).anyOf,
@@ -69,7 +105,7 @@ export const MaterialAnyOfRenderer = ({
69105
combinatorKeyword={anyOf}
70106
path={path}
71107
/>
72-
<Tabs value={selectedAnyOf} onChange={handleChange}>
108+
<Tabs value={selectedAnyOf} onChange={handleTabChange}>
73109
{anyOfRenderInfos.map((anyOfRenderInfo) => (
74110
<Tab key={anyOfRenderInfo.label} label={anyOfRenderInfo.label} />
75111
))}
@@ -87,6 +123,13 @@ export const MaterialAnyOfRenderer = ({
87123
/>
88124
)
89125
)}
126+
<TabSwitchConfirmDialog
127+
cancel={handleClose}
128+
confirm={confirm}
129+
id={'anyOf-' + id}
130+
open={confirmDialogOpen}
131+
handleClose={handleClose}
132+
/>
90133
</Hidden>
91134
);
92135
};

packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import React, { useCallback, useState } from 'react';
2626
import isEmpty from 'lodash/isEmpty';
2727

28+
import { TabSwitchConfirmDialog } from './TabSwitchConfirmDialog';
29+
2830
import {
2931
CombinatorRendererProps,
3032
createCombinatorRenderInfos,
@@ -35,17 +37,7 @@ import {
3537
RankedTester,
3638
rankWith,
3739
} from '@jsonforms/core';
38-
import {
39-
Button,
40-
Dialog,
41-
DialogActions,
42-
DialogContent,
43-
DialogContentText,
44-
DialogTitle,
45-
Hidden,
46-
Tab,
47-
Tabs,
48-
} from '@mui/material';
40+
import { Hidden, Tab, Tabs } from '@mui/material';
4941
import { JsonFormsDispatch, withJsonFormsOneOfProps } from '@jsonforms/react';
5042
import CombinatorProperties from './CombinatorProperties';
5143

@@ -67,13 +59,16 @@ export const MaterialOneOfRenderer = ({
6759
uischemas,
6860
data,
6961
}: CombinatorRendererProps) => {
70-
const [open, setOpen] = useState(false);
62+
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
7163
const [selectedIndex, setSelectedIndex] = useState(indexOfFittingSchema || 0);
7264
const [newSelectedIndex, setNewSelectedIndex] = useState(0);
73-
const handleClose = useCallback(() => setOpen(false), [setOpen]);
65+
const handleClose = useCallback(
66+
() => setConfirmDialogOpen(false),
67+
[setConfirmDialogOpen]
68+
);
7469
const cancel = useCallback(() => {
75-
setOpen(false);
76-
}, [setOpen]);
70+
setConfirmDialogOpen(false);
71+
}, [setConfirmDialogOpen]);
7772
const oneOfRenderInfos = createCombinatorRenderInfos(
7873
(schema as JsonSchema).oneOf,
7974
rootSchema,
@@ -90,18 +85,19 @@ export const MaterialOneOfRenderer = ({
9085

9186
const confirm = useCallback(() => {
9287
openNewTab(newSelectedIndex);
93-
setOpen(false);
88+
setConfirmDialogOpen(false);
9489
}, [handleChange, createDefaultValue, newSelectedIndex]);
90+
9591
const handleTabChange = useCallback(
9692
(_event: any, newOneOfIndex: number) => {
9793
setNewSelectedIndex(newOneOfIndex);
9894
if (isEmpty(data)) {
9995
openNewTab(newOneOfIndex);
10096
} else {
101-
setOpen(true);
97+
setConfirmDialogOpen(true);
10298
}
10399
},
104-
[setOpen, setSelectedIndex, data]
100+
[setConfirmDialogOpen, setSelectedIndex, data]
105101
);
106102

107103
return (
@@ -129,33 +125,13 @@ export const MaterialOneOfRenderer = ({
129125
/>
130126
)
131127
)}
132-
<Dialog
133-
open={open}
134-
onClose={handleClose}
135-
aria-labelledby='alert-dialog-title'
136-
aria-describedby='alert-dialog-description'
137-
>
138-
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
139-
<DialogContent>
140-
<DialogContentText id='alert-dialog-description'>
141-
Your data will be cleared if you navigate away from this tab. Do you
142-
want to proceed?
143-
</DialogContentText>
144-
</DialogContent>
145-
<DialogActions>
146-
<Button onClick={cancel} color='primary'>
147-
No
148-
</Button>
149-
<Button
150-
onClick={confirm}
151-
color='primary'
152-
autoFocus
153-
id={`oneOf-${id}-confirm-yes`}
154-
>
155-
Yes
156-
</Button>
157-
</DialogActions>
158-
</Dialog>
128+
<TabSwitchConfirmDialog
129+
cancel={cancel}
130+
confirm={confirm}
131+
id={'oneOf-' + id}
132+
open={confirmDialogOpen}
133+
handleClose={handleClose}
134+
/>
159135
</Hidden>
160136
);
161137
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
3+
import {
4+
Button,
5+
Dialog,
6+
DialogActions,
7+
DialogContent,
8+
DialogContentText,
9+
DialogTitle,
10+
} from '@mui/material';
11+
12+
export interface TabSwitchConfirmDialogProps {
13+
open: boolean;
14+
handleClose: () => void;
15+
confirm: () => void;
16+
cancel: () => void;
17+
id: string;
18+
}
19+
20+
export const TabSwitchConfirmDialog = ({
21+
open,
22+
handleClose,
23+
confirm,
24+
cancel,
25+
id,
26+
}: TabSwitchConfirmDialogProps) => {
27+
return (
28+
<Dialog
29+
open={open}
30+
onClose={handleClose}
31+
aria-labelledby='alert-dialog-title'
32+
aria-describedby='alert-dialog-description'
33+
>
34+
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
35+
<DialogContent>
36+
<DialogContentText id='alert-dialog-description'>
37+
Your data will be cleared if you navigate away from this tab. Do you
38+
want to proceed?
39+
</DialogContentText>
40+
</DialogContent>
41+
<DialogActions>
42+
<Button onClick={cancel} color='primary'>
43+
No
44+
</Button>
45+
<Button
46+
onClick={confirm}
47+
color='primary'
48+
autoFocus
49+
id={`${id}-confirm-yes`}
50+
>
51+
Yes
52+
</Button>
53+
</DialogActions>
54+
</Dialog>
55+
);
56+
};

0 commit comments

Comments
 (0)