chore(apollo-react): guardrails preview build (do not merge) - #1148
chore(apollo-react): guardrails preview build (do not merge)#1148andreizdrali-uipath wants to merge 8 commits into
Conversation
… field Generic forms-engine enablers extracted from the guardrails work (apollo-ui#1107 review): controlled values/onValuesChange/errors/disableValidation/container props on MetadataForm (MetadataFormProps now exported), a string-list field type with tooltip/textarea/multiselect metadata additions, label association and custom-component ref handling in the field renderer, and a useWatch re-export so cross-package custom fields share the RHF context. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ling InfoTooltip moves out of the guardrails prototype into components/ui with its a11y test; select and textarea get aria-invalid error styling; the root barrel exposes the new forms/ui surface. The guardrails domain family itself moves to apollo-react (canvas) per the #1107 review decision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moves the guardrails family out of apollo-wind's custom/ prototype shelf into apollo-react per the #1107 review decision: canvas-adjacent (MUI-free, built on wind primitives and the forms/ MetadataForm engine), exported from the canvas components barrel plus a narrow ./canvas/guardrails subpath. Strings move to lingui: useSafeLingui labels-hooks with explicit guardrails.* ids replace the wind-local catalogs and loader; the 60 keys ship translated in the shared canvas catalog for 13 locales (ru falls back to English per key). Localized templates that cross into plain-string APIs are ICU messages formatted with sentinel values, preserving the {{token}} convention. The family's Tailwind classes ride the existing tailwind.canvas.css scan; adds class-variance-authority (dep) and jest-axe (dev, matcher registered in the shared test setup). Also silences Radix's aria-describedby warning on the description-less builder dialog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ilDefinitions Adds the definitions layer the guardrails family was missing: the seam between the `/api/execution/guardrails/definitions` payload and the `GuardrailDefinition`s `GuardrailBuilder` renders. Flow and Agents each carry their own copy of this today, and the two have drifted. - `definitions-wire.ts` mirrors the payload as hand-written types, reusing `GuardrailScope` and `GuardrailDefinitionStatus` from `builder-types` so the wire and display layers cannot diverge. It admits both products' nullability variants. - `definitions-parse.ts` validates unknown input and never throws: a non-array payload sets `inputError`, a bad definition is dropped whole and reported in `invalid`, unknown keys are stripped. zod is private to this module, pinned to the public mirror by a bidirectional assignability check on the hot path, a runtime key-set assertion and a source-level guard, so the folder's emitted declarations carry no schema types. - `definitions-copy.ts` holds the canonical copy for the six built-in validators as 63 lingui messages in the shared canvas catalog, keyed by raw wire values. Translations harvested from both products, 62 of 63 in each of the 12 locales. - `definitions-enrich.ts` resolves that copy onto the wire shape. Pure and React-free; `EnrichedGuardrailDefinition extends GuardrailDefinition`, so its output feeds the builder with no mapping. - `useGuardrailDefinitions` composes the three over `useState` + `fetch` + `AbortController`, following `useDiscoveryModels`. `options.definitions` skips the request entirely, which is how each product keeps its own transport. Unlike `useDiscoveryModels` the context is compared by content, not identity: keying the effect off identity made an inline context object refetch on every render without terminating. Where the products' English differed, all 17 choices are declared with a reason in `definitions-parity.test.ts` and asserted against both products' transcribed copy, so the shared table cannot quietly drift from the tables it replaces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds `GuardrailList` to the canvas guardrails family: the applied-guardrails
section both products own today (Agents `GuardrailsListingSection`, Flow
`GuardrailsEditor` + `SortableGuardrailItem`), extracted once.
The host filters and the list renders. Rows and definitions arrive already
filtered by feature flags, entitlements and scope, every callback is an intent
(dialogs, persistence and telemetry stay with the product), and `onReorder`
reports the visible array plus `{ from, to, id }` so a host rendering a filtered
view can splice the result back. Every addition beyond what both products show
today is opt-in, so adopting the list behind a flag renders what the host
renders now.
Reorder is real dnd-kit with pointer and keyboard sensors; the drag handle is a
real button, where Agents' handle today is an `aria-hidden` icon carrying the
listeners. With reorder off, no drag machinery mounts at all.
`GuardrailStatusChip` is `Badge`-based rather than the Radix-Toggle
`GuardrailChip`: these are read-only labels. `GuardrailStatusBanner` and
`MixedScopesBanner` are promoted to exports additively.
Chrome strings resolve through `useGuardrailListLabels` on `useSafeLingui` with
`guardrails.list.*` ids; 12 of the 17 are harvested from Flow's canvas catalog
into all 12 translated locales, the other 5 fall back to English per key.
Also here: `@dnd-kit/modifiers` added to apollo-react (wind already pinned it,
so no new install weight), the three label resolvers share one merge helper, and
`__fixtures__` no longer reaches the published bundle.
Promote the read-only status chip and the chip geometry constant it reuses. Copied verbatim from the AL-575 list branch (#1140), which introduced them: the palette needs the same chip for an unauthorized definition, and both PRs branch off the definitions layer rather than stacking, so each carries the shared files and whichever merges second drops its duplicate on rebase. Keep the two copies byte-identical.
Add `GuardrailPalette`, the picker both products open from their guardrails list: grouped definitions, an optional create-custom entry, and the loading, failed and empty states. The host filters and the palette offers. Definitions arrive pre-filtered (flags, entitlements, `FeatureDisabled`/`Disabled`, Tool scope), both callbacks are intents, and no telemetry, flag or product type crosses the boundary. Definitions are generic over the eight fields the palette reads, so `EnrichedGuardrailDefinition` and a product's own type both go in and come back out of `onSelectOotb` unchanged. Grouping and entry identity are re-derived from what both products already ship: one unheaded group in payload order without BYO definitions, otherwise a group per BYO folder or connector plus a trailing UiPath group, and BYO entries keyed by validator name and connection id. An `Unauthorised` definition is offered, chipped and not choosable (`aria-disabled`, so it stays reachable), which is Flow's behaviour; Agents lets it through to a builder that then refuses to save. Only the picker ships. Flow's dialog and inline overlay and Agents' sidebar takeover are host orchestration, shown in the stories rather than modelled in a wrapper. Nine `guardrails.palette.*` lingui ids, all harvested from the two products' own catalogs at 9 of 9 coverage in the 12 translated locales, asserted both ways against the shared canvas catalog. Three label resolvers now share one `mergeLabels` helper.
Integration branch only: it exists so a host can pin one preview package carrying every open apollo stream. Not for merging into main. Merges feat/apollo-react-guardrail-palette (#1147, AL-576) into feat/apollo-react-guardrail-list (#1140, AL-575). The chip files both branches carry merged clean, being byte-identical. The four append conflicts were resolved mechanically: locale catalogs and i18n.ts take the list side verbatim and append only what the palette adds, index.ts is the union of both barrels, i18n.test.ts keeps both suites, and the README orders sections along the data flow (definitions layer, list, palette, builder). Verified after the merge: Guardrails suite 440 passing (26 files), tsc, biome and rslib build clean.
|
Apollo Coded App preview deployments finished with failures.
|
Dependency License Review
License distribution
Excluded packages
|
📦 Dev Packages🧹 Dev packages cleaned up after PR close. Last updated: 2026-09-10 04:45:44 PT |
Storybook visual diff⏭️ Skipped: the apollo-design preview deployment did not succeed, so no comparison ran. Logs Updated (PT): Sep 10, 2026, 04:29:53 AM |
There was a problem hiding this comment.
🟡 Changes recommended
One or more issues must be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Temporary preview build combining Apollo React guardrail definitions, builder, list, palette, localization, and Apollo Wind form enablers.
Changes:
- Adds shared guardrail components and definition parsing/enrichment.
- Adds palette/list UX, drag-and-drop ordering, and localized catalogs.
- Extends MetadataForm with controlled values, string-list fields, tooltips, and validation accessibility.
File summaries
| File | Description |
|---|---|
| pnpm-lock.yaml | Updated as part of this pull request. |
| packages/apollo-wind/src/index.ts | Updated as part of this pull request. |
| packages/apollo-wind/src/components/ui/textarea.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/ui/select.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/ui/info-tooltip.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/ui/info-tooltip.test.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/ui/index.ts | Updated as part of this pull request. |
| packages/apollo-wind/src/components/forms/validation-converter.ts | Updated as part of this pull request. |
| packages/apollo-wind/src/components/forms/string-list-field.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/forms/metadata-form.stories.tsx | Updated as part of this pull request. |
| packages/apollo-wind/src/components/forms/index.ts | Updated as part of this pull request. |
| packages/apollo-wind/src/components/forms/form-schema.ts | Updated as part of this pull request. |
| packages/apollo-react/src/test/setup.ts | Updated as part of this pull request. |
| packages/apollo-react/src/i18n/index.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/index.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/utils.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/use-guardrail-definitions.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/types.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/render-parameter-bridge.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/palette-types.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/list-types.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/index.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/i18n.test.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-validator-form.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-palette.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-palette.stories.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-palette-utils.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-palette-utils.test.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-list-utils.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-list-utils.test.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-form-layout.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-form-layout.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/guardrail-form-layout.stories.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/form-schema-builder.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/definitions-wire.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/definitions-parse.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/definitions-parity.test.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/definitions-copy.test.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/parameter-label.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/mixed-scopes-banner.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/mixed-scopes-banner.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/map-enum-field.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-status-chip.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-status-chip.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-status-banner.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-status-banner.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-scope-selector.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-palette-item.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-palette-item.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-chip.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-chip.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-action-section.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-action-section.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/field-shell.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/field-shell.test.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/components/enum-list-chips-field.tsx | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/builder-utils.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/builder-types.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/fixtures/guardrail-palette.fixtures.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/fixtures/guardrail-list.fixtures.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/fixtures/dnd-geometry.ts | Updated as part of this pull request. |
| packages/apollo-react/src/canvas/components/Guardrails/fixtures/definitions-wire.fixtures.ts | Updated as part of this pull request. |
| packages/apollo-react/rslib.config.ts | Updated as part of this pull request. |
| packages/apollo-react/package.json | Updated as part of this pull request. |
Review details
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (7)
packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-list-row.tsx:107
- The default edit and remove buttons have the same accessible name for every row (
Edit guardrail/Remove guardrail), while the row is only a plaindiv. When a screen-reader user tabs through these buttons, the name of the guardrail the action applies to is not exposed. Use item-specific localized templates for these action labels, as the reorder/edit-row labels already do.
aria-label={labels.editItem}
packages/apollo-react/src/canvas/components/Guardrails/components/guardrail-list-row.tsx:153
- With
rowActivatesEdit, thisaria-labelbecomes the entire accessible name of the row and overrides all descendant text. Screen readers therefore hear only “Edit ”, not the visible BYO failure notices, description, provider, action, or scope information (and nested alert semantics may be lost). Preserve the edit action name while exposing the row's descriptive/status content viaaria-describedbyor an equivalent accessible structure.
role: 'button',
tabIndex: 0,
'aria-label': formatGuardrailFormMessage(labels.editRow, { name: item.name }),
onClick: handleEdit,
packages/apollo-react/src/canvas/components/Guardrails/components/map-enum-field.tsx:73
- The custom numeric handler parses and writes back every intermediate
inputvalue. After entering0, the next.is parsed as0and the controlled value removes the decimal before the user can enter the fraction, making normal keyboard editing of thresholds fail. Keep an editable string or defer numeric conversion until blur.
packages/apollo-react/src/canvas/components/Guardrails/definitions-parse.ts:120 byoValidatorNameis the one optional display field that does not useemptyToUndefined. A wire definition withbyoValidatorName: ''therefore failssafeParseand is reported as invalid instead of being returned as a normal UiPath definition, contradicting the parser test and dropping that definition from consumers.
packages/apollo-react/src/canvas/components/Guardrails/guardrail-list-utils.ts:59- With a successfully loaded empty catalog, this length check suppresses the
Unavailablestate for every BYO row, so the UI silently treats missing definitions as normal. Distinguish an in-flight catalog from an explicitly loaded empty array before applying this guard.
packages/apollo-react/src/canvas/components/Guardrails/guardrail-palette-utils.ts:73 - These synthetic keys are not disjoint from customer-controlled folder or connector names. For example, a BYO group named
__uipath__receives the same key as the trailing UiPath group, while__byo__collides with the unnamed BYO group; React then sees duplicate keys and can reconcile the wrong group. Namespace or otherwise encode every user-derived group key before returning it.
packages/apollo-react/src/canvas/components/Guardrails/i18n.test.ts:160 - The translated catalog files all stop after
guardrails.list.status-unauthorized, so the five newer list IDs (edit-row, the three status labels, andadministration-governance) fall back to English in every translated locale. The coverage test added here only checks palette messages, so it does not catch this shipped localization regression; add the list translations and assert list coverage as well.
- Files reviewed: 104/105 changed files
- Comments generated: 8
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| useEffect(() => { | ||
| if (!hasTools && selectedScopes.includes('Tool')) { | ||
| const cleaned = selectedScopes.filter((s) => s !== 'Tool'); | ||
| onChange({ scopes: cleaned }); | ||
| } |
| ? { | ||
| label: labels.saveAsNew, | ||
| onClick: handleSaveAsNew, | ||
| disabled: !isDefinitionAvailable, |
| {field.tooltip && ( | ||
| <InfoTooltip | ||
| content={field.tooltip} | ||
| aria-label={field.tooltipAriaLabel ?? 'More information'} | ||
| /> |
| <Input | ||
| value={recipientDisplayValue} | ||
| onChange={(e) => | ||
| handleRecipientSelect({ value: e.target.value, displayName: e.target.value }) | ||
| } | ||
| placeholder={searchPlaceholder} | ||
| aria-invalid={errors?.recipient ? true : undefined} | ||
| /> |
| <Input | ||
| aria-label={`${paramDef.label}: ${sourceDef?.optionLabels?.[key] ?? key}`} | ||
| type="number" | ||
| value={currentMap[key] ?? defaults[key] ?? paramDef.min ?? 0} | ||
| onChange={(e) => handleThresholdChange(key, Number.parseFloat(e.target.value) || 0)} | ||
| min={paramDef.min} | ||
| max={paramDef.max} | ||
| step={paramDef.step} | ||
| className="flex-1" | ||
| /> |
| inputError: parsed.inputError, | ||
| loading, | ||
| error, | ||
| refetch: load, |
| <StringListField | ||
| field={field} | ||
| value={formField.value as string[] | undefined} | ||
| onChange={formField.onChange} | ||
| error={error} | ||
| disabled={disabled} | ||
| required={required} | ||
| /> |
| <Textarea | ||
| value={item} | ||
| onChange={(e) => updateItem(index, e.target.value)} | ||
| minRows={field.minRows ?? 2} | ||
| maxLength={field.maxLength} | ||
| disabled={disabled} | ||
| aria-label={`${field.label} ${index + 1}`} | ||
| className="flex-1" | ||
| /> |
📊 Coverage + size by packagePer-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.
"Coverage" is each package's own |
|
Published: CI: Test Coverage, Typecheck, Lint, Format and Build green. Three red checks, none of them this |
Do not merge, and do not review. This branch exists only to publish one dev preview
package that carries every open apollo guardrails stream at once, because a
-prNNNNpreview only carries its own stack: #1140's lacks the palette and #1147's lacks the list,
while both host PRs need both.
What is in it
string-list,InfoTooltip,aria-invalid=
feat/apollo-react-guardrail-listwithfeat/apollo-react-guardrail-palettemerged in. Thepalette branches off #1139 rather than stacking on #1140, so neither stream's own preview has
both components.
For the host sessions
Pin the pair from this PR's
dev-packagesbot comment (@uipath/apollo-react@6.42.0-pr1148.<sha>and
@uipath/apollo-wind@2.47.2-pr1148.<sha>). Every labeled push republishes under a new shaand unpublishes the previous one, so read the versions off the comment rather than any doc, and
re-pin when a stream moves.
Maintenance
Whoever pushes to a stream re-merges it here and reports the new versions. The merge is
mechanical: the
GuardrailStatusChipfiles both branches carry are byte-identical and mergeclean; the four append conflicts (13 locale catalogs,
i18n.ts,index.ts,i18n.test.ts,README.md) resolve by taking the list side verbatim and appending only what the other streamadds, keeping both test suites, and unioning the barrel.
Verified after the merge: Guardrails suite 440 passing (26 files),
tsc, biome andrslib buildclean.