Skip to content

feat(apollo-wind): scrollable tabs + per-tab error badges in tabbed MetadataForm#922

Draft
CalinaCristian wants to merge 2 commits into
mainfrom
feat/apollo-wind-compact-tabs
Draft

feat(apollo-wind): scrollable tabs + per-tab error badges in tabbed MetadataForm#922
CalinaCristian wants to merge 2 commits into
mainfrom
feat/apollo-wind-compact-tabs

Conversation

@CalinaCristian

Copy link
Copy Markdown
Collaborator

What

Adapts the tabbed MetadataForm (properties-panel form) so it holds up in a narrow panel and surfaces validation state on the tab strip.

  • Scrollable tabsTabbedStepForm now renders its tab strip with ScrollableTabsList instead of a plain TabsList. When the tabs overflow a narrow panel they get prev/next chevrons and the active tab auto-scrolls into view. Wide panels are unchanged (no chevrons render when nothing overflows).
  • Per-tab error badges — each tab shows a count badge of its fields that currently have errors, computed from react-hook-form state via useFormState (so it updates live). Fields on inactive tabs are counted too, so a hidden validation problem still surfaces on its tab.

Why

Consumed by flow-workbench's redesigned node properties panel, which docks narrow. Today the built-in tab strip clips overflowing tabs with no affordance, and validation errors on non-active tabs are invisible. Both fixes live here because the tab strip is owned by TabbedStepForm; the consumer drives it purely through schema.steps + form plugins, so no consumer-side change is needed (errors are already in form state via the consumer's validation plugin).

Testing

  • pnpm --filter @uipath/apollo-wind test — 986 pass, incl. a new test asserting a badge on an errored (inactive) tab.
  • biome lint + format clean.

Notes

  • Additive: badges only appear when fields have errors; the scrollable list reads identically to a plain strip when nothing overflows.
  • dev-packages label added to publish a dev build for flow-workbench to consume.

🤖 Generated with Claude Code

…etadataForm

Adapt the tabbed properties-panel form to narrow panels:

- TabbedStepForm now renders its tab strip with ScrollableTabsList, so
  overflowing tabs get prev/next chevrons and the active tab auto-scrolls
  into view. Wide panels are unaffected (no chevrons when nothing overflows).
- Each tab shows a count badge of its fields that currently have errors,
  computed from react-hook-form state via useFormState. Fields on inactive
  tabs are counted too, so a hidden validation problem still surfaces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 16, 2026 15:59
@CalinaCristian CalinaCristian added the dev-packages Adds dev package publishing on pushes to this PR label Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (PT)
apollo-design 🟢 Ready Preview, Logs Jul 16, 2026, 12:20:47 PM
apollo-docs 🟢 Ready Preview, Logs Jul 16, 2026, 12:20:47 PM
apollo-landing 🟢 Ready Preview, Logs Jul 16, 2026, 12:20:47 PM
apollo-vertex 🟢 Ready Preview, Logs Jul 16, 2026, 12:20:47 PM

@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • 1950 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1720
ISC 89
Apache-2.0 55
BSD-3-Clause 27
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.2.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

📦 Dev Packages

Package Status Updated (PT)
@uipath/apollo-wind@2.28.0-pr922.28ca0a5 🟢 Published Jul 16, 2026, 12:18:30 PM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the tabbed MetadataForm experience in narrow properties panels by making the tab strip horizontally scrollable (with chevrons when overflowed) and by surfacing validation state per tab via an error-count badge.

Changes:

  • Replaced the plain TabsList with ScrollableTabsList in TabbedStepForm to support overflow scrolling and auto-reveal of the active tab.
  • Added per-tab error count badges computed from react-hook-form state (via useFormState) so errors on inactive tabs are still visible.
  • Added a unit test asserting a badge appears on an inactive tab with a seeded field error.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/apollo-wind/src/components/forms/metadata-form.tsx Adds ScrollableTabsList tab strip and computes per-step error counts from RHF state to render badges.
packages/apollo-wind/src/components/forms/metadata-form.test.tsx Adds a test to verify an inactive tab shows an error-count badge when an error is present.

Comment on lines +382 to +399
const errorCountByStepId = useMemo(() => {
const counts: Record<string, number> = {};
for (const step of visibleSteps) {
let count = 0;
for (const section of step.sections) {
if (section.conditions && !context.evaluateConditions(section.conditions)) {
continue;
}
for (const field of section.fields) {
if (context.form.getFieldState(field.name, formState).error) count++;
}
}
counts[step.id] = count;
}
return counts;
// `formState` is the reactive dependency; `context` is stable per render.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visibleSteps, formState, context]);
Comment on lines +430 to +444
<TabsTrigger
key={step.id}
value={step.id}
className="inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm"
>
{step.title}
{errorCount > 0 && (
<span
title={`${errorCount} ${errorCount === 1 ? 'issue' : 'issues'}`}
className="grid h-4 min-w-4 place-items-center rounded-full bg-error px-1 text-[10px] font-semibold leading-none text-foreground-on-accent"
>
{errorCount}
</span>
)}
</TabsTrigger>
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core 9.0% 43.82 MB 57.31 MB ±0
@uipath/apollo-react 35.7% 0.0% (0/1) 7.35 MB 27.99 MB ±0
@uipath/apollo-wind 40.6% 93.8% (15/16) 395.8 KB 2.58 MB +660 B
@uipath/ap-chat 85.8% 43.43 MB 55.91 MB ±0

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

A composite field (e.g. a connector editor holding many sub-fields) surfaces
several validation issues at once, stored as an array of errors under one field
name. Count each array entry so the tab badge reflects the number of issues the
user sees inside the field instead of collapsing the whole field to "1". Plain
fields (a single error object) still count as 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 16, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment on lines +435 to +439
<TabsTrigger
key={step.id}
value={step.id}
className="inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm"
>
Comment on lines +450 to +456
onFormInit: (context) => {
context.form.setError('field1.0', { message: 'Channel is required' });
context.form.setError('field1.1', {
message: 'Timestamp is required',
});
context.form.setError('field1.2', { message: 'Message is required' });
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-packages Adds dev package publishing on pushes to this PR pkg:apollo-wind size:L 100-499 changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants