Skip to content

Commit

Permalink
react-material: Reset data in anyOf renderer for incompatible data ty…
Browse files Browse the repository at this point in the history
…pes (#2175)

Reset data in anyOfRenderer if data types dont match

Co-authored-by: Lucas Koehler <lkoehler@eclipsesource.com>
  • Loading branch information
LukasBoll and lucas-koehler authored Sep 21, 2023
1 parent 1e44159 commit 29e42b7
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 51 deletions.
55 changes: 49 additions & 6 deletions packages/material-renderers/src/complex/MaterialAnyOfRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@
import React, { useCallback, useState } from 'react';

import {
CombinatorRendererProps,
createCombinatorRenderInfos,
createDefaultValue,
isAnyOfControl,
JsonSchema,
RankedTester,
rankWith,
StatePropsOfCombinator,
} from '@jsonforms/core';
import { JsonFormsDispatch, withJsonFormsAnyOfProps } from '@jsonforms/react';
import { Hidden, Tab, Tabs } from '@mui/material';
import CombinatorProperties from './CombinatorProperties';
import isEmpty from 'lodash/isEmpty';
import { TabSwitchConfirmDialog } from './TabSwitchConfirmDialog';

export const MaterialAnyOfRenderer = ({
handleChange,
schema,
rootSchema,
indexOfFittingSchema,
Expand All @@ -46,12 +50,44 @@ export const MaterialAnyOfRenderer = ({
cells,
uischema,
uischemas,
}: StatePropsOfCombinator) => {
id,
data,
}: CombinatorRendererProps) => {
const [selectedAnyOf, setSelectedAnyOf] = useState(indexOfFittingSchema || 0);
const handleChange = useCallback(
(_ev: any, value: number) => setSelectedAnyOf(value),
[setSelectedAnyOf]
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
const [newSelectedIndex, setNewSelectedIndex] = useState(0);

const handleClose = useCallback(
() => setConfirmDialogOpen(false),
[setConfirmDialogOpen]
);

const handleTabChange = useCallback(
(_event: any, newIndex: number) => {
if (
isEmpty(data) ||
typeof data ===
typeof createDefaultValue(anyOfRenderInfos[newIndex].schema)
) {
setSelectedAnyOf(newIndex);
} else {
setNewSelectedIndex(newIndex);
setConfirmDialogOpen(true);
}
},
[setConfirmDialogOpen, setSelectedAnyOf, data]
);

const openNewTab = (newIndex: number) => {
handleChange(path, createDefaultValue(anyOfRenderInfos[newIndex].schema));
setSelectedAnyOf(newIndex);
};

const confirm = useCallback(() => {
openNewTab(newSelectedIndex);
setConfirmDialogOpen(false);
}, [handleChange, createDefaultValue, newSelectedIndex]);

const anyOf = 'anyOf';
const anyOfRenderInfos = createCombinatorRenderInfos(
(schema as JsonSchema).anyOf,
Expand All @@ -69,7 +105,7 @@ export const MaterialAnyOfRenderer = ({
combinatorKeyword={anyOf}
path={path}
/>
<Tabs value={selectedAnyOf} onChange={handleChange}>
<Tabs value={selectedAnyOf} onChange={handleTabChange}>
{anyOfRenderInfos.map((anyOfRenderInfo) => (
<Tab key={anyOfRenderInfo.label} label={anyOfRenderInfo.label} />
))}
Expand All @@ -87,6 +123,13 @@ export const MaterialAnyOfRenderer = ({
/>
)
)}
<TabSwitchConfirmDialog
cancel={handleClose}
confirm={confirm}
id={'anyOf-' + id}
open={confirmDialogOpen}
handleClose={handleClose}
/>
</Hidden>
);
};
Expand Down
66 changes: 21 additions & 45 deletions packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import React, { useCallback, useState } from 'react';
import isEmpty from 'lodash/isEmpty';

import { TabSwitchConfirmDialog } from './TabSwitchConfirmDialog';

import {
CombinatorRendererProps,
createCombinatorRenderInfos,
Expand All @@ -35,17 +37,7 @@ import {
RankedTester,
rankWith,
} from '@jsonforms/core';
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Hidden,
Tab,
Tabs,
} from '@mui/material';
import { Hidden, Tab, Tabs } from '@mui/material';
import { JsonFormsDispatch, withJsonFormsOneOfProps } from '@jsonforms/react';
import CombinatorProperties from './CombinatorProperties';

Expand All @@ -67,13 +59,16 @@ export const MaterialOneOfRenderer = ({
uischemas,
data,
}: CombinatorRendererProps) => {
const [open, setOpen] = useState(false);
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(indexOfFittingSchema || 0);
const [newSelectedIndex, setNewSelectedIndex] = useState(0);
const handleClose = useCallback(() => setOpen(false), [setOpen]);
const handleClose = useCallback(
() => setConfirmDialogOpen(false),
[setConfirmDialogOpen]
);
const cancel = useCallback(() => {
setOpen(false);
}, [setOpen]);
setConfirmDialogOpen(false);
}, [setConfirmDialogOpen]);
const oneOfRenderInfos = createCombinatorRenderInfos(
(schema as JsonSchema).oneOf,
rootSchema,
Expand All @@ -90,18 +85,19 @@ export const MaterialOneOfRenderer = ({

const confirm = useCallback(() => {
openNewTab(newSelectedIndex);
setOpen(false);
setConfirmDialogOpen(false);
}, [handleChange, createDefaultValue, newSelectedIndex]);

const handleTabChange = useCallback(
(_event: any, newOneOfIndex: number) => {
setNewSelectedIndex(newOneOfIndex);
if (isEmpty(data)) {
openNewTab(newOneOfIndex);
} else {
setOpen(true);
setConfirmDialogOpen(true);
}
},
[setOpen, setSelectedIndex, data]
[setConfirmDialogOpen, setSelectedIndex, data]
);

return (
Expand Down Expand Up @@ -129,33 +125,13 @@ export const MaterialOneOfRenderer = ({
/>
)
)}
<Dialog
open={open}
onClose={handleClose}
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
Your data will be cleared if you navigate away from this tab. Do you
want to proceed?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={cancel} color='primary'>
No
</Button>
<Button
onClick={confirm}
color='primary'
autoFocus
id={`oneOf-${id}-confirm-yes`}
>
Yes
</Button>
</DialogActions>
</Dialog>
<TabSwitchConfirmDialog
cancel={cancel}
confirm={confirm}
id={'oneOf-' + id}
open={confirmDialogOpen}
handleClose={handleClose}
/>
</Hidden>
);
};
Expand Down
56 changes: 56 additions & 0 deletions packages/material-renderers/src/complex/TabSwitchConfirmDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';

import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from '@mui/material';

export interface TabSwitchConfirmDialogProps {
open: boolean;
handleClose: () => void;
confirm: () => void;
cancel: () => void;
id: string;
}

export const TabSwitchConfirmDialog = ({
open,
handleClose,
confirm,
cancel,
id,
}: TabSwitchConfirmDialogProps) => {
return (
<Dialog
open={open}
onClose={handleClose}
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle id='alert-dialog-title'>{'Clear form?'}</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
Your data will be cleared if you navigate away from this tab. Do you
want to proceed?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={cancel} color='primary'>
No
</Button>
<Button
onClick={confirm}
color='primary'
autoFocus
id={`${id}-confirm-yes`}
>
Yes
</Button>
</DialogActions>
</Dialog>
);
};

0 comments on commit 29e42b7

Please sign in to comment.