Repository navigation
refactor(dashboard): overlay, feedback and table primitives as kit adapters (KEA-7886, trilha D) - #17322
Merged
Conversation
…EA-7886, trilha D)
… Toaster (KEA-7886, trilha D)
…n, realign portal queries (KEA-7886, trilha D)
…l (KEA-7886, trilha D)
…A-7886, trilha D)
…A-7886, trilha D)
…stays live under a dialog (KEA-7886, trilha D)
…iled with the kit (KEA-7886, trilha D)
…-restoration (KEA-7886, trilha D)
…ropdownMenu and Slider (KEA-7886, trilha D)
…egmentedControl over Tabs (KEA-7886, trilha D)
…eeps the phone layout; closed CollapsibleSection is inert; Collapsible title truncates (KEA-7886, trilha D)
… tile; view_column mapped (KEA-7886, trilha D)
…lity (KEA-7886, trilha D)
…t (KEA-7886, trilha D)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Track D of the OmniRoute → Keak CI UI Kit migration (Linear KEA-7886): the overlay, feedback and table primitives become thin adapters over the vendored kit (
packages/ui-kit). Every adapter keeps its file, default export, named exports and legacy props, so no importer is edited. Adapters import kit subpaths (@omniroute/ui-kit/<file>), never the barrel, which keeps react-day-picker and the rest of the kit out of every vitest worker._tasks/superpowers/specs/2026-10-19-uikit-migration-design.md§3.6 (primitive adapters, API preserved) + §3.5 (<Icon>) + §3.9 (i18n), and_tasks/superpowers/specs/uikit/shared/primitives.md_tasks/superpowers/plans/2026-10-19-uikit-migration.md, Tasks 16–22feat/new-uikit(integration branch). Track A (feat(dashboard): CI UI Kit foundation — vendored kit, token bridge, theme, UI_KIT_SHELL (KEA-7886, trilha A) #17279) is back-merged here (57ee4c2c, clean merge).Changes by task
Task 16: Modal / ConfirmModal over the kit Dialog (Radix) (
603711ab,831ab9c5,7e6ae03d,840c88e3,9452dcd3)src/shared/components/Modal.tsx: kitDialogwitharia-modal, Radix title wiring (sr-onlycommon.dialogTitleFallbackwhen there is no title), own focus restoration for controlledisOpen,TALL_MODAL_PROPSunchanged, outside-clicks on toasts ignored, one scroll owner (body) with the kit mobile guttersrc/i18n/messages/{en,pt-BR}.json:common.dialogTitleFallbackTask 17: Tooltip / InfoTooltip over the kit Tooltip (
363f99d4,7e6ae03d,9452dcd3)src/shared/components/Tooltip.tsx,InfoTooltip.tsx: Radix tooltip (hover + focus, Escape); a disabled trigger is wrapped in a focusable span; InfoTooltip is now a real, named<button>Task 18: NotificationToast bridges the store into the kit Toaster (
1e946c45,7e6ae03d,840c88e3)src/shared/components/NotificationToast.tsx:<Toaster position="top-right">+ a store bridge; the toaster root stays a live region under an open dialogconfig/quality/eslint-suppressions.json: stale suppression prunedTask 19: EmptyState + Loading family (
1a4d6234)src/shared/components/EmptyState.tsx: kitEmptyState; Material ids render through<Icon>(Lucide), emoji keep the detection regex; the action is theButtonadapter (variant="primary")src/shared/components/Loading.tsx:Spinnerkeepsrole="status"+aria-label(Lucide spinner),PageLoadingis the kitLoadingStatepanel centred over the viewport,Skeleton/CardSkeletonare kit skeletons (ci-skeleton,aria-hidden)Task 21: Breadcrumbs + Avatar (
7dfadb7b)src/shared/components/Breadcrumbs.tsx: kitBreadcrumb*;PATH_LABELS,getLabel, the/dashboardearly return and the translatedaria-labelstay;aria-current="page"on the last crumb. The kitBreadcrumbLinkhas noasChild, so links staynext/link(client-side navigation) carrying the kitci-breadcrumb__linkclasssrc/shared/components/Avatar.tsx: kitAvatar(initials fromname, same size names,?fallback); the rainbow palette is goneTask 22: DataTable family (
2337142e)src/shared/components/DataTable.tsx:DataTableShell loading+ kitTable*+ theEmptyStateadapter; sticky header on the--table-header-bgtoken, selected row =aria-selected+data-state="selected", row click + Enter/Space activation and the nested-control guard keptFilterBar.tsx: same signature,handleClear/hasActiveFilterskept;Input type="search" icon="search", one compactSelectper filter (empty option = all),Button variant="ghost" icon="close"; colour styles removedColumnToggle.tsx: kitDropdownMenu(non-modal, like the legacy popover) +DropdownMenuCheckboxItem, menu stays open while togglingFilterPills.tsx:role="group"ofButtonadapters (size="sm",aria-pressed), counts viaBadge size="sm"PresetSlider.tsx: kitSlider presets showValuesrc/i18n/messages/{en,pt-BR}.json:common.clearFilters("Clear filters" / "Limpar filtros")Task 20: Collapsible / CollapsibleSection / SegmentedControl (
106d77fe)Collapsible.tsx: kitAccordion(bordered,inline→plain), the kit trigger is the single button witharia-expanded,trailingsits outside it,defaultOpenhonoured, children mount only while open (as before)CollapsibleSection.tsx: same, open by default, count as a kitBadge(variant="secondary");// F1: swap for the Badge adapter once track C mergesSegmentedControl.tsx: kit capsuleTabs(role="tablist"with thearia-label,role="tab"+aria-selected, arrow keys),onChange(value)keptTests added or realigned
Added (adapter tests, all green):
tests/unit/ui/adapters/modal.test.tsx,tooltip.test.tsx,toast.test.tsx(D1)tests/unit/ui/adapters/empty-loading.test.tsx4/4,breadcrumbs-avatar.test.tsx3/3,datatable.test.tsx6/6 (the brief's 5 + FilterBar search/select/clear),collapsible-segmented.test.tsx3/3Realigned (same assertion, kit DOM):
603711ab+ 9 in831ab9c5query the modal through its portal (document.body/ the dialog) instead of the render container; five mount checks became the stricter[role="dialog"];modal-focus-restorationkeeps the detached-opener focus spy (50e1b182);tooltip-portal-behavior.test.tspins@omniroute/ui-kit/tooltip;analytics-token-hover-tooltip.test.tsxuses pointer events + unmounts its rootstests/unit/dashboard-localization-contract.test.ts: EmptyState still detects Material ids (usesMaterialSymbol), now asserts they render through<Icon name={icon}instead of amaterial-symbols-outlinedspantests/unit/ui/data-table-loading-a11y.test.tsx: the busy status region is the kit BrandLoader (role="status",aria-busy); the decorative glyph is itsaria-hiddenSVG instead of ⏳; "layout/animation" asserts the kit overlay instead of inline styles; "no table while loading" asserts the retained rows arearia-hidden+inert; "no status region" checks look for[aria-busy="true"](the kit rendersaria-busy="false"when idle)tests/unit/design-kit-bridge.test.ts(DataTable guard): header token kept; the zebra/border token assertions became "rows render through@omniroute/ui-kit/table" + "kit row selection viadata-state"; no colour literal and no dead fallbacks still assertedCommits 1a4d623 and 7dfadb7 carry the D1 adapter tests while they were still red; 840c88e and 9452dcd make them pass (history kept as-is, PR merges with --merge).
Validation
npm run lint -- --concurrency=6npm run typecheck:corenpm run check:dashboard-typechecknpm run check:ui-icunpm run test:vitest:ui--maxWorkers=1 --testTimeout=60000resilience-connections18/18,modelsCombosCatalog23/23,compressionPanelEnginesPartialWrite3/3,manifestAdapter12/12,proxySaveRefresh1/1 → load/timeout only. Inherited:rtk-context-page-load-failure(3, known base red) andapi-key-redis-auth-cache(hook timeout, fails identically on the base)npm run check:tracked-artifactsnpm run check:cycles(advisory)node scripts/i18n/check-key-completeness.mjs --warncommon.clearFilters,common.dialogTitleFallback(this PR) andfeatureFlagUiKitShellDescription(track A); left to the i18n wavenpm run buildnext build+postbuild(standalone assembly, worker bundling) completed, rc 0 (_artifacts/D-pr-build-113.log). Thetail -60window starts after Turbopack's summary, so the warning count was not captured in this single buildManual smoke
Dev server on port 20151 with an isolated
DATA_DIRand dist dir, logged in through the e2e helper, Playwright captures light/dark at 1440 and 390 px (_artifacts/D-smoke.spec.ts):/dashboard/providers(_artifacts/D-providers-{light,dark}-{1440,390}.png): kit breadcrumb, filter chips, empty-provider hero/dashboard/settings→ general (_artifacts/D-settings-*.png) and/dashboard/settings/routing(_artifacts/D-settings-routing-*.png, 2 kit accordions + a kit empty state)/dashboard/translator(_artifacts/D-translator-*.png): 3 accordions (Collapsible), 2 capsule tab lists (SegmentedControl), 5 tooltip triggers/dashboard/resilience/connectionsand/dashboard/costs(_artifacts/D-resilience-connections-*.png,_artifacts/D-costs-*.png, 4 kit skeletons)_artifacts/D-modal-{light,dark}-1440.png); open tooltip on the translator ("The API format your app speaks…",_artifacts/D-tooltip-light-1280.png)_artifacts/D-datatable-390.png, fix round 1):/dashboard/conductorwith the fleet endpoint fulfilled by a Playwright fixture (a fresh data dir has no hub). Aftermin-w-0the 3-column runners table fits the 306 px card (auto width, no sideways scroll); the 5-column tasks table is 484 px wide and scrolls inside its own container, as the legacy table did.Fix round 1 (review of
57ee4c2c)50d1893dSegmentedControl: tabs no longer carry a danglingaria-controls(no panel is rendered);sizemaps onto the triggers (smh-7 px-2 text-xs,lgh-10 px-4 text-base); the legacy phone layout is back on the tablist (w-full sm:w-auto, segmentsflex-1on phones). A closed CollapsibleSection's content isinert, so it is out of the tab order as well asaria-hidden. The Collapsible/CollapsibleSection trigger's children wrapper can shrink, so long titles truncate.8bb7a526DataTable:min-w-0on the kit table, so narrow tables keep their auto width (the kit floors.ci-tableat 40rem). EmptyState: an emoji icon istext-2xland fits the kit's 2.5rem tile.view_column→ LucideColumns3iniconMap.ts(icon-map-coveragewas red without it).7a133bdcdata-table-loading-a11y: the status-region test asserts the loading label (aria-label) and that noaria-hiddenancestor covers it, replacing a role check that could not fail.initials()): one word gives one letter ("Ada" → "A"), several words give the first and last initials. The legacy rule was the first two letters / the first two words. No app caller.Pendências
Kit (from batch D1):
Toasterroot should be a live region itself (aria-live="polite"on[data-slot="toaster"],toast.tsx:114). The adapter works around it inuseToasterLiveRegion().toast()has no dismiss callback (noonDismiss/onAutoClose), so a kit-side close cannot update the store; it also blocks per-entrydismissible: false. Minor today: no caller usesduration: 0ordismissible: false.aria-label="Dismiss notification",toast.tsx:184); it needs acloseLabelprop.Track D2:
4.
CollapsibleSectionrenders the kitBadgedirectly until track C'sBadgeadapter lands (F1 checkpoint).5.
FilterPills/ColumnToggle/EmptyStatesit on the legacyButton/Badge/Input/Selectin this branch; they pick up track C's kit adapters on merge.6.
DataTableShellwould print an English-only "N results" count, so the adapter does not passresultCount.