Skip to content

Commit 87e4061

Browse files
eneufeldsdirix
andauthored
feat: add support for disabling add and remove in React Material
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 <sdirix@eclipsesource.com>
1 parent 52aa15a commit 87e4061

11 files changed

+389
-33
lines changed

packages/core/src/util/renderer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@ export interface OwnPropsOfMasterListItem {
726726
handleSelect(index: number): () => void;
727727
removeItem(path: string, value: number): () => void;
728728
translations: ArrayTranslations;
729+
disableRemove?: boolean;
729730
}
730731

731732
export interface StatePropsOfMasterItem extends OwnPropsOfMasterListItem {
@@ -1133,6 +1134,8 @@ export interface StatePropsOfArrayLayout extends StatePropsOfControlWithDetail {
11331134
data: number;
11341135
translations: ArrayTranslations;
11351136
minItems?: number;
1137+
disableRemove?: boolean;
1138+
disableAdd?: boolean;
11361139
}
11371140
/**
11381141
* Map state to table props

packages/material-renderers/src/additional/ListWithDetailMasterItem.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,15 @@ export const ListWithDetailMasterItem = ({
4545
removeItem,
4646
path,
4747
translations,
48+
disableRemove,
4849
}: StatePropsOfMasterItem) => {
4950
return (
5051
<ListItem button selected={selected} onClick={handleSelect(index)}>
5152
<ListItemAvatar>
5253
<Avatar aria-label='Index'>{index + 1}</Avatar>
5354
</ListItemAvatar>
5455
<ListItemText primary={childLabel} />
55-
{enabled && (
56+
{enabled && !disableRemove && (
5657
<ListItemSecondaryAction>
5758
<Tooltip
5859
id='tooltip-remove'

packages/material-renderers/src/additional/MaterialListWithDetailRenderer.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export const MaterialListWithDetailRenderer = ({
6565
rootSchema,
6666
translations,
6767
description,
68+
disableAdd,
69+
disableRemove,
6870
}: ArrayLayoutProps) => {
6971
const [selectedIndex, setSelectedIndex] = useState(undefined);
7072
const handleRemoveItem = useCallback(
@@ -100,6 +102,8 @@ export const MaterialListWithDetailRenderer = ({
100102
[uischemas, schema, uischema.scope, path, uischema, rootSchema]
101103
);
102104
const appliedUiSchemaOptions = merge({}, config, uischema.options);
105+
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
106+
const doDisableRemove = disableRemove || appliedUiSchemaOptions.disableRemove;
103107

104108
React.useEffect(() => {
105109
setSelectedIndex(undefined);
@@ -124,6 +128,7 @@ export const MaterialListWithDetailRenderer = ({
124128
enabled={enabled}
125129
addItem={addItem}
126130
createDefault={handleCreateDefaultValue}
131+
disableAdd={doDisableAdd}
127132
/>
128133
<Grid container direction='row' spacing={2}>
129134
<Grid item xs={3}>
@@ -142,6 +147,7 @@ export const MaterialListWithDetailRenderer = ({
142147
uischema={foundUISchema}
143148
childLabelProp={appliedUiSchemaOptions.elementLabelProp}
144149
translations={translations}
150+
disableRemove={doDisableRemove}
145151
/>
146152
))
147153
) : (

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

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ interface NonEmptyRowProps {
278278
cells?: JsonFormsCellRendererRegistryEntry[];
279279
path: string;
280280
translations: ArrayTranslations;
281+
disableRemove?: boolean;
281282
}
282283

283284
const NonEmptyRowComponent = ({
@@ -294,6 +295,7 @@ const NonEmptyRowComponent = ({
294295
cells,
295296
path,
296297
translations,
298+
disableRemove,
297299
}: NonEmptyRowProps & WithDeleteDialogSupport) => {
298300
const moveUp = useMemo(
299301
() => moveUpCreator(path, rowIndex),
@@ -354,21 +356,23 @@ const NonEmptyRowComponent = ({
354356
</Grid>
355357
</Fragment>
356358
) : null}
357-
<Grid item>
358-
<Tooltip
359-
id='tooltip-remove'
360-
title={translations.removeTooltip}
361-
placement='bottom'
362-
>
363-
<IconButton
364-
aria-label={translations.removeAriaLabel}
365-
onClick={() => openDeleteDialog(childPath, rowIndex)}
366-
size='large'
359+
{!disableRemove ? (
360+
<Grid item>
361+
<Tooltip
362+
id='tooltip-remove'
363+
title={translations.removeTooltip}
364+
placement='bottom'
367365
>
368-
<DeleteIcon />
369-
</IconButton>
370-
</Tooltip>
371-
</Grid>
366+
<IconButton
367+
aria-label={translations.removeAriaLabel}
368+
onClick={() => openDeleteDialog(childPath, rowIndex)}
369+
size='large'
370+
>
371+
<DeleteIcon />
372+
</IconButton>
373+
</Tooltip>
374+
</Grid>
375+
) : null}
372376
</Grid>
373377
</NoBorderTableCell>
374378
) : null}
@@ -387,6 +391,7 @@ interface TableRowsProp {
387391
moveUp?(path: string, toMove: number): () => void;
388392
moveDown?(path: string, toMove: number): () => void;
389393
translations: ArrayTranslations;
394+
disableRemove?: boolean;
390395
}
391396
const TableRows = ({
392397
data,
@@ -400,6 +405,7 @@ const TableRows = ({
400405
enabled,
401406
cells,
402407
translations,
408+
disableRemove,
403409
}: TableRowsProp & WithDeleteDialogSupport) => {
404410
const isEmptyTable = data === 0;
405411

@@ -438,6 +444,7 @@ const TableRows = ({
438444
cells={cells}
439445
path={path}
440446
translations={translations}
447+
disableRemove={disableRemove}
441448
/>
442449
);
443450
})}
@@ -464,8 +471,16 @@ export class MaterialTableControl extends React.Component<
464471
enabled,
465472
cells,
466473
translations,
474+
disableAdd,
475+
disableRemove,
476+
config,
467477
} = this.props;
468478

479+
const appliedUiSchemaOptions = merge({}, config, uischema.options);
480+
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
481+
const doDisableRemove =
482+
disableRemove || appliedUiSchemaOptions.disableRemove;
483+
469484
const controlElement = uischema as ControlElement;
470485
const isObjectSchema = schema.type === 'object';
471486
const headerCells: any = isObjectSchema
@@ -491,6 +506,7 @@ export class MaterialTableControl extends React.Component<
491506
rootSchema={rootSchema}
492507
enabled={enabled}
493508
translations={translations}
509+
disableAdd={doDisableAdd}
494510
/>
495511
{isObjectSchema && (
496512
<TableRow>
@@ -504,6 +520,7 @@ export class MaterialTableControl extends React.Component<
504520
openDeleteDialog={openDeleteDialog}
505521
translations={translations}
506522
{...this.props}
523+
disableRemove={doDisableRemove}
507524
/>
508525
</TableBody>
509526
</Table>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export interface MaterialTableToolbarProps {
5454
enabled: boolean;
5555
translations: ArrayTranslations;
5656
addItem(path: string, value: any): () => void;
57+
disableAdd?: boolean;
5758
}
5859

5960
const fixedCellSmall = {
@@ -72,6 +73,7 @@ const TableToolbar = React.memo(function TableToolbar({
7273
enabled,
7374
translations,
7475
rootSchema,
76+
disableAdd,
7577
}: MaterialTableToolbarProps) {
7678
return (
7779
<TableRow>
@@ -100,7 +102,7 @@ const TableToolbar = React.memo(function TableToolbar({
100102
{description && <FormHelperText>{description}</FormHelperText>}
101103
</Stack>
102104
</NoBorderTableCell>
103-
{enabled ? (
105+
{enabled && !disableAdd ? (
104106
<NoBorderTableCell align='right' style={fixedCellSmall}>
105107
<Tooltip
106108
id='tooltip-add'

packages/material-renderers/src/layouts/ArrayToolbar.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface ArrayLayoutToolbarProps {
2020
addItem(path: string, data: any): () => void;
2121
createDefault(): any;
2222
translations: ArrayTranslations;
23+
disableAdd?: boolean;
2324
}
2425
export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
2526
label,
@@ -30,6 +31,7 @@ export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
3031
enabled,
3132
createDefault,
3233
translations,
34+
disableAdd,
3335
}: ArrayLayoutToolbarProps) {
3436
return (
3537
<Toolbar disableGutters={true}>
@@ -57,7 +59,7 @@ export const ArrayLayoutToolbar = React.memo(function ArrayLayoutToolbar({
5759
</Grid>
5860
</Grid>
5961
</Grid>
60-
{enabled && (
62+
{enabled && !disableAdd && (
6163
<Grid item>
6264
<Grid container>
6365
<Grid item>

packages/material-renderers/src/layouts/ExpandPanelRenderer.tsx

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
removeId,
3030
ArrayTranslations,
3131
computeChildLabel,
32+
UpdateArrayContext,
3233
} from '@jsonforms/core';
3334
import {
3435
Accordion,
@@ -65,6 +66,7 @@ interface OwnPropsOfExpandPanel {
6566
childLabelProp?: string;
6667
handleExpansion(panel: string): (event: any, expanded: boolean) => void;
6768
translations: ArrayTranslations;
69+
disableRemove?: boolean;
6870
}
6971

7072
interface StatePropsOfExpandPanel extends OwnPropsOfExpandPanel {
@@ -117,6 +119,7 @@ const ExpandPanelRendererComponent = (props: ExpandPanelProps) => {
117119
cells,
118120
config,
119121
translations,
122+
disableRemove,
120123
} = props;
121124

122125
const foundUISchema = useMemo(
@@ -207,7 +210,7 @@ const ExpandPanelRendererComponent = (props: ExpandPanelProps) => {
207210
) : (
208211
''
209212
)}
210-
{enabled && (
213+
{enabled && !disableRemove && (
211214
<Grid item>
212215
<Tooltip
213216
id='tooltip-remove'
@@ -262,13 +265,17 @@ export const ctxDispatchToExpandPanelProps: (
262265
(event: any): void => {
263266
event.stopPropagation();
264267
dispatch(
265-
update(path, (array) => {
266-
toDelete
267-
.sort()
268-
.reverse()
269-
.forEach((s) => array.splice(s, 1));
270-
return array;
271-
})
268+
update(
269+
path,
270+
(array) => {
271+
toDelete
272+
.sort()
273+
.reverse()
274+
.forEach((s) => array.splice(s, 1));
275+
return array;
276+
},
277+
{ type: 'REMOVE', indices: toDelete } as UpdateArrayContext
278+
)
272279
);
273280
},
274281
[dispatch]
@@ -278,10 +285,17 @@ export const ctxDispatchToExpandPanelProps: (
278285
(event: any): void => {
279286
event.stopPropagation();
280287
dispatch(
281-
update(path, (array) => {
282-
moveUp(array, toMove);
283-
return array;
284-
})
288+
update(
289+
path,
290+
(array) => {
291+
moveUp(array, toMove);
292+
return array;
293+
},
294+
{
295+
type: 'MOVE',
296+
moves: [{ from: toMove, to: toMove - 1 }],
297+
} as UpdateArrayContext
298+
)
285299
);
286300
},
287301
[dispatch]
@@ -291,10 +305,17 @@ export const ctxDispatchToExpandPanelProps: (
291305
(event: any): void => {
292306
event.stopPropagation();
293307
dispatch(
294-
update(path, (array) => {
295-
moveDown(array, toMove);
296-
return array;
297-
})
308+
update(
309+
path,
310+
(array) => {
311+
moveDown(array, toMove);
312+
return array;
313+
},
314+
{
315+
type: 'MOVE',
316+
moves: [{ from: toMove, to: toMove + 1 }],
317+
} as UpdateArrayContext
318+
)
298319
);
299320
},
300321
[dispatch]

packages/material-renderers/src/layouts/MaterialArrayLayout.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
6767
uischemas,
6868
translations,
6969
description,
70+
disableAdd,
71+
disableRemove,
7072
} = props;
7173
const appliedUiSchemaOptions = merge({}, config, props.uischema.options);
74+
const doDisableAdd = disableAdd || appliedUiSchemaOptions.disableAdd;
75+
const doDisableRemove = disableRemove || appliedUiSchemaOptions.disableRemove;
7276

7377
return (
7478
<div>
@@ -85,6 +89,7 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
8589
enabled={enabled}
8690
addItem={addItem}
8791
createDefault={innerCreateDefaultValue}
92+
disableAdd={doDisableAdd}
8893
/>
8994
<div>
9095
{data > 0 ? (
@@ -108,6 +113,7 @@ const MaterialArrayLayoutComponent = (props: ArrayLayoutProps) => {
108113
childLabelProp={appliedUiSchemaOptions.elementLabelProp}
109114
uischemas={uischemas}
110115
translations={translations}
116+
disableRemove={doDisableRemove}
111117
/>
112118
);
113119
})

0 commit comments

Comments
 (0)