From b9021c81d161737589de3147870f638be7615980 Mon Sep 17 00:00:00 2001 From: Bat-Zion Rotman Date: Sun, 17 Nov 2024 16:25:59 +0200 Subject: [PATCH] docs(orchestrator): add documentation for the extensible workflow execution form (#2540) --- .changeset/two-students-promise.md | 2 + plugins/orchestrator-form-api/README.md | 105 +-------------- plugins/orchestrator-form-react/README.md | 4 +- plugins/orchestrator/README.md | 4 + plugins/orchestrator/docs/extensibleForm.md | 136 ++++++++++++++++++++ 5 files changed, 147 insertions(+), 104 deletions(-) create mode 100644 .changeset/two-students-promise.md create mode 100644 plugins/orchestrator/docs/extensibleForm.md diff --git a/.changeset/two-students-promise.md b/.changeset/two-students-promise.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/two-students-promise.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/plugins/orchestrator-form-api/README.md b/plugins/orchestrator-form-api/README.md index 460eae527f..87d5a1dff4 100644 --- a/plugins/orchestrator-form-api/README.md +++ b/plugins/orchestrator-form-api/README.md @@ -1,106 +1,5 @@ # @janus-idp/backstage-plugin-orchestrator-form-api -### Overview +This library provides the interface for implementing a factory providing a decorator to customize the orchestrator workflow execution form. -This library offers the flexibility to override a selected list of [properties](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props) of the `react-jsonschema-form` workflow execution form component. It allows customers to provide a custom decorator for the form component in a backstage plugin. This decorator enables users to: - -- **Custom Validations:** Two types of custom validations can be added on top of the JSON schema validation provided by default: - - Synchronous validation through the `customValidate` property - - Asynchronous validation through the `getExtraErrors` property. Handles validations that require backend calls. -- **Custom Components:** Replace default components by overriding the `widgets` property. -- **Correlated Field Values:** Implement complex inter-field dependencies by overriding the `onChange` and the `formData` properties. - -The decorator will be provided through a factory method that leverages a [Backstage utility API](https://backstage.io/docs/api/utility-apis) offered by the orchestrator. - -### Interface Provided in this package - -```typescript -export type FormDecoratorProps = Pick< - FormProps, - 'formData' | 'formContext' | 'widgets' | 'onChange' | 'customValidate' -> & { - getExtraErrors?: ( - formData: JsonObject, - ) => Promise> | undefined; -}; - -export type FormDecorator = ( - FormComponent: React.ComponentType, -) => React.ComponentType; - -export interface FormExtensionsApi { - getFormDecorator(schema: JSONSchema7): FormDecorator; -} -``` - -### Example API Implementation - -```typescript -class CustomFormExtensionsApi implements FormExtensionsApi { - getFormDecorator(schema: JSONSchema7) { - return (FormComponent: React.ComponentType>) => { - const widgets = {CountryWidget}; - return () => ; - }; - } -} -``` - -### Plugin Creation Example - -```typescript -export const formApiFactory = createApiFactory({ - api: orchestratorFormApiRef, - deps: {}, - factory() { - return new CustomApi(); - }, -}); - -export const testFactoryPlugin = createPlugin({ - id: 'testfactory', - apis: [formApiFactory], -}); -``` - -### Schema example for above plugin - -```typescript -{ - "title": "Product", - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "country": { - "type": "string", - "title": "Country", - "description": "Country of residence", - "ui:widget": "CountryWidget" - } - }, - "required": ["name", "country"] -} -``` - -### dynamic plugin configuration - -add the following to app-config.local.yaml for integrating the dynamic plugin. - -```yaml -dynamicPlugins: - frontend: - backstage-plugin-testfactory: - apiFactories: - - importName: formApiFactory -``` - -### Additional Details - -The workflow execution schema adheres to the [json-schema](https://json-schema.org/) format, which allows for extending the schema with custom properties beyond the official specification. This flexibility enables the inclusion of additional [UiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/) fields directly within the schema, as demonstrated in the example above. - -The orchestrator plugin handles the separation of UI schema fields from the main schema. It also organizes the form into wizard steps based on an additional hierarchical structure within the JSON schema. - -Full plugin example is available [here](https://github.com/parodos-dev/extended-form-example-plugin). +Details available [here](../orchestrator/docs/extensibleForm.md). diff --git a/plugins/orchestrator-form-react/README.md b/plugins/orchestrator-form-react/README.md index 18ced4033e..cc0f0fba88 100644 --- a/plugins/orchestrator-form-react/README.md +++ b/plugins/orchestrator-form-react/README.md @@ -1,3 +1,5 @@ # backstage-plugin-orchestrator-form-react -This library provides the form component used in the workflow execution form. It is decoupled from the orchestrator plugin to allow plugins implementing the OrchestratorFormApi to test their behavior independently. +This library provides the form component used in the workflow execution form. It is decoupled from the orchestrator plugin to allow plugins implementing the OrchestratorFormApi test the behavior in a simple backstage developer environment. + +Details available [here](../orchestrator/docs/extensibleForm.md). diff --git a/plugins/orchestrator/README.md b/plugins/orchestrator/README.md index 0ed9f9b264..cb2f080e0e 100644 --- a/plugins/orchestrator/README.md +++ b/plugins/orchestrator/README.md @@ -154,6 +154,10 @@ For more information about the configuration options, including other optional p ); ``` +### Extensible Workflow Execution Form + +The `orchestrator` plugin includes an extensible form for executing forms. For detailed guidance see the [Extensible Workflow Execution Form Documentation](./docs/extensibleForm.md). + ## For users ### Using the Orchestrator plugin in Backstage diff --git a/plugins/orchestrator/docs/extensibleForm.md b/plugins/orchestrator/docs/extensibleForm.md new file mode 100644 index 0000000000..94a49bcae3 --- /dev/null +++ b/plugins/orchestrator/docs/extensibleForm.md @@ -0,0 +1,136 @@ +# Extensible Workflow Execution Form + +This capability enables developers to extend and customize the `react-jsonschema-form` workflow execution form component. It is designed to enable developers to implement a Backstage plugin that provides a custom decorator for the workflow execution form. This decorator supports overriding a selected set of [react-json-schema-form properties](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props) enabling the following features: + +- **Custom Validations:** Extend default JSON schema validation with: + - **Synchronous Validation** via the `customValidate` property. + - **Asynchronous Validation** via the `getExtraErrors` property, for validations requiring backend calls. +- **Custom Components:** Replace default form components by overriding the `widgets` property. +- **Interdependent Field Values:** Manage complex inter-field dependencies using the `onChange` and `formData` properties. + +The custom decorator is delivered via a factory method that leverages a [Backstage utility API](https://backstage.io/docs/api/utility-apis) provided by the orchestrator. To trigger the desired behavior, the workflow schema should include custom UI properties. + +For reference, an example plugin can be found [here](https://github.com/parodos-dev/custom-form-example-plugin). + +## API + +To implement the API, include @janus-idp/backstage-plugin-orchestrator-form-api package as a dependency. +This package provides the `FormExtensionsApi` interface and related types. + +```typescript +export type FormDecoratorProps = Pick< + FormProps, + 'formData' | 'formContext' | 'widgets' | 'onChange' | 'customValidate' +> & { + getExtraErrors?: ( + formData: JsonObject, + ) => Promise> | undefined; +}; + +export type FormDecorator = ( + FormComponent: React.ComponentType, +) => React.ComponentType; + +export interface FormExtensionsApi { + getFormDecorator(schema: JSONSchema7): FormDecorator; +} +``` + +### Example API Implementation + +```typescript +class CustomFormApi implements FormExtensionsApi { + getFormDecorator(schema: JSONSchema7) { + return (FormComponent: React.ComponentType>) => { + const widgets = {CountryWidget}; // CountryWidget needs to be implemneted and imported + return () => ; + }; + } +} +``` + +### Plugin Creation Example + +```typescript +export const formApiFactory = createApiFactory({ + api: orchestratorFormApiRef, + deps: {}, + factory() { + return new CustomFormApi(); + }, +}); + +export const testFactoryPlugin = createPlugin({ + id: 'custom-form-plugin', + apis: [formApiFactory], +}); +``` + +### Schema example for above plugin + +```typescript +{ + "type": "object", + "properties": { + "personalDetails": { + "type": "object", + "title": "Personal Details", + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "country": { + "type": "string", + "title": "Country", + "ui:widget": "CountryWidget" + } + } + }, + "contactDetails": { + "type": "object", + "title": "Contact Details", + "properties": { + "email": { + "type": "string", + "title": "Email" + }, + "phone": { + "type": "string", + "title": "Phone Number" + } + } + } + } +} +``` + +### Dynamic plugin configuration example + +Add the following to backstage config to integrate the plugin: + +```yaml +dynamicPlugins: + frontend: + custom-form-plugin: + apiFactories: + - importName: formApiFactory +``` + +### Referencing the custom behavior in the schema + +The workflow execution schema adheres to the [json-schema](https://json-schema.org/) format, which allows for extending the schema with custom properties beyond the official specification. This flexibility enables the inclusion of additional [uiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/) fields directly within the schema, as demonstrated in the example above. + +### How It All Comes Together + +The `orchestrator-form-react` plugin implements the form component for workflow execution. It integrates with the custom API provided by the developer's plugin to generate and customize the form. The `orchestrator` plugin then incorporates this form into the workflow execution page. + +The `orchestrator-form-react` plugin handles the following key tasks: + +- **Generating the UI Schema:** It extracts custom UI schema fields from the main schema, automatically generates the [uiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/), and passes it to the `react-jsonschema-form` component, enabling advanced UI customizations. + +- **Organizing Forms into Wizard-Style Steps:** If the schema is an object containing nested objects (i.e., the root is an object, and its properties are also objects), the plugin organizes the form into multiple steps. Each nested object becomes a separate step in a wizard-style interface. For example, the schema provided above results in two steps: _Personal Details_ and _Contact Details_. + +The [`orchestrator-form-react`](https://github.com/janus-idp/backstage-plugins/tree/main/plugins/orchestrator-form-react) plugin is designed to operate independently of the main orchestrator plugin. This modularity allows developers to test and validate form behavior in a standalone Backstage development environment before integrating it with the full orchestrator setup. + +To use this plugin, add the `@janus-idp/backstage-plugin-orchestrator-form-react` package as a dependency in your project.