Skip to content
This repository has been archived by the owner on Jul 17, 2023. It is now read-only.

Upgrade to RJSF v5 #1819

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open

Conversation

nickgros
Copy link
Contributor

@nickgros nickgros commented Oct 5, 2022

Upgrade to RJSF v5.

Includes many changes to clean up code + fix existing bugs.

Tests still failing.
Changes to fix tests and build errors
@nickgros nickgros marked this pull request as ready for review October 12, 2022 18:13
@@ -15,7 +15,6 @@ const globals = {
'rss-parser': 'Parser',
'react-mailchimp-subscribe': 'ReactMailchimpSubscribe',
'plotly.js-basic-dist': 'Plotly',
'@rjsf/core': 'JSONSchemaForm',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's include RJSF in the bundle. Bundle size doesn't change much since we were bundling our forked version, and now we're dropping it.

// These tests are unstable, so we'll skip them until we can fix them
// The component is in experimental mode only, so not a big deal for now
describe.skip('SchemaDrivenAnnotationEditor tests', () => {
describe('SchemaDrivenAnnotationEditor tests', () => {
Copy link
Contributor Author

@nickgros nickgros Oct 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully these are stable now. The test suite also should emit no errors/warnings.

@@ -191,6 +195,17 @@ describe.skip('SchemaDrivenAnnotationEditor tests', () => {
return res(ctx.status(201), ctx.json({ token: mockAsyncTokenId }))
},
),
rest.get(
Copy link
Contributor Author

@nickgros nickgros Oct 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A while ago we changed how SynapseClient requests the result for asynchronous jobs. This accommodates that change.

Comment on lines +318 to +319
// TODO: Test is not working, but the functionality is working in the browser
it.skip('Removes a custom annotation field when the last value is removed', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only skipped test now.

* - convert schema-defined formData from an array to a non-array if the schema type is not an array
* @param props
*/
export function objectFieldComponentDidUpdate(props: FieldProps) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic used to be split up in FieldTemplate and AdditionalPropertiesSchemaField. Each of those components wrapped the call to onChange in useEffect with a setTimeout.

That wasn't working very well. In short, multiple fields would call onChange at once, and only one would succeed.

This eliminates the race condition by changing all of the fields in the object in one pass.

* If the intitial data is a string, returns an array of substrings separated by commas.
* Otherwise, wrap the data in an array.
*/
function convertToArray(value: T): Array<any> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to AnnotationEditorUtils

Comment on lines -148 to +141
const { list, handleListChange, handleListRemove, appendToList, setList } =
useListState(convertToArray(formData))

const list = Array.isArray(formData) ? formData : convertToArray(formData)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this excess state (which also lets us get rid of another effect)

Comment on lines -161 to -170
useEffect(() => {
// The item may not be an array when we get it, and we need to convert it right away because the order of items is not stable, and seems to depend on if the item is an array or not.
// Otherwise, the order of the properties will change when the user modifies the data. We may be able to fix this by modifying react-jsonschema-form to stabilize the item order.

// FIXME: This doesn't work without a delay.
setTimeout(() => {
onChange(list)
}, 50)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic was moved to ObjectField via AnnotationEditorUtils.objectFieldComponentDidUpdate

Fix test suite broken from moving files
Comment on lines +22 to +27
/**
* This file is mostly a direct copy of the RJSF ObjectField component. Because it handles a lot of complex logic for
* rendering a form, when we upgrade RJSF, we should replace this file with the new version.
*
* The only change that we have applied is adding the `componentDidUpdate` method to the class.
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See here ^^^

*
* @param props - The `ArrayFieldTemplateItemType` props for the component
*/
export default function ArrayFieldItemTemplate<T, F>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template that didn't exist before RJSF v5. Pulled from our custom ArrayFieldTemplate.

* Identical to @rjsf/core ArrayFieldDescriptionTemplate except doesn't render null if there is no description
* @param props - The `ArrayFieldDescriptionProps` for the component
*/
export default function ArrayFieldDescriptionTemplate<T = any, F = any>(
Copy link
Contributor Author

@nickgros nickgros Oct 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template that didn't exist before RJSF v5. Mostly copied and pasted from the base one

*
* @param props - The `ArrayFieldTemplateItemType` props for the component
*/
function ArrayFieldTemplate<T = any, F = any>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from CustomArrayFieldTemplate. Since it now uses other templates that didn't exist before, it was substantially rewritten.

Comment on lines +48 to +52
useEffect(() => {
if (props.items.length === 0) {
props.onAddClick()
}
}, [props])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is our addition (unchanged from previous version)

* @param props
* @returns
*/
export default function ArrayFieldTitleTemplate<T, F>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template that didn't exist before RJSF v5.

)
}

export default {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ability to simply override buttons didn't exist before RJSF v5.

import React from 'react'
import Typography from '../../../../utils/typography/Typography'

export default function DescriptionFieldTemplate(props: DescriptionFieldProps) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used to be FieldDescriptionTable.tsx and was manually inserted into each template. Now, we can just override the DescriptionFieldTemplate.

import { HelpOutline } from '@material-ui/icons'
import { Collapse } from '@material-ui/core'

export function FieldTemplate<T>(props: FieldTemplateProps<T>) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used to be CustomDefaultTemplate. Now is just concerned with layout

@@ -13,10 +20,35 @@ import { displayToast } from '../../ToastMessage'
* @param props
* @returns
*/
export function CustomObjectFieldTemplate(
props: ObjectFieldTemplateProps<Record<string, unknown>>,
export function ObjectFieldTemplate<T, F>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly code style changes in this component to match the base RJSF v5 ObjectFieldTemplate

onKeyChange: (newKey: string) => void
},
) => {
export default function WrapIfAdditionalTemplate<T = any, F = any>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For additionalProperties, we were overriding an entire FieldTemplate to alter the layout of an internal RJSF component called WrapIfAdditional. We added WrapIfAdditionalTemplate to RJSF v5 to make this easier.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant