Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist form state and validation in Workspace #61

Merged
merged 8 commits into from
Oct 23, 2023

Conversation

ohltyler
Copy link
Member

@ohltyler ohltyler commented Oct 18, 2023

Description

At a high level, this PR adds 2 main functionalities:

  1. Persist and validate form data/inputs to the components in the Workspace. All of the form inputs and schema are dynamically generated based on what components are in the workspace, and what fields and field types they have specified in their json config. This way, any changes to existing or new components will not require adding any special logic for persisting input values or validating it.
  2. Persist selection state in a customizable manner. We keep the node selected when clicking outside of the workspace so users know what data they are editing in the side panel.

More details:

  • adds apache-2.0-licensed formik and MIT-licensed yup packages for form management and validation, respectively. Formik is a widely used & popular library used for form management with react apps, and is already used in other OSD plugins. Formik validation has very good integration with Yup, a library used for defining validation schemas over form data.
  • integrates the TextField and SelectField input components with formik using formik's Field component
  • configures and wraps the entire workspace with the Formik component so form data can be accessed in the workspace + details side panel
  • adds several util fns to convert component data to and from Formik values and Yup schemas
  • refactors and moves input_fields into the component_details module
  • adds a name and value field to IComponentField to generate formik values from component data, or vice versa.
  • adds a custom initialization hook in resizable_workspace to dynamically generate the form values and schema based on the workflow's component data
  • adds an onNodesChange() fn in resizable_workspace used for updating the forms and schema when a component is added or removed from the Workspace. This is done by passing this fn to the workspace, where we use formik's useStore custom hook to listen on node count changes, which we then trigger the onNodesChange callback fn
  • adds a testable 'submit' button on the bottom to test form validation. leaving in for now for the sake of testing submission since there is no finalized UX around this part yet.
  • persist selection state by 1/ moving the ReactFlowProvider to a higher-level component so we can move useOnSelectionChange to resizable_workspace. This simplifies the downstream components. And, 2/ Updates css styling to control when a component is selected or not.

Demo video showing form state:

screen-capture.19.webm

Demo video showing selection state (added after prev. demo video):

screen-capture.20.webm

Issues Resolved

Makes progress on #8, #10

Check List

  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: Tyler Ohlsen <[email protected]>
Signed-off-by: Tyler Ohlsen <[email protected]>
const [edges, setEdges, onEdgesChange] = useEdgesState([]);

// Listener for node additions or deletions to propagate to parent component
const nodesLength = useStore(
(state) => Array.from(state.nodeInternals.values()).length || 0
Copy link
Member

Choose a reason for hiding this comment

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

would the nodes.length not be updated to use here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a custom hook that will be updated when the node internals change (node added/deleted/etc.). See docs and similar example: https://reactflow.dev/docs/api/hooks/use-store/

Copy link
Member Author

Choose a reason for hiding this comment

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

And similar to the example, we listen for when the value changes on our useEffect on line 56-58

function onNodesChange(nodes: ReactFlowComponent[]): void {
const updatedComponentIds = nodes.map((node) => node.id);
const existingComponentIds = Object.keys(formValues);
const updatedSchemaObj = cloneDeep(formSchema.fields) as WorkspaceSchemaObj;
Copy link
Member

Choose a reason for hiding this comment

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

why do we clone formSchema.fields. We don't set it to formSchema.fields earlier

Copy link
Member Author

Choose a reason for hiding this comment

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

We extract the fields which is the underlying object, update it if necessary (like removing the component ID on line 119), and re-generate the schema on line 128.

@ohltyler ohltyler merged commit 10810e3 into opensearch-project:main Oct 23, 2023
4 checks passed
@ohltyler ohltyler deleted the form branch October 23, 2023 21:55
opensearch-trigger-bot bot pushed a commit that referenced this pull request Oct 23, 2023
Signed-off-by: Tyler Ohlsen <[email protected]>
(cherry picked from commit 10810e3)
ohltyler added a commit that referenced this pull request Oct 23, 2023
Signed-off-by: Tyler Ohlsen <[email protected]>
(cherry picked from commit 10810e3)

Co-authored-by: Tyler Ohlsen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants