Skip to content

Commit 09b39b3

Browse files
committed
feat(widgets): init table grid, autosuggest cell editor
Signed-off-by: Pamfilos Fokianos <pamfilosf@gmail.com>
1 parent 95ba9cc commit 09b39b3

13 files changed

Lines changed: 1188 additions & 10 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
"@rjsf/core": "^5.21.0",
4545
"@rjsf/utils": "^5.21.0",
4646
"@rjsf/validator-ajv8": "^5.21.0",
47+
"ag-grid-community": "^34.3.1",
48+
"ag-grid-react": "^34.3.1",
4749
"ajv": "^8.17.1",
4850
"antd": "^5.26.0",
4951
"axios": "^1.4.0",

src/admin/components/PropertyEditor.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,20 +106,20 @@ const PropertyEditor = () => {
106106
"Root"
107107
) : (
108108
<Space wrap={false}>
109-
{screens.xl && fieldSpec.title}
109+
{screens.xl && fieldSpec?.title}
110110
<Tooltip
111111
title={
112112
<>
113113
{!screens.xl && (
114114
<div style={{ fontWeight: "bold" }}>
115-
{fieldSpec.title}
115+
{fieldSpec?.title}
116116
</div>
117117
)}
118-
<div>{fieldSpec.description}</div>
118+
<div>{fieldSpec?.description}</div>
119119
</>
120120
}
121121
>
122-
{fieldSpec.icon || <QuestionOutlined />}
122+
{fieldSpec?.icon || <QuestionOutlined />}
123123
</Tooltip>
124124
</Space>
125125
)

src/admin/components/SchemaTree.jsx

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,70 @@ import FieldTemplate from "../formComponents/FieldTemplate";
55
import { _validate } from "../utils";
66
import { useSelector } from "react-redux";
77
import CustomizationContext from "../../contexts/CustomizationContext";
8-
import { useContext } from "react";
8+
import { useContext, useMemo } from "react";
99

1010
const SchemaTree = () => {
1111
const schema = useSelector((state) => state.schemaWizard.current.schema);
1212
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema);
1313

1414
const customizationContext = useContext(CustomizationContext);
1515

16+
// Memoize removeUiWidget function so it's not recreated on every render
17+
const removeUiWidget = useMemo(() => {
18+
return function removeUiWidgetRecursive(_obj) {
19+
// Handle null/undefined
20+
if (_obj == null) {
21+
return _obj;
22+
}
23+
24+
// Handle arrays - recursively process each element
25+
if (Array.isArray(_obj)) {
26+
return _obj.map((item) => removeUiWidgetRecursive(item));
27+
}
28+
29+
// Handle objects
30+
if (typeof _obj === "object") {
31+
const obj = {};
32+
for (const key in _obj) {
33+
// Skip the ui:widget property if its value is "table"
34+
if (key === "ui:widget" && _obj[key] === "table") {
35+
continue;
36+
}
37+
// Recursively process nested objects/arrays
38+
obj[key] = removeUiWidgetRecursive(_obj[key]);
39+
}
40+
return obj;
41+
}
42+
43+
// Return primitive values as-is
44+
return _obj;
45+
};
46+
}, []);
47+
48+
// Memoize transformed schema - only recompute when schema changes
49+
const transformedSchema = useMemo(
50+
() => customizationContext.transformSchema(schema),
51+
[customizationContext, schema],
52+
);
53+
54+
// Memoize cleaned uiSchema - only recompute when uiSchema changes
55+
const cleanedUiSchema = useMemo(
56+
() => removeUiWidget(uiSchema),
57+
[removeUiWidget, uiSchema],
58+
);
59+
1660
return (
1761
<Form
18-
schema={customizationContext.transformSchema(schema)}
19-
uiSchema={uiSchema}
62+
schema={transformedSchema}
63+
uiSchema={cleanedUiSchema}
2064
formData={{}}
2165
ObjectFieldTemplate={ObjectFieldTemplate}
2266
ArrayFieldTemplate={ArrayFieldTemplate}
2367
FieldTemplate={FieldTemplate}
2468
onChange={() => {}}
2569
validate={_validate}
2670
liveValidate
27-
formContext={{ schema: [], uiSchema: [] }}
71+
formContext={{ tree: true, schema: [], uiSchema: [] }}
2872
className="schemaTree"
2973
/>
3074
);

src/admin/formComponents/SchemaTreeItem.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ const SchemaTreeItem = ({
7575
<Row gutter={8} onClick={handleClick} align="middle" wrap={false}>
7676
<Col flex="none">
7777
{getFieldSpec(schema, uiSchema, customizationContext.allFieldTypes)
78-
.icon || <QuestionOutlined />}
78+
?.icon || <QuestionOutlined />}
7979
</Col>
8080
<Col flex="auto">
8181
<Row

src/admin/utils/fieldTypes.jsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,92 @@ const collections = {
301301
uiSchema: {},
302302
},
303303
},
304+
TableArrayFieldTemplate: {
305+
title: "Table",
306+
icon: <UnorderedListOutlined />,
307+
description: "List of fields supporting addition, deletion and reordering",
308+
className: "tour-list-field",
309+
child: {},
310+
optionsSchema: {
311+
type: "object",
312+
title: "Array Schema",
313+
properties: {
314+
...common.optionsSchema,
315+
},
316+
},
317+
optionsSchemaUiSchema: {
318+
...common.optionsSchemaUiSchema,
319+
},
320+
optionsUiSchema: {
321+
type: "object",
322+
title: "UI Schema",
323+
properties: {
324+
"ui:options": {
325+
type: "object",
326+
title: "UI Options",
327+
properties: {
328+
...common.optionsUiSchema.properties["ui:options"].properties,
329+
itemsDisplayTitle: {
330+
type: "string",
331+
title: "Items Display Title",
332+
description:
333+
"You can set a fixed value or you can reference child fields by id between `{{` and `}}`",
334+
tooltip:
335+
"You can easily copy the field id by right-clicking the desired field in the tree",
336+
},
337+
},
338+
},
339+
"ui:label": common.optionsUiSchema.properties["ui:label"],
340+
},
341+
},
342+
optionsUiSchemaUiSchema: {
343+
...common.optionsUiSchemaUiSchema,
344+
"ui:options": {
345+
...common.optionsUiSchemaUiSchema["ui:options"],
346+
itemsDisplayTitle: {
347+
"ui:options": {
348+
descriptionIsMarkdown: true,
349+
showAsModal: true,
350+
modal: {
351+
buttonInNewLine: true,
352+
},
353+
codeEditor: {
354+
minimal: true,
355+
language: "jinja",
356+
extraExtensions: [
357+
placeholder("Path: {{item_123}} - Type: {{item_456}}"),
358+
],
359+
height: "200px",
360+
},
361+
},
362+
"ui:field": "codeEditor",
363+
},
364+
},
365+
},
366+
367+
default: {
368+
schema: {
369+
type: "array",
370+
items: {
371+
type: "object",
372+
properties: {
373+
col1: {
374+
type: "string",
375+
title: "Column 1",
376+
},
377+
col2: {
378+
type: "number",
379+
title: "Number Col",
380+
},
381+
},
382+
},
383+
},
384+
uiSchema: {
385+
"ui:widget": "table",
386+
},
387+
},
388+
},
389+
304390
accordion: {
305391
title: "Accordion",
306392
icon: <BorderTopOutlined />,

src/forms/Form.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import { Provider } from "react-redux";
1616
import store from "../store/configureStore";
1717
import FormErrorBoundary from "./FormErrorBoundary";
1818

19+
import { AllCommunityModule, ModuleRegistry } from "ag-grid-community";
20+
ModuleRegistry.registerModules([AllCommunityModule]);
21+
1922
const RJSFForm = ({
2023
formRef,
2124
schema,

src/forms/templates/ArrayFieldTemplates/ArrayFieldTemplate.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ const ArrayFieldTemplate = ({
8383
),
8484
default: items.map((itemProps, index) => (
8585
<ArrayFieldTemplateItem
86-
key={idSchema.$id + index}
8786
{...itemProps}
87+
key={idSchema.$id + index}
8888
formContext={formContext}
8989
/>
9090
)),
@@ -341,6 +341,7 @@ ArrayFieldTemplate.propTypes = {
341341
title: PropTypes.string,
342342
uiSchema: PropTypes.object,
343343
formData: PropTypes.object,
344+
onChange: PropTypes.func,
344345
};
345346

346347
export default ArrayFieldTemplate;

0 commit comments

Comments
 (0)