Skip to content

fix(orchestrator-form-widgets): evaluate $${{…}} in fetch-response selectors#3058

Open
lokanandaprabhu wants to merge 1 commit intoredhat-developer:mainfrom
lokanandaprabhu:fix/orchestrator-fetch-response-selector-templates
Open

fix(orchestrator-form-widgets): evaluate $${{…}} in fetch-response selectors#3058
lokanandaprabhu wants to merge 1 commit intoredhat-developer:mainfrom
lokanandaprabhu:fix/orchestrator-fetch-response-selector-templates

Conversation

@lokanandaprabhu
Copy link
Copy Markdown
Member

@lokanandaprabhu lokanandaprabhu commented May 6, 2026

Hey, I just made a Pull Request!

fetch:url / fetch:body-style props already interpolated $${{…}} via the shared template evaluator, but fetch:response:value, fetch:response:autocomplete, fetch:response:label, and dropdown fetch:response:value were passed straight to JSONata. This change runs those selector strings through the same template step first, then applies JSONata to the fetch response.

Screen.Recording.2026-05-06.at.9.04.36.PM.mov

How to test

Use below schema to test

{
  "$id": "classpath:/schemas/test-fetch-response-template__main-schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Test fetch response selector templates",
  "type": "object",
  "properties": {
    "step1": {
      "type": "object",
      "title": "Step 1 - Dollar-brace templates in fetch response selectors",
      "description": "Change the templated selectors and confirm widgets refetch correctly.",
      "properties": {
        "intro": {
          "title": "About this workflow",
          "type": "string",
          "ui:widget": "ActiveText",
          "ui:props": {
            "ui:text": "**Purpose:** Validates that template units (syntax: two `$` chars then `${{expression}}`) are evaluated for **fetch:response:value**, **fetch:response:autocomplete**, **fetch:response:label**, and **fetch:response:value** (dropdown). ActiveText resolves `$ ${{…}}`-style placeholders in help copy if written with a space so it is not parsed as an expression. Uses form paths like `current.*`, `backend.baseUrl`, plus the widget fetch response; Sonata `/q/health` exposes `status`. Postman Echo (via backstage proxy `/postman-echo/get`) repeats `tag` query params under `args.tag`."
          }
        },
        "healthFieldKey": {
          "type": "string",
          "title": "Top-level key on Sonata `/q/health`",
          "default": "status"
        },
        "sonataHealthPreview": {
          "type": "string",
          "title": "ActiveTextInput — templated fetch:response:value",
          "description": "Reads the field named in Top-level key (default `status`).",
          "ui:widget": "ActiveTextInput",
          "ui:props": {
            "fetch:url": "http://localhost:8899/q/health",
            "fetch:response:value": "$${{current.step1.healthFieldKey}}",
            "fetch:retrigger": ["current.step1.healthFieldKey"]
          }
        },
        "tagsSelector": {
          "type": "string",
          "title": "JSONata selector for Echo tag list",
          "default": "args.tag",
          "description": "Echo returns repeated `tag` query params here (typically an array)."
        },
        "fruitsAutocomplete": {
          "type": "array",
          "title": "ActiveMultiSelect — templated fetch:response:autocomplete",
          "items": {
            "type": "string"
          },
          "ui:widget": "ActiveMultiSelect",
          "ui:props": {
            "fetch:url": "$${{backend.baseUrl}}/api/proxy/postman-echo/get?tag=apple&tag=banana&tag=cherry",
            "fetch:response:autocomplete": "$${{current.step1.tagsSelector}}",
            "fetch:retrigger": ["current.step1.tagsSelector"]
          }
        },
        "dropdownSelector": {
          "type": "string",
          "title": "JSONata selector for dropdown label & value arrays",
          "default": "args.tag",
          "description": "Same Echo response as multiselect; label and value both use this path."
        },
        "echoTagChoice": {
          "type": "string",
          "title": "ActiveDropdown — templated fetch:response:label & value",
          "description": "Options come from Echo `tag` params via the templated selectors.",
          "ui:widget": "ActiveDropdown",
          "ui:props": {
            "fetch:url": "$${{backend.baseUrl}}/api/proxy/postman-echo/get?tag=apple&tag=banana&tag=cherry",
            "fetch:response:label": "$${{current.step1.dropdownSelector}}",
            "fetch:response:value": "$${{current.step1.dropdownSelector}}",
            "fetch:retrigger": ["current.step1.dropdownSelector"]
          }
        }
      }
    }
  }
}
id: test-fetch-response-template
version: '1.0'
specVersion: '0.8'
name: Test fetch response selector templates
description:
  Demonstrates dollar-brace template units inside fetch response selectors
  (ActiveTextInput, ActiveMultiSelect, ActiveDropdown).
dataInputSchema: schemas/test-fetch-response-template__main-schema.json
start: StartState
functions:
  - name: runActionFunction
    type: custom
    operation: sysout
states:
  - name: StartState
    type: operation
    actions:
      - name: runAction
        functionRef:
          refName: runActionFunction
          arguments:
            message: Workflow input is ${.}
    end: true

In app-config.yaml, you can add below in proxy.endpoints

   "/postman-echo":
      target: "https://postman-echo.com"
      changeOrigin: true
      secure: true
      allowedMethods: [ "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE" ]
      headers:
        X-Requested-With: XMLHttpRequest

✔️ 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)

…selectors

Evaluate placeholder templates in fetch:response:value, fetch:response:autocomplete, fetch:response:label, and dropdown fetch:response:value before JSONata, consistent with other fetch fields. Treat undefined array selector results as empty options for ActiveDropdown and ActiveTextInput autocomplete (same as ActiveMultiSelect).

Add changeset for patch release.

Co-authored-by: Cursor <cursoragent@cursor.com>
@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented May 6, 2026

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-orchestrator-form-widgets workspaces/orchestrator/plugins/orchestrator-form-widgets patch v1.10.4

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 26.31579% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.77%. Comparing base (5e4d2b2) to head (277b66e).
⚠️ Report is 8 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3058      +/-   ##
==========================================
- Coverage   60.78%   60.77%   -0.01%     
==========================================
  Files        2067     2067              
  Lines       63873    63891      +18     
  Branches    16580    16585       +5     
==========================================
+ Hits        38827    38832       +5     
- Misses      24793    24803      +10     
- Partials      253      256       +3     
Flag Coverage Δ *Carryforward flag
adoption-insights 83.58% <ø> (ø) Carriedforward from 5e4d2b2
ai-integrations 70.03% <ø> (ø) Carriedforward from 5e4d2b2
app-defaults 69.60% <ø> (ø) Carriedforward from 5e4d2b2
augment 69.36% <ø> (ø) Carriedforward from 5e4d2b2
bulk-import 72.44% <ø> (ø) Carriedforward from 5e4d2b2
cost-management 16.49% <ø> (ø) Carriedforward from 5e4d2b2
dcm 32.85% <ø> (ø) Carriedforward from 5e4d2b2
extensions 61.42% <ø> (ø) Carriedforward from 5e4d2b2
global-floating-action-button 73.75% <ø> (ø) Carriedforward from 5e4d2b2
global-header 61.62% <ø> (ø) Carriedforward from 5e4d2b2
homepage 50.92% <ø> (ø) Carriedforward from 5e4d2b2
konflux 91.01% <ø> (ø) Carriedforward from 5e4d2b2
lightspeed 69.96% <ø> (ø) Carriedforward from 5e4d2b2
mcp-integrations 81.59% <ø> (ø) Carriedforward from 5e4d2b2
orchestrator 33.14% <26.31%> (-0.02%) ⬇️
quickstart 62.64% <ø> (ø) Carriedforward from 5e4d2b2
sandbox 79.49% <ø> (ø) Carriedforward from 5e4d2b2
scorecard 83.61% <ø> (ø) Carriedforward from 5e4d2b2
theme 64.54% <ø> (ø) Carriedforward from 5e4d2b2
translations 8.49% <ø> (ø) Carriedforward from 5e4d2b2
x2a 82.09% <ø> (ø) Carriedforward from 5e4d2b2

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5e4d2b2...277b66e. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

Verified the fix it works as expected. Additionally I have noticed another issue probably exists in the main branch as well.

when you modifiy the dynamic field value (HealthFieldKey) that may not exist in the response, which will return undefined and break the UI.

invalid_selector_throws.mp4

@lokanandaprabhu
Copy link
Copy Markdown
Member Author

@karthikjeeyar I will check and create separate issue for that.

@lokanandaprabhu
Copy link
Copy Markdown
Member Author

Created ticket - https://redhat.atlassian.net/browse/RHDHBUGS-3110 for the other issue raised.

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