Skip to content

feat(orchestrator): add custom review page API support#2759

Merged
karthikjeeyar merged 4 commits intoredhat-developer:mainfrom
lokanandaprabhu:pr-1877
Apr 15, 2026
Merged

feat(orchestrator): add custom review page API support#2759
karthikjeeyar merged 4 commits intoredhat-developer:mainfrom
lokanandaprabhu:pr-1877

Conversation

@lokanandaprabhu
Copy link
Copy Markdown
Member

@lokanandaprabhu lokanandaprabhu commented Apr 14, 2026

Hey, I just made a Pull Request!

Story: https://redhat.atlassian.net/browse/RHIDP-13037

Custom Review Page API:

  • Add ReviewComponentProps type to define props for custom review components
  • Add optional getReviewComponent() method to OrchestratorFormApi interface
  • Update OrchestratorForm to support custom review page components from plugins
  • Add CustomReviewPage example component in orchestrator-form-widgets plugin
  • Falls back to default review page when getReviewComponent() returns undefined

Documentation:

  • Update extensibleForm.md with custom review page implementation guide

--------Custom review page-----

Screenshot 2026-04-14 at 11 50 05 AM

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented Apr 14, 2026

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-orchestrator-form-api workspaces/orchestrator/plugins/orchestrator-form-api minor v2.5.3
@red-hat-developer-hub/backstage-plugin-orchestrator-form-react workspaces/orchestrator/plugins/orchestrator-form-react minor v2.6.3
@red-hat-developer-hub/backstage-plugin-orchestrator-form-widgets workspaces/orchestrator/plugins/orchestrator-form-widgets minor v1.8.0

@rhdh-qodo-merge
Copy link
Copy Markdown

Review Summary by Qodo

Add custom review page API support for plugins

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add ReviewComponentProps type for custom review components
• Add optional getReviewComponent() method to OrchestratorFormApi
• Update OrchestratorForm to render custom review components
• Provide CustomReviewPage example implementation with Material-UI styling
• Document custom review page API in extensibleForm.md
Diagram
flowchart LR
  A["OrchestratorFormApi"] -->|getReviewComponent| B["ReviewComponentProps"]
  B -->|defines props for| C["Custom Review Component"]
  D["OrchestratorForm"] -->|uses| C
  D -->|fallback to| E["Default ReviewStep"]
  F["FormWidgetsApi"] -->|implements| A
  G["CustomReviewPage"] -->|example of| C
Loading

Grey Divider

File Changes

1. workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts ✨ Enhancement +25/-0

Define review component API types and interface

• Add ReviewComponentProps type with busy, schema, data, and handleExecute properties
• Add optional getReviewComponent() method to OrchestratorFormApi interface
• Include JSDoc documentation for new type and method

workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts


2. workspaces/orchestrator/plugins/orchestrator-form-api/src/index.ts ✨ Enhancement +1/-0

Export review component props type

• Export ReviewComponentProps type from the API package

workspaces/orchestrator/plugins/orchestrator-form-api/src/index.ts


3. workspaces/orchestrator/.changeset/custom-review-page-api.md 📝 Documentation +20/-0

Add changeset for custom review page API

• Document new ReviewComponentProps type
• Document optional getReviewComponent() method
• Document OrchestratorForm updates for custom components
• Document CustomReviewPage example component
• Document fallback to default review page behavior
• Document extensibleForm.md updates

workspaces/orchestrator/.changeset/custom-review-page-api.md


View more (5)
4. workspaces/orchestrator/docs/extensibleForm.md 📝 Documentation +57/-0

Document custom review page implementation guide

• Add custom review page feature to overview list
• Add "Custom Review Page Component" section with props documentation
• Provide example implementation showing component structure
• Include usage guide for plugins to implement custom review pages
• Reference CustomReviewPage.tsx example component

workspaces/orchestrator/docs/extensibleForm.md


5. workspaces/orchestrator/plugins/orchestrator-form-api/report.api.md 📝 Documentation +10/-1

Update API report with new types and methods

• Update API report to include ReviewComponentProps type definition
• Update API report to include getReviewComponent() method signature
• Update line numbers in warnings section

workspaces/orchestrator/plugins/orchestrator-form-api/report.api.md


6. workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx ✨ Enhancement +20/-4

Integrate custom review component rendering

• Import useOrchestratorFormApiOrDefault hook
• Retrieve custom review component from API using getReviewComponent()
• Use custom component if provided, otherwise fallback to default ReviewStep
• Update dependency array in reviewStep useMemo to include CustomReviewComponent

workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx


7. workspaces/orchestrator/plugins/orchestrator-form-widgets/src/FormWidgetsApi.tsx ✨ Enhancement +8/-0

Implement review component method in FormWidgetsApi

• Implement getReviewComponent() method returning undefined by default
• Include comments showing how to enable custom review page
• Reference CustomReviewPage.tsx example component

workspaces/orchestrator/plugins/orchestrator-form-widgets/src/FormWidgetsApi.tsx


8. workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx ✨ Enhancement +197/-0

Add CustomReviewPage example component implementation

• Create example custom review page component with Material-UI styling
• Implement data flattening for nested object display
• Provide formatted value rendering for various data types
• Include execute button with busy state handling
• Add comprehensive JSDoc explaining usage and integration

workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx


Grey Divider

Qodo Logo

@rhdh-qodo-merge
Copy link
Copy Markdown

rhdh-qodo-merge Bot commented Apr 14, 2026

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (0)   📎 Requirement gaps (0)
🐞\ ≡ Correctness (1) ⛨ Security (1)

Grey Divider


Action required

1. Custom review lacks back 🐞
Description
Custom review components receive no back-navigation capability, while the Stepper step labels are
not clickable, so a custom review page can trap users on the review step. The shipped
CustomReviewPage example reinforces this by rendering a Back button with no onClick handler.
Code

workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx[R175-190]

+  // Get custom review component from API if available
+  const orchestratorFormApi = useOrchestratorFormApiOrDefault();
+  const CustomReviewComponent = useMemo(() => {
+    return orchestratorFormApi.getReviewComponent?.();
+  }, [orchestratorFormApi]);
+
  const reviewStep = useMemo(() => {
+    // Use custom review component if provided, otherwise use default
+    const ReviewComponent = CustomReviewComponent || ReviewStep;
    return (
-      <ReviewStep
+      <ReviewComponent
        data={prunedFormData}
        schema={schema}
        busy={isExecuting}
        handleExecute={_handleExecute}
-        // no schema update here
      />
Evidence
OrchestratorForm renders the plugin-supplied ReviewComponent with only
busy/schema/data/handleExecute, so a custom component has no supported way to call
StepperContext.handleBack. The stepper headers aren’t clickable, and the default ReviewStep relies
on StepperContext.handleBack for navigation; the new example custom review page includes a Back
button without an onClick, demonstrating the functional gap.

workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx[175-191]
workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts[125-134]
workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorFormStepper.tsx[69-95]
workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx[126-187]
workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/StepperContext.tsx[58-65]
workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[181-189]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Custom review components can’t navigate back from the review step because the stepper labels aren’t clickable and `ReviewComponentProps` doesn’t provide a back handler (and the example’s Back button has no handler).

## Issue Context
The built-in `ReviewStep` uses `useStepperContext().handleBack`, but custom review components are defined via the API package and should not rely on internal deep imports.

## Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts[119-135]
- workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx[175-198]
- workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx[112-191]
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[181-194]

## Suggested approach
1. Extend `ReviewComponentProps` to include a back callback (e.g., `handleBack: () => void`).
2. In `OrchestratorForm`, render a small wrapper component inside `reviewStep` that calls `useStepperContext()` and passes `handleBack` into the selected review component.
3. Update `ReviewStep` to accept and use the passed `handleBack` (or keep using context, but ensure TS props allow it).
4. Fix `CustomReviewPage` example to wire its Back button to `handleBack`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Example exposes sensitive fields 🐞
Description
CustomReviewPage displays the raw submitted form data (including nested objects) without applying
the default review-step rules that hide ui:hidden fields and mask password widgets. This can
reveal values that the built-in ReviewStep intentionally suppresses (e.g., secrets/passwords).
Code

workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[R84-104]

+const renderValue = (value: any): React.ReactNode => {
+  if (value === null || value === undefined) {
+    return (
+      <Typography variant="body2" color="textSecondary">
+        N/A
+      </Typography>
+    );
+  }
+  if (typeof value === 'object') {
+    return (
+      <Typography
+        variant="body2"
+        component="pre"
+        sx={{ whiteSpace: 'pre-wrap' }}
+      >
+        {JSON.stringify(value, null, 2)}
+      </Typography>
+    );
+  }
+  return <Typography variant="body2">{String(value)}</Typography>;
+};
Evidence
The default review pipeline explicitly skips schema fields with ui:hidden (unless toggled) and
masks ui:widget=password values; CustomReviewPage ignores the schema entirely and
stringifies/renders values directly, so hidden/password values would be shown verbatim if a plugin
enables this example component.

workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/generateReviewTableData.ts[45-58]
workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx[128-133]
workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[84-104]
workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[110-138]
workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[168-178]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`CustomReviewPage` renders `data` directly and JSON-stringifies objects, which can expose fields the default review step hides/masks (e.g., `ui:hidden` and password widgets).

## Issue Context
The built-in `ReviewStep` uses schema-aware logic (`generateReviewTableData`/`processSchema`) to:
- omit `ui:hidden` values by default
- mask password widget values
Custom review pages should demonstrate or provide an easy path to the same safety guarantees.

## Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[84-104]
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[110-178]
- workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md[62-117]

## Suggested approach
Pick one:
1. **Update the example to respect schema hiding/masking**: implement a small schema-walk that omits `ui:hidden` (static true) and masks `ui:widget=password` values before rendering.
2. **Provide a shared utility** (preferred): move/export a schema-aware review-data sanitizer (similar to `generateReviewTableData`) into a package that custom review components can depend on, and update the example/docs to use it.
3. If keeping the example as-is, add a prominent warning in docs and inline comments that it may reveal secrets and must be adapted before use.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +175 to 190
// Get custom review component from API if available
const orchestratorFormApi = useOrchestratorFormApiOrDefault();
const CustomReviewComponent = useMemo(() => {
return orchestratorFormApi.getReviewComponent?.();
}, [orchestratorFormApi]);

const reviewStep = useMemo(() => {
// Use custom review component if provided, otherwise use default
const ReviewComponent = CustomReviewComponent || ReviewStep;
return (
<ReviewStep
<ReviewComponent
data={prunedFormData}
schema={schema}
busy={isExecuting}
handleExecute={_handleExecute}
// no schema update here
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Custom review lacks back 🐞 Bug ≡ Correctness

Custom review components receive no back-navigation capability, while the Stepper step labels are
not clickable, so a custom review page can trap users on the review step. The shipped
CustomReviewPage example reinforces this by rendering a Back button with no onClick handler.
Agent Prompt
## Issue description
Custom review components can’t navigate back from the review step because the stepper labels aren’t clickable and `ReviewComponentProps` doesn’t provide a back handler (and the example’s Back button has no handler).

## Issue Context
The built-in `ReviewStep` uses `useStepperContext().handleBack`, but custom review components are defined via the API package and should not rely on internal deep imports.

## Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-form-api/src/api.ts[119-135]
- workspaces/orchestrator/plugins/orchestrator-form-react/src/components/OrchestratorForm.tsx[175-198]
- workspaces/orchestrator/plugins/orchestrator-form-react/src/components/ReviewStep.tsx[112-191]
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[181-194]

## Suggested approach
1. Extend `ReviewComponentProps` to include a back callback (e.g., `handleBack: () => void`).
2. In `OrchestratorForm`, render a small wrapper component inside `reviewStep` that calls `useStepperContext()` and passes `handleBack` into the selected review component.
3. Update `ReviewStep` to accept and use the passed `handleBack` (or keep using context, but ensure TS props allow it).
4. Fix `CustomReviewPage` example to wire its Back button to `handleBack`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +84 to +104
const renderValue = (value: any): React.ReactNode => {
if (value === null || value === undefined) {
return (
<Typography variant="body2" color="textSecondary">
N/A
</Typography>
);
}
if (typeof value === 'object') {
return (
<Typography
variant="body2"
component="pre"
sx={{ whiteSpace: 'pre-wrap' }}
>
{JSON.stringify(value, null, 2)}
</Typography>
);
}
return <Typography variant="body2">{String(value)}</Typography>;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Example exposes sensitive fields 🐞 Bug ⛨ Security

CustomReviewPage displays the raw submitted form data (including nested objects) without applying
the default review-step rules that hide ui:hidden fields and mask password widgets. This can
reveal values that the built-in ReviewStep intentionally suppresses (e.g., secrets/passwords).
Agent Prompt
## Issue description
`CustomReviewPage` renders `data` directly and JSON-stringifies objects, which can expose fields the default review step hides/masks (e.g., `ui:hidden` and password widgets).

## Issue Context
The built-in `ReviewStep` uses schema-aware logic (`generateReviewTableData`/`processSchema`) to:
- omit `ui:hidden` values by default
- mask password widget values
Custom review pages should demonstrate or provide an easy path to the same safety guarantees.

## Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[84-104]
- workspaces/orchestrator/plugins/orchestrator-form-widgets/src/components/CustomReviewPage.tsx[110-178]
- workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md[62-117]

## Suggested approach
Pick one:
1. **Update the example to respect schema hiding/masking**: implement a small schema-walk that omits `ui:hidden` (static true) and masks `ui:widget=password` values before rendering.
2. **Provide a shared utility** (preferred): move/export a schema-aware review-data sanitizer (similar to `generateReviewTableData`) into a package that custom review components can depend on, and update the example/docs to use it.
3. If keeping the example as-is, add a prominent warning in docs and inline comments that it may reveal secrets and must be adapted before use.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread workspaces/orchestrator/docs/extensibleForm.md
…tep parity

- Add handleBack to ReviewComponentProps; OrchestratorForm uses ReviewStepHost to inject it from stepper context
- Export generateReviewTableData, schemaHasUiHiddenFields, and NestedReviewTable from form-react
- CustomReviewPage uses the same review data path and hidden-fields toggle as ReviewStep; depend on form-react
- Document limitations and recommended helpers in extensibleForm.md; update changeset and API reports

Made-with: Cursor
…w step

Share hidden-parameters Alert+Switch between ReviewStep and CustomReviewPage
to reduce duplication (Sonar). Export component and props from form-react;
document in extensibleForm.md. Regenerate API reports.

Made-with: Cursor
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Member

@karthikjeeyar karthikjeeyar left a comment

Choose a reason for hiding this comment

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

Looks good to me!

Image

/approve
/lgtm

@openshift-ci openshift-ci Bot added the lgtm label Apr 15, 2026
@karthikjeeyar karthikjeeyar merged commit f45fe5a into redhat-developer:main Apr 15, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants