From 2c3e9760a6a9e94752431183b586718a4822a7f4 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 16 Nov 2022 13:35:55 -0500 Subject: [PATCH] attempting to add a theme w/ burnettk cullerton --- spiffworkflow-frontend/package-lock.json | 66 +++++++++++++ spiffworkflow-frontend/package.json | 1 + .../src/routes/TaskShow.tsx | 3 +- .../src/themes/AddButton/AddButton.tsx | 20 ++++ .../src/themes/AddButton/index.ts | 2 + .../ArrayFieldItemTemplate.tsx | 77 +++++++++++++++ .../themes/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 97 +++++++++++++++++++ .../src/themes/ArrayFieldTemplate/index.ts | 2 + .../BaseInputTemplate/BaseInputTemplate.tsx | 67 +++++++++++++ .../src/themes/BaseInputTemplate/index.ts | 2 + .../themes/CheckboxWidget/CheckboxWidget.tsx | 53 ++++++++++ .../src/themes/CheckboxWidget/index.ts | 2 + .../CheckboxesWidget/CheckboxesWidget.tsx | 83 ++++++++++++++++ .../src/themes/CheckboxesWidget/index.ts | 2 + .../DescriptionField/DescriptionField.tsx | 18 ++++ .../src/themes/DescriptionField/index.ts | 2 + .../src/themes/ErrorList/ErrorList.tsx | 25 +++++ .../src/themes/ErrorList/index.ts | 2 + .../FieldErrorTemplate/FieldErrorTemplate.tsx | 27 ++++++ .../src/themes/FieldErrorTemplate/index.ts | 2 + .../FieldHelpTemplate/FieldHelpTemplate.tsx | 20 ++++ .../src/themes/FieldHelpTemplate/index.ts | 2 + .../themes/FieldTemplate/FieldTemplate.tsx | 73 ++++++++++++++ .../src/themes/FieldTemplate/index.ts | 2 + .../src/themes/FileWidget/FileWidget.tsx | 14 +++ .../src/themes/FileWidget/index.ts | 2 + .../src/themes/Form/Form.tsx | 7 ++ .../src/themes/Form/index.ts | 2 + .../src/themes/IconButton/IconButton.tsx | 43 ++++++++ .../src/themes/IconButton/index.ts | 2 + .../ObjectFieldTemplate.tsx | 91 +++++++++++++++++ .../src/themes/ObjectFieldTemplate/index.ts | 2 + .../src/themes/RadioWidget/RadioWidget.tsx | 65 +++++++++++++ .../src/themes/RadioWidget/index.ts | 2 + .../src/themes/RangeWidget/RangeWidget.tsx | 18 ++++ .../src/themes/RangeWidget/index.ts | 2 + .../src/themes/SelectWidget/SelectWidget.tsx | 89 +++++++++++++++++ .../src/themes/SelectWidget/index.ts | 2 + .../src/themes/SubmitButton/SubmitButton.tsx | 23 +++++ .../src/themes/SubmitButton/index.ts | 2 + .../src/themes/Templates/Templates.ts | 35 +++++++ .../src/themes/Templates/index.ts | 2 + .../themes/TextareaWidget/TextareaWidget.tsx | 56 +++++++++++ .../src/themes/TextareaWidget/index.ts | 2 + .../src/themes/Theme/Theme.tsx | 11 +++ .../src/themes/Theme/index.ts | 2 + .../src/themes/TitleField/TitleField.tsx | 13 +++ .../src/themes/TitleField/index.ts | 2 + .../src/themes/Widgets/Widgets.ts | 17 ++++ .../src/themes/Widgets/index.ts | 2 + .../WrapIfAdditionalTemplate.tsx | 69 +++++++++++++ .../themes/WrapIfAdditionalTemplate/index.ts | 2 + spiffworkflow-frontend/src/themes/index.ts | 8 ++ 54 files changed, 1238 insertions(+), 1 deletion(-) create mode 100644 spiffworkflow-frontend/src/themes/AddButton/AddButton.tsx create mode 100644 spiffworkflow-frontend/src/themes/AddButton/index.ts create mode 100644 spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/ArrayFieldTemplate/ArrayFieldTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/ArrayFieldTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/BaseInputTemplate/BaseInputTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/BaseInputTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/CheckboxWidget/CheckboxWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/CheckboxWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/CheckboxesWidget/CheckboxesWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/CheckboxesWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/DescriptionField/DescriptionField.tsx create mode 100644 spiffworkflow-frontend/src/themes/DescriptionField/index.ts create mode 100644 spiffworkflow-frontend/src/themes/ErrorList/ErrorList.tsx create mode 100644 spiffworkflow-frontend/src/themes/ErrorList/index.ts create mode 100644 spiffworkflow-frontend/src/themes/FieldErrorTemplate/FieldErrorTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/FieldErrorTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/FieldHelpTemplate/FieldHelpTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/FieldHelpTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/FieldTemplate/FieldTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/FieldTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/FileWidget/FileWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/FileWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/Form/Form.tsx create mode 100644 spiffworkflow-frontend/src/themes/Form/index.ts create mode 100644 spiffworkflow-frontend/src/themes/IconButton/IconButton.tsx create mode 100644 spiffworkflow-frontend/src/themes/IconButton/index.ts create mode 100644 spiffworkflow-frontend/src/themes/ObjectFieldTemplate/ObjectFieldTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/ObjectFieldTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/RadioWidget/RadioWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/RadioWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/RangeWidget/RangeWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/RangeWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/SelectWidget/SelectWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/SelectWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/SubmitButton/SubmitButton.tsx create mode 100644 spiffworkflow-frontend/src/themes/SubmitButton/index.ts create mode 100644 spiffworkflow-frontend/src/themes/Templates/Templates.ts create mode 100644 spiffworkflow-frontend/src/themes/Templates/index.ts create mode 100644 spiffworkflow-frontend/src/themes/TextareaWidget/TextareaWidget.tsx create mode 100644 spiffworkflow-frontend/src/themes/TextareaWidget/index.ts create mode 100644 spiffworkflow-frontend/src/themes/Theme/Theme.tsx create mode 100644 spiffworkflow-frontend/src/themes/Theme/index.ts create mode 100644 spiffworkflow-frontend/src/themes/TitleField/TitleField.tsx create mode 100644 spiffworkflow-frontend/src/themes/TitleField/index.ts create mode 100644 spiffworkflow-frontend/src/themes/Widgets/Widgets.ts create mode 100644 spiffworkflow-frontend/src/themes/Widgets/index.ts create mode 100644 spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx create mode 100644 spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/index.ts create mode 100644 spiffworkflow-frontend/src/themes/index.ts diff --git a/spiffworkflow-frontend/package-lock.json b/spiffworkflow-frontend/package-lock.json index 0e242476d..5dc7f8027 100644 --- a/spiffworkflow-frontend/package-lock.json +++ b/spiffworkflow-frontend/package-lock.json @@ -19,6 +19,7 @@ "@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0", "@monaco-editor/react": "^4.4.5", "@rjsf/core": "^4.2.0", + "@rjsf/utils": "^5.0.0-beta.13", "@tanstack/react-table": "^8.2.2", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", @@ -4551,6 +4552,42 @@ "react": ">=16 || >=17" } }, + "node_modules/@rjsf/utils": { + "version": "5.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.0.0-beta.13.tgz", + "integrity": "sha512-hWWWFD2ifjSOhqWueML4OHrZe2HW5pE2nfKGhCObFbwtggHoQlj64xDBsJ1qfUG8DGvCHztJQ/sKIaOvXnpt7w==", + "dependencies": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/utils/node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@rjsf/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -34221,6 +34258,35 @@ "react-is": "16.9.0" } }, + "@rjsf/utils": { + "version": "5.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.0.0-beta.13.tgz", + "integrity": "sha512-hWWWFD2ifjSOhqWueML4OHrZe2HW5pE2nfKGhCObFbwtggHoQlj64xDBsJ1qfUG8DGvCHztJQ/sKIaOvXnpt7w==", + "requires": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "react-is": "^18.2.0" + }, + "dependencies": { + "json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "requires": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", diff --git a/spiffworkflow-frontend/package.json b/spiffworkflow-frontend/package.json index 51d2c4855..6aeb83008 100644 --- a/spiffworkflow-frontend/package.json +++ b/spiffworkflow-frontend/package.json @@ -14,6 +14,7 @@ "@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0", "@monaco-editor/react": "^4.4.5", "@rjsf/core": "^4.2.0", + "@rjsf/utils": "^5.0.0-beta.13", "@tanstack/react-table": "^8.2.2", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 096f408dc..3373eb71d 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -1,11 +1,12 @@ import { useContext, useEffect, useState } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; -import Form from '@rjsf/core'; +// import Form from '@rjsf/core'; // @ts-ignore import { Button, Stack } from '@carbon/react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; +import Form from '../themes'; import HttpService from '../services/HttpService'; import ErrorContext from '../contexts/ErrorContext'; import { modifyProcessModelPath } from '../helpers'; diff --git a/spiffworkflow-frontend/src/themes/AddButton/AddButton.tsx b/spiffworkflow-frontend/src/themes/AddButton/AddButton.tsx new file mode 100644 index 000000000..f88f7153c --- /dev/null +++ b/spiffworkflow-frontend/src/themes/AddButton/AddButton.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import Button from "react-bootstrap/Button"; +import { BsPlus } from "@react-icons/all-files/bs/BsPlus"; + +const AddButton: React.ComponentType = ({ + uiSchema, + ...props +}) => ( + +); + +export default AddButton; diff --git a/spiffworkflow-frontend/src/themes/AddButton/index.ts b/spiffworkflow-frontend/src/themes/AddButton/index.ts new file mode 100644 index 000000000..e41962705 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/AddButton/index.ts @@ -0,0 +1,2 @@ +export { default } from "./AddButton"; +export * from "./AddButton"; diff --git a/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx b/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx new file mode 100644 index 000000000..7858b1cc0 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx @@ -0,0 +1,77 @@ +import React, { CSSProperties } from "react"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import { ArrayFieldTemplateItemType } from "@rjsf/utils"; + +const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => { + const { + children, + disabled, + hasToolbar, + hasMoveDown, + hasMoveUp, + hasRemove, + index, + onDropIndexClick, + onReorderClick, + readonly, + registry, + uiSchema, + } = props; + const { MoveDownButton, MoveUpButton, RemoveButton } = + registry.templates.ButtonTemplates; + const btnStyle: CSSProperties = { + flex: 1, + paddingLeft: 6, + paddingRight: 6, + fontWeight: "bold", + }; + return ( +
+ + + {children} + + + {hasToolbar && ( +
+ {(hasMoveUp || hasMoveDown) && ( +
+ +
+ )} + {(hasMoveUp || hasMoveDown) && ( +
+ +
+ )} + {hasRemove && ( +
+ +
+ )} +
+ )} + +
+
+ ); +}; + +export default ArrayFieldItemTemplate; diff --git a/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/index.ts b/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/index.ts new file mode 100644 index 000000000..f64828beb --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ArrayFieldItemTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ArrayFieldItemTemplate"; +export * from "./ArrayFieldItemTemplate"; diff --git a/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/ArrayFieldTemplate.tsx b/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/ArrayFieldTemplate.tsx new file mode 100644 index 000000000..01d2575e4 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/ArrayFieldTemplate.tsx @@ -0,0 +1,97 @@ +import React from "react"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import Container from "react-bootstrap/Container"; +import { + ArrayFieldTemplateItemType, + ArrayFieldTemplateProps, + getTemplate, + getUiOptions, +} from "@rjsf/utils"; + +const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { + const { + canAdd, + disabled, + idSchema, + uiSchema, + items, + onAddClick, + readonly, + registry, + required, + schema, + title, + } = props; + const uiOptions = getUiOptions(uiSchema); + const ArrayFieldDescriptionTemplate = + getTemplate<"ArrayFieldDescriptionTemplate">( + "ArrayFieldDescriptionTemplate", + registry, + uiOptions + ); + const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate">( + "ArrayFieldItemTemplate", + registry, + uiOptions + ); + const ArrayFieldTitleTemplate = getTemplate<"ArrayFieldTitleTemplate">( + "ArrayFieldTitleTemplate", + registry, + uiOptions + ); + // Button templates are not overridden in the uiSchema + const { + ButtonTemplates: { AddButton }, + } = registry.templates; + return ( +
+ + + + + + {items && + items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => ( + + ))} + {canAdd && ( + + + + + + + + + )} + + + +
+ ); +}; + +export default ArrayFieldTemplate; diff --git a/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/index.ts b/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/index.ts new file mode 100644 index 000000000..29cbde48e --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ArrayFieldTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ArrayFieldTemplate"; +export * from "./ArrayFieldTemplate"; diff --git a/spiffworkflow-frontend/src/themes/BaseInputTemplate/BaseInputTemplate.tsx b/spiffworkflow-frontend/src/themes/BaseInputTemplate/BaseInputTemplate.tsx new file mode 100644 index 000000000..68699d050 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/BaseInputTemplate/BaseInputTemplate.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import Form from "react-bootstrap/Form"; +import { getInputProps, WidgetProps } from "@rjsf/utils"; + +const BaseInputTemplate = ({ + id, + placeholder, + required, + readonly, + disabled, + type, + value, + onChange, + onBlur, + onFocus, + autofocus, + options, + schema, + rawErrors = [], + children, + extraProps, +}: WidgetProps) => { + const inputProps = { ...extraProps, ...getInputProps(schema, type, options) }; + const _onChange = ({ + target: { value }, + }: React.ChangeEvent) => + onChange(value === "" ? options.emptyValue : value); + const _onBlur = ({ target: { value } }: React.FocusEvent) => + onBlur(id, value); + const _onFocus = ({ + target: { value }, + }: React.FocusEvent) => onFocus(id, value); + + // const classNames = [rawErrors.length > 0 ? "is-invalid" : "", type === 'file' ? 'custom-file-label': ""] + return ( + <> + 0 ? "is-invalid" : ""} + list={schema.examples ? `examples_${id}` : undefined} + {...inputProps} + value={value || value === 0 ? value : ""} + onChange={_onChange} + onBlur={_onBlur} + onFocus={_onFocus} + /> + {children} + {schema.examples ? ( + + {(schema.examples as string[]) + .concat(schema.default ? ([schema.default] as string[]) : []) + .map((example: any) => { + return + ) : null} + + ); +}; + +export default BaseInputTemplate; diff --git a/spiffworkflow-frontend/src/themes/BaseInputTemplate/index.ts b/spiffworkflow-frontend/src/themes/BaseInputTemplate/index.ts new file mode 100644 index 000000000..37c3947ed --- /dev/null +++ b/spiffworkflow-frontend/src/themes/BaseInputTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./BaseInputTemplate"; +export * from "./BaseInputTemplate"; diff --git a/spiffworkflow-frontend/src/themes/CheckboxWidget/CheckboxWidget.tsx b/spiffworkflow-frontend/src/themes/CheckboxWidget/CheckboxWidget.tsx new file mode 100644 index 000000000..f2e665d41 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/CheckboxWidget/CheckboxWidget.tsx @@ -0,0 +1,53 @@ +import React from "react"; + +import { WidgetProps } from "@rjsf/utils"; +import Form from "react-bootstrap/Form"; + +const CheckboxWidget = (props: WidgetProps) => { + const { + id, + value, + required, + disabled, + readonly, + label, + schema, + autofocus, + onChange, + onBlur, + onFocus, + } = props; + + const _onChange = ({ + target: { checked }, + }: React.FocusEvent) => onChange(checked); + const _onBlur = ({ + target: { checked }, + }: React.FocusEvent) => onBlur(id, checked); + const _onFocus = ({ + target: { checked }, + }: React.FocusEvent) => onFocus(id, checked); + + const desc = label || schema.description; + return ( + + + + ); +}; + +export default CheckboxWidget; diff --git a/spiffworkflow-frontend/src/themes/CheckboxWidget/index.ts b/spiffworkflow-frontend/src/themes/CheckboxWidget/index.ts new file mode 100644 index 000000000..9a6515772 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/CheckboxWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./CheckboxWidget"; +export * from "./CheckboxWidget"; diff --git a/spiffworkflow-frontend/src/themes/CheckboxesWidget/CheckboxesWidget.tsx b/spiffworkflow-frontend/src/themes/CheckboxesWidget/CheckboxesWidget.tsx new file mode 100644 index 000000000..71646084e --- /dev/null +++ b/spiffworkflow-frontend/src/themes/CheckboxesWidget/CheckboxesWidget.tsx @@ -0,0 +1,83 @@ +import React from "react"; +import Form from "react-bootstrap/Form"; +import { WidgetProps } from "@rjsf/utils"; + +const selectValue = (value: any, selected: any, all: any) => { + const at = all.indexOf(value); + const updated = selected.slice(0, at).concat(value, selected.slice(at)); + + // As inserting values at predefined index positions doesn't work with empty + // arrays, we need to reorder the updated selection to match the initial order + return updated.sort((a: any, b: any) => all.indexOf(a) > all.indexOf(b)); +}; + +const deselectValue = (value: any, selected: any) => { + return selected.filter((v: any) => v !== value); +}; + +const CheckboxesWidget = ({ + id, + disabled, + options, + value, + autofocus, + readonly, + required, + onChange, + onBlur, + onFocus, +}: WidgetProps) => { + const { enumOptions, enumDisabled, inline } = options; + + const _onChange = + (option: any) => + ({ target: { checked } }: React.ChangeEvent) => { + const all = (enumOptions as any).map(({ value }: any) => value); + + if (checked) { + onChange(selectValue(option.value, value, all)); + } else { + onChange(deselectValue(option.value, value)); + } + }; + + const _onBlur = ({ target: { value } }: React.FocusEvent) => + onBlur(id, value); + const _onFocus = ({ + target: { value }, + }: React.FocusEvent) => onFocus(id, value); + + return ( + + {Array.isArray(enumOptions) && + enumOptions.map((option, index: number) => { + const checked = value.indexOf(option.value) !== -1; + const itemDisabled = + Array.isArray(enumDisabled) && + enumDisabled.indexOf(option.value) !== -1; + + return ( + + ); + })} + + ); +}; + +export default CheckboxesWidget; diff --git a/spiffworkflow-frontend/src/themes/CheckboxesWidget/index.ts b/spiffworkflow-frontend/src/themes/CheckboxesWidget/index.ts new file mode 100644 index 000000000..c5acc6aa1 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/CheckboxesWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./CheckboxesWidget"; +export * from "./CheckboxesWidget"; diff --git a/spiffworkflow-frontend/src/themes/DescriptionField/DescriptionField.tsx b/spiffworkflow-frontend/src/themes/DescriptionField/DescriptionField.tsx new file mode 100644 index 000000000..1e6e0eccb --- /dev/null +++ b/spiffworkflow-frontend/src/themes/DescriptionField/DescriptionField.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { DescriptionFieldProps } from "@rjsf/utils"; + +const DescriptionField = ({ id, description }: DescriptionFieldProps) => { + if (description) { + return ( +
+
+ {description} +
+
+ ); + } + + return null; +}; + +export default DescriptionField; diff --git a/spiffworkflow-frontend/src/themes/DescriptionField/index.ts b/spiffworkflow-frontend/src/themes/DescriptionField/index.ts new file mode 100644 index 000000000..899add9fc --- /dev/null +++ b/spiffworkflow-frontend/src/themes/DescriptionField/index.ts @@ -0,0 +1,2 @@ +export { default } from "./DescriptionField"; +export * from "./DescriptionField"; diff --git a/spiffworkflow-frontend/src/themes/ErrorList/ErrorList.tsx b/spiffworkflow-frontend/src/themes/ErrorList/ErrorList.tsx new file mode 100644 index 000000000..61dd66312 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ErrorList/ErrorList.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +import Card from "react-bootstrap/Card"; +import ListGroup from "react-bootstrap/ListGroup"; + +import { ErrorListProps } from "@rjsf/utils"; + +const ErrorList = ({ errors }: ErrorListProps) => ( + + Errors + + + {errors.map((error, i: number) => { + return ( + + {error.stack} + + ); + })} + + + +); + +export default ErrorList; diff --git a/spiffworkflow-frontend/src/themes/ErrorList/index.ts b/spiffworkflow-frontend/src/themes/ErrorList/index.ts new file mode 100644 index 000000000..af63a176f --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ErrorList/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ErrorList"; +export * from "./ErrorList"; diff --git a/spiffworkflow-frontend/src/themes/FieldErrorTemplate/FieldErrorTemplate.tsx b/spiffworkflow-frontend/src/themes/FieldErrorTemplate/FieldErrorTemplate.tsx new file mode 100644 index 000000000..f1709ddaf --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldErrorTemplate/FieldErrorTemplate.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { FieldErrorProps } from "@rjsf/utils"; +import ListGroup from "react-bootstrap/ListGroup"; + +/** The `FieldErrorTemplate` component renders the errors local to the particular field + * + * @param props - The `FieldErrorProps` for the errors being rendered + */ +export default function FieldErrorTemplate(props: FieldErrorProps) { + const { errors = [], idSchema } = props; + if (errors.length === 0) { + return null; + } + const id = `${idSchema.$id}__error`; + + return ( + + {errors.map((error, i) => { + return ( + + {error} + + ); + })} + + ); +} diff --git a/spiffworkflow-frontend/src/themes/FieldErrorTemplate/index.ts b/spiffworkflow-frontend/src/themes/FieldErrorTemplate/index.ts new file mode 100644 index 000000000..dd9c569ff --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldErrorTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./FieldErrorTemplate"; +export * from "./FieldErrorTemplate"; diff --git a/spiffworkflow-frontend/src/themes/FieldHelpTemplate/FieldHelpTemplate.tsx b/spiffworkflow-frontend/src/themes/FieldHelpTemplate/FieldHelpTemplate.tsx new file mode 100644 index 000000000..271923188 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldHelpTemplate/FieldHelpTemplate.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { FieldHelpProps } from "@rjsf/utils"; +import Form from "react-bootstrap/Form"; + +/** The `FieldHelpTemplate` component renders any help desired for a field + * + * @param props - The `FieldHelpProps` to be rendered + */ +export default function FieldHelpTemplate(props: FieldHelpProps) { + const { idSchema, help, hasErrors } = props; + if (!help) { + return null; + } + const id = `${idSchema.$id}__help`; + return ( + + {help} + + ); +} diff --git a/spiffworkflow-frontend/src/themes/FieldHelpTemplate/index.ts b/spiffworkflow-frontend/src/themes/FieldHelpTemplate/index.ts new file mode 100644 index 000000000..55b9f4a09 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldHelpTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./FieldHelpTemplate"; +export * from "./FieldHelpTemplate"; diff --git a/spiffworkflow-frontend/src/themes/FieldTemplate/FieldTemplate.tsx b/spiffworkflow-frontend/src/themes/FieldTemplate/FieldTemplate.tsx new file mode 100644 index 000000000..ace72557d --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldTemplate/FieldTemplate.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import { FieldTemplateProps, getTemplate, getUiOptions } from "@rjsf/utils"; +import Form from "react-bootstrap/Form"; + +const FieldTemplate = ({ + id, + children, + displayLabel, + rawErrors = [], + errors, + help, + rawDescription, + classNames, + disabled, + label, + hidden, + onDropPropertyClick, + onKeyChange, + readonly, + required, + schema, + uiSchema, + registry, +}: FieldTemplateProps) => { + const uiOptions = getUiOptions(uiSchema); + const WrapIfAdditionalTemplate = getTemplate<"WrapIfAdditionalTemplate">( + "WrapIfAdditionalTemplate", + registry, + uiOptions + ); + if (hidden) { + return
{children}
; + } + return ( + + + {displayLabel && ( + 0 ? "text-danger" : ""} + > + {label} + {required ? "*" : null} + + )} + {children} + {displayLabel && rawDescription && ( + 0 ? "text-danger" : "text-muted"} + > + {rawDescription} + + )} + {errors} + {help} + + + ); +}; + +export default FieldTemplate; diff --git a/spiffworkflow-frontend/src/themes/FieldTemplate/index.ts b/spiffworkflow-frontend/src/themes/FieldTemplate/index.ts new file mode 100644 index 000000000..290c188da --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FieldTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./FieldTemplate"; +export * from "./FieldTemplate"; diff --git a/spiffworkflow-frontend/src/themes/FileWidget/FileWidget.tsx b/spiffworkflow-frontend/src/themes/FileWidget/FileWidget.tsx new file mode 100644 index 000000000..4bd934b4b --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FileWidget/FileWidget.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import { getTemplate, WidgetProps } from "@rjsf/utils"; + +const FileWidget = (props: WidgetProps) => { + const { options, registry } = props; + const BaseInputTemplate = getTemplate<"BaseInputTemplate">( + "BaseInputTemplate", + registry, + options + ); + return ; +}; + +export default FileWidget; diff --git a/spiffworkflow-frontend/src/themes/FileWidget/index.ts b/spiffworkflow-frontend/src/themes/FileWidget/index.ts new file mode 100644 index 000000000..e70174ced --- /dev/null +++ b/spiffworkflow-frontend/src/themes/FileWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./FileWidget"; +export * from "./FileWidget"; diff --git a/spiffworkflow-frontend/src/themes/Form/Form.tsx b/spiffworkflow-frontend/src/themes/Form/Form.tsx new file mode 100644 index 000000000..e19361924 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Form/Form.tsx @@ -0,0 +1,7 @@ +import { withTheme, FormProps } from "@rjsf/core"; + +import Theme from "../Theme"; + +const Form: React.ComponentType = withTheme(Theme); + +export default Form; diff --git a/spiffworkflow-frontend/src/themes/Form/index.ts b/spiffworkflow-frontend/src/themes/Form/index.ts new file mode 100644 index 000000000..dbca2de64 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Form/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Form"; +export * from "./Form"; diff --git a/spiffworkflow-frontend/src/themes/IconButton/IconButton.tsx b/spiffworkflow-frontend/src/themes/IconButton/IconButton.tsx new file mode 100644 index 000000000..6a8e00fe4 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/IconButton/IconButton.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import Button, { ButtonProps } from "react-bootstrap/Button"; +import { IoIosRemove } from "@react-icons/all-files/io/IoIosRemove"; +import { AiOutlineArrowUp } from "@react-icons/all-files/ai/AiOutlineArrowUp"; +import { AiOutlineArrowDown } from "@react-icons/all-files/ai/AiOutlineArrowDown"; + +const IconButton = (props: IconButtonProps & ButtonProps) => { + const { icon, iconType, className, uiSchema, ...otherProps } = props; + return ( + + ); +}; + +export default IconButton; + +export function MoveDownButton(props: IconButtonProps) { + return ( + } /> + ); +} + +export function MoveUpButton(props: IconButtonProps) { + return } />; +} + +export function RemoveButton(props: IconButtonProps) { + return ( + } + /> + ); +} diff --git a/spiffworkflow-frontend/src/themes/IconButton/index.ts b/spiffworkflow-frontend/src/themes/IconButton/index.ts new file mode 100644 index 000000000..55447475b --- /dev/null +++ b/spiffworkflow-frontend/src/themes/IconButton/index.ts @@ -0,0 +1,2 @@ +export { default } from "./IconButton"; +export * from "./IconButton"; diff --git a/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/ObjectFieldTemplate.tsx b/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/ObjectFieldTemplate.tsx new file mode 100644 index 000000000..83008ec06 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/ObjectFieldTemplate.tsx @@ -0,0 +1,91 @@ +import React from "react"; + +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import Container from "react-bootstrap/Container"; + +import { + canExpand, + getTemplate, + getUiOptions, + ObjectFieldTemplateProps, +} from "@rjsf/utils"; + +const ObjectFieldTemplate = ({ + description, + title, + properties, + required, + uiSchema, + idSchema, + schema, + formData, + onAddClick, + disabled, + readonly, + registry, +}: ObjectFieldTemplateProps) => { + const uiOptions = getUiOptions(uiSchema); + const TitleFieldTemplate = getTemplate<"TitleFieldTemplate">( + "TitleFieldTemplate", + registry, + uiOptions + ); + const DescriptionFieldTemplate = getTemplate<"DescriptionFieldTemplate">( + "DescriptionFieldTemplate", + registry, + uiOptions + ); + // Button templates are not overridden in the uiSchema + const { + ButtonTemplates: { AddButton }, + } = registry.templates; + return ( + <> + {(uiOptions.title || title) && ( + + )} + {(uiOptions.description || description) && ( + + )} + + {properties.map((element: any, index: number) => ( + + {element.content} + + ))} + {canExpand(schema, uiSchema, formData) ? ( + + + + + + ) : null} + + + ); +}; + +export default ObjectFieldTemplate; diff --git a/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/index.ts b/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/index.ts new file mode 100644 index 000000000..b7e3ae624 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/ObjectFieldTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ObjectFieldTemplate"; +export * from "./ObjectFieldTemplate"; diff --git a/spiffworkflow-frontend/src/themes/RadioWidget/RadioWidget.tsx b/spiffworkflow-frontend/src/themes/RadioWidget/RadioWidget.tsx new file mode 100644 index 000000000..715a66e1d --- /dev/null +++ b/spiffworkflow-frontend/src/themes/RadioWidget/RadioWidget.tsx @@ -0,0 +1,65 @@ +import React from "react"; + +import Form from "react-bootstrap/Form"; + +import { WidgetProps } from "@rjsf/utils"; + +const RadioWidget = ({ + id, + schema, + options, + value, + required, + disabled, + readonly, + onChange, + onBlur, + onFocus, +}: WidgetProps) => { + const { enumOptions, enumDisabled } = options; + + const _onChange = ({ + target: { value }, + }: React.ChangeEvent) => + onChange(schema.type == "boolean" ? value !== "false" : value); + const _onBlur = ({ target: { value } }: React.FocusEvent) => + onBlur(id, value); + const _onFocus = ({ + target: { value }, + }: React.FocusEvent) => onFocus(id, value); + + const inline = Boolean(options && options.inline); + + return ( + + {Array.isArray(enumOptions) && + enumOptions.map((option) => { + const itemDisabled = + Array.isArray(enumDisabled) && + enumDisabled.indexOf(option.value) !== -1; + const checked = option.value == value; + + const radio = ( + + ); + return radio; + })} + + ); +}; + +export default RadioWidget; diff --git a/spiffworkflow-frontend/src/themes/RadioWidget/index.ts b/spiffworkflow-frontend/src/themes/RadioWidget/index.ts new file mode 100644 index 000000000..f0568f0d8 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/RadioWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./RadioWidget"; +export * from "./RadioWidget"; diff --git a/spiffworkflow-frontend/src/themes/RangeWidget/RangeWidget.tsx b/spiffworkflow-frontend/src/themes/RangeWidget/RangeWidget.tsx new file mode 100644 index 000000000..f75d3756c --- /dev/null +++ b/spiffworkflow-frontend/src/themes/RangeWidget/RangeWidget.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { getTemplate, WidgetProps } from "@rjsf/utils"; + +const RangeWidget = (props: WidgetProps) => { + const { value, label, options, registry } = props; + const BaseInputTemplate = getTemplate<"BaseInputTemplate">( + "BaseInputTemplate", + registry, + options + ); + return ( + + {value} + + ); +}; + +export default RangeWidget; diff --git a/spiffworkflow-frontend/src/themes/RangeWidget/index.ts b/spiffworkflow-frontend/src/themes/RangeWidget/index.ts new file mode 100644 index 000000000..70a8e7601 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/RangeWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./RangeWidget"; +export * from "./RangeWidget"; diff --git a/spiffworkflow-frontend/src/themes/SelectWidget/SelectWidget.tsx b/spiffworkflow-frontend/src/themes/SelectWidget/SelectWidget.tsx new file mode 100644 index 000000000..07864f0e6 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/SelectWidget/SelectWidget.tsx @@ -0,0 +1,89 @@ +import React from "react"; + +import Form from "react-bootstrap/Form"; + +import { processSelectValue, WidgetProps } from "@rjsf/utils"; + +const SelectWidget = ({ + schema, + id, + options, + required, + disabled, + readonly, + value, + multiple, + autofocus, + onChange, + onBlur, + onFocus, + placeholder, + rawErrors = [], +}: WidgetProps) => { + const { enumOptions, enumDisabled } = options; + + const emptyValue = multiple ? [] : ""; + + function getValue( + event: React.FocusEvent | React.ChangeEvent | any, + multiple?: boolean + ) { + if (multiple) { + return [].slice + .call(event.target.options as any) + .filter((o: any) => o.selected) + .map((o: any) => o.value); + } else { + return event.target.value; + } + } + + return ( + 0 ? "is-invalid" : ""} + onBlur={ + onBlur && + ((event: React.FocusEvent) => { + const newValue = getValue(event, multiple); + onBlur(id, processSelectValue(schema, newValue, options)); + }) + } + onFocus={ + onFocus && + ((event: React.FocusEvent) => { + const newValue = getValue(event, multiple); + onFocus(id, processSelectValue(schema, newValue, options)); + }) + } + onChange={(event: React.ChangeEvent) => { + const newValue = getValue(event, multiple); + onChange(processSelectValue(schema, newValue, options)); + }} + > + {!multiple && schema.default === undefined && ( + + )} + {(enumOptions as any).map(({ value, label }: any, i: number) => { + const disabled: any = + Array.isArray(enumDisabled) && + (enumDisabled as any).indexOf(value) != -1; + return ( + + ); + })} + + ); +}; + +export default SelectWidget; diff --git a/spiffworkflow-frontend/src/themes/SelectWidget/index.ts b/spiffworkflow-frontend/src/themes/SelectWidget/index.ts new file mode 100644 index 000000000..91a604a36 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/SelectWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./SelectWidget"; +export * from "./SelectWidget"; diff --git a/spiffworkflow-frontend/src/themes/SubmitButton/SubmitButton.tsx b/spiffworkflow-frontend/src/themes/SubmitButton/SubmitButton.tsx new file mode 100644 index 000000000..fc88cc93f --- /dev/null +++ b/spiffworkflow-frontend/src/themes/SubmitButton/SubmitButton.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import Button from "react-bootstrap/Button"; +import { getSubmitButtonOptions, SubmitButtonProps } from "@rjsf/utils"; + +const SubmitButton: React.ComponentType = (props) => { + const { + submitText, + norender, + props: submitButtonProps, + } = getSubmitButtonOptions(props.uiSchema); + if (norender) { + return null; + } + return ( +
+ +
+ ); +}; + +export default SubmitButton; diff --git a/spiffworkflow-frontend/src/themes/SubmitButton/index.ts b/spiffworkflow-frontend/src/themes/SubmitButton/index.ts new file mode 100644 index 000000000..467dba249 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/SubmitButton/index.ts @@ -0,0 +1,2 @@ +export { default } from "./SubmitButton"; +export * from "./SubmitButton"; diff --git a/spiffworkflow-frontend/src/themes/Templates/Templates.ts b/spiffworkflow-frontend/src/themes/Templates/Templates.ts new file mode 100644 index 000000000..e8eef55a0 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Templates/Templates.ts @@ -0,0 +1,35 @@ +import AddButton from "../AddButton"; +import ArrayFieldItemTemplate from "../ArrayFieldItemTemplate"; +import ArrayFieldTemplate from "../ArrayFieldTemplate"; +import BaseInputTemplate from "../BaseInputTemplate/BaseInputTemplate"; +import DescriptionField from "../DescriptionField"; +import ErrorList from "../ErrorList"; +import { MoveDownButton, MoveUpButton, RemoveButton } from "../IconButton"; +import FieldErrorTemplate from "../FieldErrorTemplate"; +import FieldHelpTemplate from "../FieldHelpTemplate"; +import FieldTemplate from "../FieldTemplate"; +import ObjectFieldTemplate from "../ObjectFieldTemplate"; +import SubmitButton from "../SubmitButton"; +import TitleField from "../TitleField"; +import WrapIfAdditionalTemplate from "../WrapIfAdditionalTemplate"; + +export default { + ArrayFieldItemTemplate, + ArrayFieldTemplate, + BaseInputTemplate, + ButtonTemplates: { + AddButton, + MoveDownButton, + MoveUpButton, + RemoveButton, + SubmitButton, + }, + DescriptionFieldTemplate: DescriptionField, + ErrorListTemplate: ErrorList, + FieldErrorTemplate, + FieldHelpTemplate, + FieldTemplate, + ObjectFieldTemplate, + TitleFieldTemplate: TitleField, + WrapIfAdditionalTemplate, +}; diff --git a/spiffworkflow-frontend/src/themes/Templates/index.ts b/spiffworkflow-frontend/src/themes/Templates/index.ts new file mode 100644 index 000000000..0c3e935ca --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Templates/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Templates"; +export * from "./Templates"; diff --git a/spiffworkflow-frontend/src/themes/TextareaWidget/TextareaWidget.tsx b/spiffworkflow-frontend/src/themes/TextareaWidget/TextareaWidget.tsx new file mode 100644 index 000000000..afb2c98da --- /dev/null +++ b/spiffworkflow-frontend/src/themes/TextareaWidget/TextareaWidget.tsx @@ -0,0 +1,56 @@ +import React from "react"; + +import { WidgetProps } from "@rjsf/utils"; +import FormControl from "react-bootstrap/FormControl"; +import InputGroup from "react-bootstrap/InputGroup"; + +type CustomWidgetProps = WidgetProps & { + options: any; +}; + +const TextareaWidget = ({ + id, + placeholder, + value, + required, + disabled, + autofocus, + readonly, + onBlur, + onFocus, + onChange, + options, +}: CustomWidgetProps) => { + const _onChange = ({ + target: { value }, + }: React.ChangeEvent) => + onChange(value === "" ? options.emptyValue : value); + const _onBlur = ({ + target: { value }, + }: React.FocusEvent) => onBlur(id, value); + const _onFocus = ({ + target: { value }, + }: React.FocusEvent) => onFocus(id, value); + + return ( + + + + ); +}; + +export default TextareaWidget; diff --git a/spiffworkflow-frontend/src/themes/TextareaWidget/index.ts b/spiffworkflow-frontend/src/themes/TextareaWidget/index.ts new file mode 100644 index 000000000..1c7268c66 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/TextareaWidget/index.ts @@ -0,0 +1,2 @@ +export { default } from "./TextareaWidget"; +export * from "./TextareaWidget"; diff --git a/spiffworkflow-frontend/src/themes/Theme/Theme.tsx b/spiffworkflow-frontend/src/themes/Theme/Theme.tsx new file mode 100644 index 000000000..ecfcdd572 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Theme/Theme.tsx @@ -0,0 +1,11 @@ +import { ThemeProps } from "@rjsf/core"; + +import Templates from "../Templates"; +import Widgets from "../Widgets"; + +const Theme: ThemeProps = { + templates: Templates, + widgets: Widgets, +}; + +export default Theme; diff --git a/spiffworkflow-frontend/src/themes/Theme/index.ts b/spiffworkflow-frontend/src/themes/Theme/index.ts new file mode 100644 index 000000000..491c3a07c --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Theme/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Theme"; +export * from "./Theme"; diff --git a/spiffworkflow-frontend/src/themes/TitleField/TitleField.tsx b/spiffworkflow-frontend/src/themes/TitleField/TitleField.tsx new file mode 100644 index 000000000..4606e0d15 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/TitleField/TitleField.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { TitleFieldProps } from "@rjsf/utils"; + +const TitleField = ({ id, title, uiSchema }: TitleFieldProps) => ( + <> +
+
{(uiSchema && uiSchema["ui:title"]) || title}
+
+
+ +); + +export default TitleField; diff --git a/spiffworkflow-frontend/src/themes/TitleField/index.ts b/spiffworkflow-frontend/src/themes/TitleField/index.ts new file mode 100644 index 000000000..2e26cd18f --- /dev/null +++ b/spiffworkflow-frontend/src/themes/TitleField/index.ts @@ -0,0 +1,2 @@ +export { default } from "./TitleField"; +export * from "./TitleField"; diff --git a/spiffworkflow-frontend/src/themes/Widgets/Widgets.ts b/spiffworkflow-frontend/src/themes/Widgets/Widgets.ts new file mode 100644 index 000000000..543a05ec3 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Widgets/Widgets.ts @@ -0,0 +1,17 @@ +import CheckboxWidget from "../CheckboxWidget/CheckboxWidget"; +import CheckboxesWidget from "../CheckboxesWidget/CheckboxesWidget"; +import RadioWidget from "../RadioWidget/RadioWidget"; +import RangeWidget from "../RangeWidget/RangeWidget"; +import SelectWidget from "../SelectWidget/SelectWidget"; +import TextareaWidget from "../TextareaWidget/TextareaWidget"; +import FileWidget from "../FileWidget/FileWidget"; + +export default { + CheckboxWidget, + CheckboxesWidget, + RadioWidget, + RangeWidget, + SelectWidget, + TextareaWidget, + FileWidget, +}; diff --git a/spiffworkflow-frontend/src/themes/Widgets/index.ts b/spiffworkflow-frontend/src/themes/Widgets/index.ts new file mode 100644 index 000000000..595580b54 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/Widgets/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Widgets"; +export * from "./Widgets"; diff --git a/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx b/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx new file mode 100644 index 000000000..3eafe9069 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx @@ -0,0 +1,69 @@ +import React from "react"; + +import { + ADDITIONAL_PROPERTY_FLAG, + WrapIfAdditionalTemplateProps, +} from "@rjsf/utils"; + +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import Form from "react-bootstrap/Form"; + +const WrapIfAdditionalTemplate = ({ + classNames, + children, + disabled, + id, + label, + onDropPropertyClick, + onKeyChange, + readonly, + required, + schema, + uiSchema, + registry, +}: WrapIfAdditionalTemplateProps) => { + // Button templates are not overridden in the uiSchema + const { RemoveButton } = registry.templates.ButtonTemplates; + const keyLabel = `${label} Key`; // i18n ? + const additional = ADDITIONAL_PROPERTY_FLAG in schema; + + if (!additional) { + return
{children}
; + } + + const handleBlur = ({ target }: React.FocusEvent) => + onKeyChange(target.value); + const keyId = `${id}-key`; + + return ( + + + + {keyLabel} + + + + {children} + + + + + ); +}; + +export default WrapIfAdditionalTemplate; diff --git a/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/index.ts b/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/index.ts new file mode 100644 index 000000000..95ba7de22 --- /dev/null +++ b/spiffworkflow-frontend/src/themes/WrapIfAdditionalTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WrapIfAdditionalTemplate"; +export * from "./WrapIfAdditionalTemplate"; diff --git a/spiffworkflow-frontend/src/themes/index.ts b/spiffworkflow-frontend/src/themes/index.ts new file mode 100644 index 000000000..2f409639e --- /dev/null +++ b/spiffworkflow-frontend/src/themes/index.ts @@ -0,0 +1,8 @@ +import Form from './Form/Form'; + +export { default as Form } from './Form'; +export { default as Templates } from './Templates'; +export { default as Theme } from './Theme'; +export { default as Widgets } from './Widgets'; + +export default Form;