Skip to content

fix(a11y): resolve Lighthouse button-name and aria-valid-attr-value failures in output modal - #14278

Merged
olayinkaadelakun merged 2 commits into
release-1.12.0from
LE-2014
Jul 30, 2026
Merged

fix(a11y): resolve Lighthouse button-name and aria-valid-attr-value failures in output modal#14278
olayinkaadelakun merged 2 commits into
release-1.12.0from
LE-2014

Conversation

@olayinkaadelakun

@olayinkaadelakun olayinkaadelakun commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes two Lighthouse accessibility failures on the component output modal (Outputs/Logs tabs + copy-to-clipboard button):

  • button-name — the icon-only copy button had no accessible name.
  • aria-valid-attr-value — the tab switcher's aria-controls pointed at a panel element that never existed.

What changed

  • Copy button naming: added aria-label to the copy button, dynamically reflecting the active tab — "Copy output" on the Outputs tab, "Copy logs" on the Logs tab — since the button copies whatever tab is currently showing.
  • Tab/panel ARIA linkage: paired each TabsTrigger with a matching TabsContent (Radix's expected trigger/content contract). Previously the panel content (SwitchOutputView) was a disconnected sibling driven by manual string branching, so Radix's auto-generated aria-controls referenced a nonexistent id.
  • Internal tab identifiers normalized: "Outputs"/"Logs" → lowercase "outputs"/"logs", decoupled from the translated visible labels. Extracted as an exported OutputModalTab type shared between outputModal/index.tsx and switchOutputView/index.tsx instead of duplicating the union.
  • Layout regression fix: the real output content briefly ended up nested inside the small, overflow-hidden, absolutely-positioned pill meant only for the switcher buttons. Fixed by scoping that constrained styling to TabsList alone and giving Tabs/TabsContent a proper flex-1 chain so the content fills the modal again.
  • Focus-visibility fix: TabsList's overflow-hidden was clipping the browser's default focus outline on the tab triggers. Replaced with an inset focus ring (focus-visible:ring-2 focus-visible:ring-inset), which renders inside the trigger's own box and can't be clipped.
  • Translations: added output.copyOutputAria and output.copyLogsAria across all 7 locales (en, de, es, fr, ja, pt, zh-Hans).
  • Tests: new outputModal.a11y.test.tsx (10 tests) — axe checks, accessible-name correctness per tab, aria-controls validity, tab-switch/copy behavior parity, and regression guards for the layout and focus-ring fixes.

How QA can test

Automated
cd src/frontend
npx jest src/CustomNodes/GenericNode/components/outputModal --no-coverage
npx tsc --noEmit

Expect all 10 tests passing, no new type errors.

Manual — copy button naming

  1. Run a flow so a component has output data, open its output modal.
  2. Turn on a screen reader (VoiceOver on Mac: Cmd+F5) and Tab to the copy button.
  3. Confirm it announces "Copy output" while the Outputs tab is active.
  4. Switch to the Logs tab (see keyboard steps below) and Tab back to the copy button — confirm it now announces "Copy logs".
  5. Click copy in each tab state and confirm the clipboard contents match what's actually shown (Outputs vs Logs).

Manual — tab switcher keyboard behavior

  1. Tab into the modal until focus lands on the active tab trigger ("Outputs").
  2. Press Tab again — focus should leave the tablist entirely (move to the panel content), not jump to "Logs". This is expected per the ARIA tabs pattern.
  3. Tab back to the "Outputs" trigger, then use Left/Right arrow keys — focus and selection should move between Outputs and Logs.
  4. Confirm a visible focus ring appears on whichever tab is focused at every step (this was previously invisible due to clipping).

Manual — layout

  1. Open the output modal and confirm the output/log content still fills the full modal height, same as before this change (no clipping or empty space).
  2. Confirm the Outputs/Logs switcher stays a small, centered pill at the top — not stretched to the full width of the modal.

Manual — translations

  1. Switch the app language to each of de/es/fr/ja/pt/zh-Hans.
  2. Open the output modal and confirm the copy button's accessible name (screen reader) and any visible tab labels are translated, not raw i18n keys.

Summary by CodeRabbit

  • Accessibility

    • Improved the output modal’s accessibility with descriptive, tab-specific copy button labels.
    • Enhanced tab navigation, focus styling, and panel associations for screen readers and keyboard users.
  • Bug Fixes

    • Improved switching between Outputs and Logs views.
    • Copying now consistently copies content from the currently selected tab.
  • Localization

    • Added translated accessibility labels for copying outputs and logs across supported languages.
  • Tests

    • Added coverage for accessibility compliance, tab behavior, focus states, and clipboard functionality.

@olayinkaadelakun olayinkaadelakun self-assigned this Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

OutputModal behavior

Layer / File(s) Summary
Modal tab contract and copy content
src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx
Introduces lowercase typed tab values, updates output/log content selection, and assigns localized copy labels based on the active tab.
Tab view integration
src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx, src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx
Renders separate output and log panels and updates SwitchOutputView to use the shared tab type and lowercase values.
Accessibility coverage and localized labels
src/frontend/src/CustomNodes/GenericNode/components/outputModal/__tests__/*, src/frontend/src/locales/*
Adds accessibility, tab behavior, clipboard, layout, focus styling, and localized ARIA label coverage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OutputModal
  participant Tabs
  participant TabsContent
  participant SwitchOutputView
  OutputModal->>Tabs: set active tab value
  Tabs->>TabsContent: select outputs or logs panel
  TabsContent->>SwitchOutputView: render fixed tab type
  SwitchOutputView-->>TabsContent: render selected data view
Loading

Suggested reviewers: ramgopalsrikar

🚥 Pre-merge checks | ✅ 9
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: accessibility fixes for the output modal, including button naming and ARIA validity issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test Coverage For New Implementations ✅ Passed PASS: The PR adds a substantive frontend a11y/regression test suite (outputModal.a11y.test.tsx) covering ARIA, copy behavior, layout, and focus fixes, matching the changed code.
Test Quality And Coverage ✅ Passed The new Jest/RTL suite covers axe, accessible naming, ARIA linkage, layout/focus regressions, tab switching, and copy behavior, matching repo patterns.
Test File Naming And Structure ✅ Passed outputModal.a11y.test.tsx is a colocated Jest/RTL test with clear describe/it names, setup/teardown, and positive/negative coverage; it matches repo frontend test conventions.
Excessive Mock Usage Warning ✅ Passed Mocks are limited to stores, icon, clipboard, and a heavy child; the tests still exercise real modal/tab/copy behavior, so they aren't excessive.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch LE-2014

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the bug Something isn't working label Jul 27, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx (1)

27-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Extract the shared outputs/logs selection logic into one helper. Both files independently re-implement activeTab/type === "outputs" ? data.outputs[...] : data.logs[...] against the same OutputModalTab contract; this PR already had to touch both spots to rename the tab literals, showing the duplication is prone to drifting.

  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx#L27-L46: extract a small shared helper (e.g. getFlowPoolResult(flowPoolNode, outputName, tab)) that both getOutputContent here and SwitchOutputView can call instead of duplicating the ternary.
  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx#L51-L54: replace the local type === "outputs" ? ... : ... selection with the same shared helper.
♻️ Proposed shared helper
// e.g. in a shared utils module colocated with OutputModalTab
export function getFlowPoolResult(
  flowPoolNode: { data?: { outputs?: Record<string, unknown>; logs?: Record<string, unknown> } } | undefined,
  outputName: string,
  tab: OutputModalTab,
) {
  return tab === "outputs"
    ? flowPoolNode?.data?.outputs?.[outputName]
    : flowPoolNode?.data?.logs?.[outputName];
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx`
around lines 27 - 46, Extract the duplicated outputs/logs lookup into a shared
getFlowPoolResult helper aligned with the OutputModalTab contract. Update
src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx lines
27-46 so getOutputContent uses the helper, and update
src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx
lines 51-54 so SwitchOutputView uses it instead of its local ternary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx`:
- Around line 27-46: Extract the duplicated outputs/logs lookup into a shared
getFlowPoolResult helper aligned with the OutputModalTab contract. Update
src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx lines
27-46 so getOutputContent uses the helper, and update
src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx
lines 51-54 so SwitchOutputView uses it instead of its local ternary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 57a14754-c589-4191-8d92-b25e05b3058d

📥 Commits

Reviewing files that changed from the base of the PR and between 683eae6 and c0c33c8.

📒 Files selected for processing (10)
  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/__tests__/outputModal.a11y.test.tsx
  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx
  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx
  • src/frontend/src/locales/de.json
  • src/frontend/src/locales/en.json
  • src/frontend/src/locales/es.json
  • src/frontend/src/locales/fr.json
  • src/frontend/src/locales/ja.json
  • src/frontend/src/locales/pt.json
  • src/frontend/src/locales/zh-Hans.json

@github-actions

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 47%
47.23% (67753/143443) 70.15% (9577/13651) 46.1% (1575/3416)

Unit Test Results

Tests Skipped Failures Errors Time
5395 0 💤 0 ❌ 0 🔥 18m 53s ⏱️

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 16.27907% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.39%. Comparing base (8c56958) to head (c0c33c8).
⚠️ Report is 49 commits behind head on release-1.12.0.

Files with missing lines Patch % Lines
...Nodes/GenericNode/components/outputModal/index.tsx 10.25% 35 Missing ⚠️
.../outputModal/components/switchOutputView/index.tsx 75.00% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (16.27%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.12.0   #14278      +/-   ##
==================================================
+ Coverage           61.26%   61.39%   +0.12%     
==================================================
  Files                2347     2344       -3     
  Lines              238587   236781    -1806     
  Branches            35590    33317    -2273     
==================================================
- Hits               146180   145378     -802     
+ Misses              90585    89636     -949     
+ Partials             1822     1767      -55     
Flag Coverage Δ
frontend 59.84% <16.27%> (+0.18%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../outputModal/components/switchOutputView/index.tsx 36.75% <75.00%> (-0.15%) ⬇️
...Nodes/GenericNode/components/outputModal/index.tsx 22.51% <10.25%> (-2.29%) ⬇️

... and 190 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Jul 28, 2026
@olayinkaadelakun
olayinkaadelakun added this pull request to the merge queue Jul 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 29, 2026
@olayinkaadelakun
olayinkaadelakun added this pull request to the merge queue Jul 30, 2026
Merged via the queue into release-1.12.0 with commit b4d31b1 Jul 30, 2026
108 of 109 checks passed
@olayinkaadelakun
olayinkaadelakun deleted the LE-2014 branch July 30, 2026 12:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants