Skip to content

Commit

Permalink
feat: add support for disabling add and remove in React Material
Browse files Browse the repository at this point in the history
Add and remove buttons in React Material tables, array layouts and
list-with-details can now be hidden via the UI Schema options
"disableAdd" and "disableRemove". They can also be hidden
programmatically via their props.

Includes the fix for the missing update context in
ExpandPanelRenderers (#2326)

Contributed on behalf of STMicroelectronics

Co-authored-by: Stefan Dirix <[email protected]>
  • Loading branch information
eneufeld and sdirix authored Jun 7, 2024
1 parent 52aa15a commit 87e4061
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 33 deletions.
3 changes: 3 additions & 0 deletions packages/core/src/util/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ export interface OwnPropsOfMasterListItem {
handleSelect(index: number): () => void;
removeItem(path: string, value: number): () => void;
translations: ArrayTranslations;
disableRemove?: boolean;
}

export interface StatePropsOfMasterItem extends OwnPropsOfMasterListItem {
Expand Down Expand Up @@ -1133,6 +1134,8 @@ export interface StatePropsOfArrayLayout extends StatePropsOfControlWithDetail {
data: number;
translations: ArrayTranslations;
minItems?: number;
disableRemove?: boolean;
disableAdd?: boolean;
}
/**
* Map state to table props
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ export const ListWithDetailMasterItem = ({
removeItem,
path,
translations,
disableRemove,
}: StatePropsOfMasterItem) => {
return (
<ListItem button selected={selected} onClick={handleSelect(index)}>
<ListItemAvatar>
<Avatar aria-label='Index'>{index + 1}</Avatar>
</ListItemAvatar>
<ListItemText primary={childLabel} />
{enabled && (
{enabled && !disableRemove && (
<ListItemSecondaryAction>
<Tooltip
id='tooltip-remove'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const MaterialListWithDetailRenderer = ({
rootSchema,
translations,
description,
disableAdd,
disableRemove,
}: ArrayLayoutProps) => {
const [selectedIndex, setSelectedIndex] = useState(undefined);
const handleRemoveItem = useCallback(
Expand Down Expand Up @@ -100,6 +102,8 @@ export const MaterialListWithDetailRenderer = ({
[uischemas, schema, uischema.scope, path, uischema, rootSchema]
);
const appliedUiSchemaOptions = merge({}, config, uischema.options);
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
const doDisableRemove = disableRemove || appliedUiSchemaOptions.disableRemove;

React.useEffect(() => {
setSelectedIndex(undefined);
Expand All @@ -124,6 +128,7 @@ export const MaterialListWithDetailRenderer = ({
enabled={enabled}
addItem={addItem}
createDefault={handleCreateDefaultValue}
disableAdd={doDisableAdd}
/>
<Grid container direction='row' spacing={2}>
<Grid item xs={3}>
Expand All @@ -142,6 +147,7 @@ export const MaterialListWithDetailRenderer = ({
uischema={foundUISchema}
childLabelProp={appliedUiSchemaOptions.elementLabelProp}
translations={translations}
disableRemove={doDisableRemove}
/>
))
) : (
Expand Down
45 changes: 31 additions & 14 deletions packages/material-renderers/src/complex/MaterialTableControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ interface NonEmptyRowProps {
cells?: JsonFormsCellRendererRegistryEntry[];
path: string;
translations: ArrayTranslations;
disableRemove?: boolean;
}

const NonEmptyRowComponent = ({
Expand All @@ -294,6 +295,7 @@ const NonEmptyRowComponent = ({
cells,
path,
translations,
disableRemove,
}: NonEmptyRowProps & WithDeleteDialogSupport) => {
const moveUp = useMemo(
() => moveUpCreator(path, rowIndex),
Expand Down Expand Up @@ -354,21 +356,23 @@ const NonEmptyRowComponent = ({
</Grid>
</Fragment>
) : null}
<Grid item>
<Tooltip
id='tooltip-remove'
title={translations.removeTooltip}
placement='bottom'
>
<IconButton
aria-label={translations.removeAriaLabel}
onClick={() => openDeleteDialog(childPath, rowIndex)}
size='large'
{!disableRemove ? (
<Grid item>
<Tooltip
id='tooltip-remove'
title={translations.removeTooltip}
placement='bottom'
>
<DeleteIcon />
</IconButton>
</Tooltip>
</Grid>
<IconButton
aria-label={translations.removeAriaLabel}
onClick={() => openDeleteDialog(childPath, rowIndex)}
size='large'
>
<DeleteIcon />
</IconButton>
</Tooltip>
</Grid>
) : null}
</Grid>
</NoBorderTableCell>
) : null}
Expand All @@ -387,6 +391,7 @@ interface TableRowsProp {
moveUp?(path: string, toMove: number): () => void;
moveDown?(path: string, toMove: number): () => void;
translations: ArrayTranslations;
disableRemove?: boolean;
}
const TableRows = ({
data,
Expand All @@ -400,6 +405,7 @@ const TableRows = ({
enabled,
cells,
translations,
disableRemove,
}: TableRowsProp & WithDeleteDialogSupport) => {
const isEmptyTable = data === 0;

Expand Down Expand Up @@ -438,6 +444,7 @@ const TableRows = ({
cells={cells}
path={path}
translations={translations}
disableRemove={disableRemove}
/>
);
})}
Expand All @@ -464,8 +471,16 @@ export class MaterialTableControl extends React.Component<
enabled,
cells,
translations,
disableAdd,
disableRemove,
config,
} = this.props;

const appliedUiSchemaOptions = merge({}, config, uischema.options);
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
const doDisableRemove =
disableRemove || appliedUiSchemaOptions.disableRemove;

const controlElement = uischema as ControlElement;
const isObjectSchema = schema.type === 'object';
const headerCells: any = isObjectSchema
Expand All @@ -491,6 +506,7 @@ export class MaterialTableControl extends React.Component<
rootSchema={rootSchema}
enabled={enabled}
translations={translations}
disableAdd={doDisableAdd}
/>
{isObjectSchema && (
<TableRow>
Expand All @@ -504,6 +520,7 @@ export class MaterialTableControl extends React.Component<
openDeleteDialog={openDeleteDialog}
translations={translations}
{...this.props}
disableRemove={doDisableRemove}
/>
</TableBody>
</Table>
Expand Down
4 changes: 3 additions & 1 deletion packages/material-renderers/src/complex/TableToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface MaterialTableToolbarProps {
enabled: boolean;
translations: ArrayTranslations;
addItem(path: string, value: any): () => void;
disableAdd?: boolean;
}

const fixedCellSmall = {
Expand All @@ -72,6 +73,7 @@ const TableToolbar = React.memo(function TableToolbar({
enabled,
translations,
rootSchema,
disableAdd,
}: MaterialTableToolbarProps) {
return (
<TableRow>
Expand Down Expand Up @@ -100,7 +102,7 @@ const TableToolbar = React.memo(function TableToolbar({
{description && <FormHelperText>{description}</FormHelperText>}
</Stack>
</NoBorderTableCell>
{enabled ? (
{enabled && !disableAdd ? (
<NoBorderTableCell align='right' style={fixedCellSmall}>
<Tooltip
id='tooltip-add'
Expand Down
4 changes: 3 additions & 1 deletion packages/material-renderers/src/layouts/ArrayToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface ArrayLayoutToolbarProps {
addItem(path: string, data: any): () => void;
createDefault(): any;
translations: ArrayTranslations;
disableAdd?: boolean;
}
export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
label,
Expand All @@ -30,6 +31,7 @@ export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
enabled,
createDefault,
translations,
disableAdd,
}: ArrayLayoutToolbarProps) {
return (
<Toolbar disableGutters={true}>
Expand Down Expand Up @@ -57,7 +59,7 @@ export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
</Grid>
</Grid>
</Grid>
{enabled && (
{enabled && !disableAdd && (
<Grid item>
<Grid container>
<Grid item>
Expand Down
53 changes: 37 additions & 16 deletions packages/material-renderers/src/layouts/ExpandPanelRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
removeId,
ArrayTranslations,
computeChildLabel,
UpdateArrayContext,
} from '@jsonforms/core';
import {
Accordion,
Expand Down Expand Up @@ -65,6 +66,7 @@ interface OwnPropsOfExpandPanel {
childLabelProp?: string;
handleExpansion(panel: string): (event: any, expanded: boolean) => void;
translations: ArrayTranslations;
disableRemove?: boolean;
}

interface StatePropsOfExpandPanel extends OwnPropsOfExpandPanel {
Expand Down Expand Up @@ -117,6 +119,7 @@ const ExpandPanelRendererComponent = (props: ExpandPanelProps) => {
cells,
config,
translations,
disableRemove,
} = props;

const foundUISchema = useMemo(
Expand Down Expand Up @@ -207,7 +210,7 @@ const ExpandPanelRendererComponent = (props: ExpandPanelProps) => {
) : (
''
)}
{enabled && (
{enabled && !disableRemove && (
<Grid item>
<Tooltip
id='tooltip-remove'
Expand Down Expand Up @@ -262,13 +265,17 @@ export const ctxDispatchToExpandPanelProps: (
(event: any): void => {
event.stopPropagation();
dispatch(
update(path, (array) => {
toDelete
.sort()
.reverse()
.forEach((s) => array.splice(s, 1));
return array;
})
update(
path,
(array) => {
toDelete
.sort()
.reverse()
.forEach((s) => array.splice(s, 1));
return array;
},
{ type: 'REMOVE', indices: toDelete } as UpdateArrayContext
)
);
},
[dispatch]
Expand All @@ -278,10 +285,17 @@ export const ctxDispatchToExpandPanelProps: (
(event: any): void => {
event.stopPropagation();
dispatch(
update(path, (array) => {
moveUp(array, toMove);
return array;
})
update(
path,
(array) => {
moveUp(array, toMove);
return array;
},
{
type: 'MOVE',
moves: [{ from: toMove, to: toMove - 1 }],
} as UpdateArrayContext
)
);
},
[dispatch]
Expand All @@ -291,10 +305,17 @@ export const ctxDispatchToExpandPanelProps: (
(event: any): void => {
event.stopPropagation();
dispatch(
update(path, (array) => {
moveDown(array, toMove);
return array;
})
update(
path,
(array) => {
moveDown(array, toMove);
return array;
},
{
type: 'MOVE',
moves: [{ from: toMove, to: toMove + 1 }],
} as UpdateArrayContext
)
);
},
[dispatch]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
uischemas,
translations,
description,
disableAdd,
disableRemove,
} = props;
const appliedUiSchemaOptions = merge({}, config, props.uischema.options);
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
const doDisableRemove = disableRemove || appliedUiSchemaOptions.disableRemove;

return (
<div>
Expand All @@ -85,6 +89,7 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
enabled={enabled}
addItem={addItem}
createDefault={innerCreateDefaultValue}
disableAdd={doDisableAdd}
/>
<div>
{data > 0 ? (
Expand All @@ -108,6 +113,7 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
childLabelProp={appliedUiSchemaOptions.elementLabelProp}
uischemas={uischemas}
translations={translations}
disableRemove={doDisableRemove}
/>
);
})
Expand Down
Loading

0 comments on commit 87e4061

Please sign in to comment.