Skip to content

Commit 923e630

Browse files
authored
Merge pull request #596 from devtron-labs/feat/flat-gui-schema
feat: add ability to decouple gui schema path and corresponding update path using new updatePath keyword in schema
2 parents 9b55581 + e059e27 commit 923e630

File tree

10 files changed

+299
-77
lines changed

10 files changed

+299
-77
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ src/Common/Modals/VisibleModal2.tsx
4040
src/Common/MultiSelectCustomization.tsx
4141
src/Common/PopupMenu.tsx
4242
src/Common/Progressing.tsx
43-
src/Common/RJSF/Form.tsx
4443
src/Common/RJSF/config.ts
4544
src/Common/RJSF/templates/ArrayFieldTemplate.tsx
4645
src/Common/RJSF/templates/BaseInput.tsx

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "1.8.1",
3+
"version": "1.8.2",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Common/RJSF/Form.tsx

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,94 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { forwardRef } from 'react'
17+
import { forwardRef, useMemo } from 'react'
1818
import RJSF from '@rjsf/core'
1919

20+
import { SCHEMA_07_VALIDATOR } from '@Shared/validations'
2021
import { templates, widgets } from './config'
2122
import { FormProps } from './types'
22-
import { translateString } from './utils'
23-
import { SCHEMA_07_VALIDATOR } from '@Shared/validations'
23+
import {
24+
getFormStateFromFormData,
25+
getSchemaPathToUpdatePathMap,
26+
translateString,
27+
updateFormDataFromFormState,
28+
} from './utils'
2429
import './rjsfForm.scss'
2530

2631
// Need to use this way because the default import was not working as expected
27-
// The default import resolves to an object intead of a function
32+
// The default import resolves to an object instead of a function
2833
const Form = RJSF
2934
const validator = SCHEMA_07_VALIDATOR
3035

31-
export const RJSFForm = forwardRef((props: FormProps, ref: FormProps['ref']) => (
32-
<Form
33-
noHtml5Validate
34-
showErrorList={false}
35-
autoComplete="off"
36-
{...props}
37-
className={`rjsf-form-template__container ${props.className || ''}`}
38-
validator={validator}
39-
templates={{
40-
...templates,
41-
...props.templates,
42-
}}
43-
formContext={props.formData}
44-
widgets={{ ...widgets, ...props.widgets }}
45-
translateString={translateString}
46-
ref={ref}
47-
/>
48-
))
36+
export const RJSFForm = forwardRef((props: FormProps, ref: FormProps['ref']) => {
37+
const { schemaPathToUpdatePathMap, isUpdatePathKeywordPresent } = useMemo(() => {
38+
const map = getSchemaPathToUpdatePathMap(props.schema)
39+
40+
return {
41+
schemaPathToUpdatePathMap: map,
42+
isUpdatePathKeywordPresent: Object.entries(map).some(([path, updatePath]) => path !== updatePath),
43+
}
44+
}, [props.schema])
45+
46+
const formState = useMemo(() => {
47+
if (!isUpdatePathKeywordPresent) {
48+
return props.formData
49+
}
50+
51+
return getFormStateFromFormData({ formData: props.formData ?? {}, schemaPathToUpdatePathMap })
52+
}, [props.formData, schemaPathToUpdatePathMap, isUpdatePathKeywordPresent])
53+
54+
const handleOnChange: FormProps['onChange'] = (data) => {
55+
if (!props.onChange) {
56+
return
57+
}
58+
59+
const updatedFormData = updateFormDataFromFormState({
60+
formState: data.formData,
61+
formData: props.formData,
62+
schemaPathToUpdatePathMap,
63+
})
64+
65+
props.onChange({ ...data, formData: updatedFormData })
66+
}
67+
68+
const handleOnSubmit: FormProps['onSubmit'] = (data, event) => {
69+
if (!props.onSubmit) {
70+
return
71+
}
72+
73+
const updatedFormData = updateFormDataFromFormState({
74+
formState: data.formData,
75+
formData: props.formData,
76+
schemaPathToUpdatePathMap,
77+
})
78+
79+
props.onSubmit?.({ ...data, formData: updatedFormData }, event)
80+
}
81+
82+
return (
83+
<Form
84+
noHtml5Validate
85+
showErrorList={false}
86+
autoComplete="off"
87+
{...props}
88+
formData={formState}
89+
{...(isUpdatePathKeywordPresent
90+
? {
91+
onChange: handleOnChange,
92+
onSubmit: handleOnSubmit,
93+
}
94+
: {})}
95+
className={`rjsf-form-template__container ${props.className || ''}`}
96+
validator={validator}
97+
templates={{
98+
...templates,
99+
...props.templates,
100+
}}
101+
formContext={formState}
102+
widgets={{ ...widgets, ...props.widgets }}
103+
translateString={translateString}
104+
ref={ref}
105+
/>
106+
)
107+
})

src/Common/RJSF/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@
1616

1717
export { RJSFForm } from './Form'
1818
export type * from './types'
19-
export { getInferredTypeFromValueType, getRedirectionProps } from './utils'
19+
export {
20+
getInferredTypeFromValueType,
21+
getRedirectionProps,
22+
getSchemaPathToUpdatePathMap,
23+
conformPathToPointers,
24+
} from './utils'
2025
export { HIDE_SUBMIT_BUTTON_UI_SCHEMA } from './constants'

src/Common/RJSF/templates/ObjectFieldTemplate.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,13 @@ const Field = ({
6161
if (!hiddenSchema.path) {
6262
throw new Error('Empty path property of hidden descriptor field')
6363
}
64-
if (!hiddenSchema.path.match(/^\/\w+(\/\w+)*$/g)) {
65-
throw new Error('Provided path is not a valid JSON pointer')
66-
}
6764
// NOTE: formContext is the formData passed to RJSFForm
6865
const value = JSONPath({
6966
path: convertJSONPointerToJSONPath(hiddenSchema.path),
7067
json: formContext,
71-
})?.[0]
68+
resultType: 'value',
69+
wrap: false,
70+
})
7271
const isHidden = value === undefined || deepEquals(hiddenSchema.value, value)
7372
return !isHidden
7473
} catch {

src/Common/RJSF/types.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import { ComponentProps } from 'react'
1818
import RJSFForm from '@rjsf/core'
1919
import { StrictRJSFSchema } from '@rjsf/utils'
2020

21-
export type FormProps = Omit<ComponentProps<typeof RJSFForm>, 'validator'>
22-
2321
export interface MetaHiddenType {
2422
value: any
2523
path: string
@@ -34,8 +32,26 @@ export type HiddenType =
3432
| string
3533

3634
export interface RJSFFormSchema extends StrictRJSFSchema {
37-
properties: {
35+
properties?: {
3836
[key: string]: RJSFFormSchema
3937
}
40-
hidden: HiddenType
38+
hidden?: HiddenType
39+
updatePath?: string
4140
}
41+
42+
export type FormProps = Omit<ComponentProps<typeof RJSFForm<any, RJSFFormSchema>>, 'validator'>
43+
44+
export interface UpdateFormDataFromFormStateProps {
45+
/**
46+
* formData is data that is being passed from the user
47+
*/
48+
formData: Record<string, unknown>
49+
/**
50+
* formState is the latest state of the form
51+
*/
52+
formState: Record<string, unknown>
53+
schemaPathToUpdatePathMap: Record<string, string>
54+
}
55+
56+
export interface GetFormStateFromFormDataProps
57+
extends Pick<UpdateFormDataFromFormStateProps, 'formData' | 'schemaPathToUpdatePathMap'> {}

0 commit comments

Comments
 (0)