Skip to content

fix(a11y): accessible names, dialog titles, keyboard controls, and toast dismissal across viewers, chat, and modals - #14300

Open
viktoravelino wants to merge 11 commits into
release-1.12.0from
LE-2041
Open

fix(a11y): accessible names, dialog titles, keyboard controls, and toast dismissal across viewers, chat, and modals#14300
viktoravelino wants to merge 11 commits into
release-1.12.0from
LE-2041

Conversation

@viktoravelino

@viktoravelino viktoravelino commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Jira: LE-2041 · Parent epic: LE-1505

Summary

Seven independent a11y quick wins on top of release-1.12.0. Label/semantics-level only — no visual or behavioral redesign. 24 new i18n keys added to all 7 locales.

  • Shortcut modifiers announced: modifier icons in RenderKey were aria-hidden, so "Cmd+S" announced as "S" on every /settings/shortcuts row and canvas shortcut tooltip. Added sr-only text alternatives.
  • Chat live regions: streamed replies were silent. Both chat views (playground page + IO modal) get role="log" containers and an sr-only status region that announces a reply once it finishes streaming — no token-by-token spam.
  • Dialog names: list-selection dialog and model-provider modal used a styled div instead of DialogTitle (no accessible name). Real titles added; list-selection search input labeled.
  • Icon-only controls named (had literally empty accessible names): image viewer (5), PDF viewer (4 + zoom level input), flow header save, sidebar clear-filter, node output copy.
  • Mouse-only → real buttons: password show/hide, multiselect badge remove, slider click-to-edit value. All data-testids preserved. Review round: the password toggle now stays mounted (visually hidden) while the field is being edited, so forward Tab from the field still reaches it.
  • Toast dismissal: focusable, named dismiss button in error/success/notice toasts; body-click and auto-dismiss timing unchanged.
  • Focus order: template get-started card tabIndex={1}0 (only positive tabindex in the codebase). Review round: cards also gained role="button" and an accessible name (the template name).

QA — how to test

  1. Shortcuts: with a screen reader, read the Keyboard Shortcut column on /settings/shortcuts — must announce modifiers ("Command S", not "S"). Same for canvas toolbar shortcut tooltips.
  2. Chat: send a playground message; the completed reply is announced once (not per token).
  3. Dialogs: node list-selection dialog and Settings → Model Providers modal announce meaningful titles.
  4. Icon controls: image viewer / PDF viewer toolbars, flow save, sidebar clear-filter, node output copy — every control announces a name.
  5. Keyboard-only: Tab to and activate password toggle, multiselect chip remove, slider value edit — reachable, focus ring visible, Enter/Space works. Password toggle specifically: focus the field, then Tab twice (expand-editor icon, then toggle) — visible focus, Enter reveals/masks the value.
  6. Toasts: trigger an error toast; Tab reaches a named dismiss button, Enter closes; auto-dismiss timing unchanged.
  7. Templates modal: tab order through Get Started cards follows visual order; each card announces as a button named after its template.

Verification

  • Full jest suite green; 6 new a11y test files (15 assertions verified to fail against pre-fix code). Review round added 5 more a11y test files (chat live region + response-complete cue, image viewer, PDF viewer, password toggle, template card focus/semantics); a11y+chat+modal scoped run: 505 suites / 5660 tests green.
  • Live IBM Equal Access scan post-fix: /settings/shortcuts and all 14 static routes report zero violations; remaining canvas/playground violations are pre-existing and tracked by LE-1753 / LE-1756 / LE-1514.
  • Zero new TypeScript/biome errors; locale JSONs validated (parity, no duplicate keys).

Summary by CodeRabbit

  • Accessibility Improvements

    • Added localized accessible labels to dialogs, alerts, buttons, inputs, viewers, sliders, password controls, and filter actions.
    • Improved keyboard and screen-reader support for chat messages, shortcut keys, selectable options, and focusable cards.
    • Chat responses are now announced when generation completes without repeated announcements during streaming.
  • Localization

    • Added corresponding accessibility translations across supported languages.
  • Tests

    • Added accessibility coverage for dialogs, alerts, list controls, sliders, shortcuts, and modal components.

- announce shortcut modifier keys (sr-only text next to aria-hidden icons)
- role=log chat containers + one-shot completion announcement in both
  playground and IO modal chat views
- real DialogTitle on list-selection dialog and model-provider modal
- accessible names for 12 icon-only controls (image viewer, PDF viewer,
  flow save, sidebar clear-filter, node output copy)
- password toggle, multiselect badge remove, and slider value edit are
  real buttons now (testids preserved)
- focusable named dismiss button on error/success/notice toasts
- tabIndex 1 -> 0 on template get-started cards

24 new i18n keys in all 7 locales; 6 new a11y test files.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 34806c4e-0649-49aa-91d1-6ea3d5ae6564

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The PR adds localized accessible names, semantic buttons, dialog titles, alert dismissal controls, keyboard labels, viewer controls, and chat live-region announcements across the frontend. It also adds accessibility tests and translation keys in eight locale files.

Changes

Accessibility and localization

Layer / File(s) Summary
Dialog naming and action labels
src/frontend/src/CustomNodes/GenericNode/..., src/frontend/src/modals/modelProviderModal/..., src/frontend/src/pages/FlowPage/...
Dialog titles, search labels, output controls, hidden-output controls, and filter reset buttons receive accessible names and tests.
Toast dismissal controls
src/frontend/src/alerts/...
Error, notice, and success alerts use localized dismiss buttons, centralized dismissal handlers, propagation control, and accessibility tests.
Localized interactive controls
src/frontend/src/components/common/..., src/frontend/src/components/core/..., src/frontend/src/modals/templatesModal/..., src/frontend/src/locales/*
Shortcut keys, image/PDF viewers, parameter controls, password toggles, and focus behavior gain semantic controls and translated labels.
Chat live-region announcements
src/frontend/src/components/core/playgroundComponent/..., src/frontend/src/modals/IOModal/...
Chat containers expose log and busy states, while completed assistant responses are announced through status regions.

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

Sequence Diagram(s)

sequenceDiagram
  participant Messages
  participant ChatHistory
  participant ScreenReader
  Messages->>ChatHistory: detect build completion
  ChatHistory-->>Messages: provide final assistant response
  Messages->>ScreenReader: announce completed response
Loading

Suggested reviewers: ramgopalsrikar


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 3 warnings)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error Some new a11y changes have real tests, but ImageViewer/PdfViewer/chat/flow/output/template changes have none; coverage is incomplete. Add regression/a11y tests for the remaining touched components so each new accessible label/behavior change is covered.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Quality And Coverage ⚠️ Warning Added RTL a11y tests are solid, but several changed behaviors (chat live regions, image/pdf/flow/output labels, password toggle, template focus order) lack targeted coverage. Add targeted tests for the remaining changed components, especially live-region announcements, icon-only controls, password toggle, and template tab order.
Test File Naming And Structure ⚠️ Warning The new frontend tests are Jest/@testing-library unit tests under src/frontend/src/**/tests, not Playwright specs in src/frontend/tests as required. Rehome or relabel them as Playwright specs, or relax the check to allow Jest/RTL unit tests; keep descriptive names, setup/teardown, and edge-case coverage.
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Excessive Mock Usage Warning ✅ Passed Mocks are limited to external icons/UI wrappers and jsdom gaps; the new tests still exercise real component behavior without over-mocking core logic.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR’s main accessibility improvements across dialogs, controls, toast dismissal, and related UI areas.
✨ 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-2041

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 bug Something isn't working and removed bug Something isn't working labels Jul 28, 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 28, 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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/frontend/src/components/common/ImageViewer/index.tsx (1)

102-155: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add regression coverage for the new accessible names.

No changed test covers either newly named icon control in the supplied PR files. Add assertions that query these buttons by their localized accessible names.

  • src/frontend/src/components/common/ImageViewer/index.tsx#L102-L155: cover all five viewer toolbar button names.
  • src/frontend/src/components/core/appHeaderComponent/components/FlowMenu/index.tsx#L211-L211: cover the save-flow button name.

As per coding guidelines, “For new frontend implementations or bug fixes, ensure corresponding test files are included” and verify changed behavior.

🤖 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/components/common/ImageViewer/index.tsx` around lines 102 -
155, Add regression tests for the accessible names introduced in ImageViewer,
querying all five toolbar buttons by their localized names: zoom in, zoom out,
reset view, full screen, and download. In FlowMenu, add coverage for the
save-flow button’s localized accessible name; update the relevant test files for
both components.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/__tests__/slider-value-edit.a11y.test.tsx (1)

54-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise the real keyboard activation path.

fireEvent.keyDown followed by a manual fireEvent.click verifies only the click handler; the test passes even if Enter does nothing. Use the project’s user-level keyboard or browser helper to press Enter and assert edit mode without manually clicking.

As per coding guidelines, frontend tests should verify meaningful behavior rather than only smoke-testing it.

🤖 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/components/core/parameterRenderComponent/components/sliderComponent/__tests__/slider-value-edit.a11y.test.tsx`
around lines 54 - 64, Update the "should_enter_edit_mode_from_the_keyboard" test
to use the project’s user-level keyboard or browser interaction helper to press
Enter on the focused default_slider_display_value trigger, removing the manual
fireEvent.click call. Keep the assertion that slider_input appears so the test
verifies the real Enter activation path.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@src/frontend/src/alerts/error/index.tsx`:
- Around line 17-22: Cancel the pending auto-dismiss timer when alerts are
manually dismissed so removal is idempotent. Update handleDismiss in
src/frontend/src/alerts/error/index.tsx#L17-L22, route the new notice button
through cancellation-safe dismissal in
src/frontend/src/alerts/notice/index.tsx#L74-L84, and cancel the timer after
immediate removal in src/frontend/src/alerts/success/index.tsx#L14-L17. Extend
src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L60-L65, `#L74-L77`,
and `#L86-L90` to advance beyond 5.5 seconds and assert each error, success, and
notice toast is removed exactly once.
- Around line 15-16: Move toast dismissal visibility from local useState into
the alert Zustand store in src/frontend/src/alerts/error/index.tsx lines 15-16
and src/frontend/src/alerts/success/index.tsx lines 12-13; update ErrorAlert and
SuccessAlert to read and update the store’s visibility state while preserving
their existing dismissal behavior.

In
`@src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx`:
- Around line 246-259: Propagate the disabled state to both interactive buttons:
add the existing disabled value to the slider value-edit button in
sliderComponent/index.tsx (lines 246-259) and the password visibility button in
textAreaComponent/index.tsx (lines 239-259), ensuring keyboard activation is
also blocked when disabled.

In
`@src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx`:
- Around line 300-302: Force a DOM mutation for each completion announcement by
clearing or re-keying the status region around completedAnnouncement in
messages.tsx (lines 300-302) and chat-view.tsx (lines 257-259), so identical
consecutive messages are announced independently.
- Around line 199-211: Update the completion-announcement logic in messages.tsx
and the corresponding chat-view.tsx logic at lines 120-137 to track the current
assistant message identity rather than reading only the latest chatHistory
entry. Keep the completion pending when isBuilding falls before the new
assistant message is committed, then announce only that correlated message once
available and avoid announcing a prior-turn response.

In
`@src/frontend/src/modals/templatesModal/components/TemplateGetStartedCardComponent/index.tsx`:
- Around line 66-68: Add button semantics to the clickable template card in
TemplateGetStartedCardComponent by applying role="button" or replacing the div
with a native button, while preserving keyboard and click activation. Add a
regression test covering tab focus and activation with both Enter and Space.

---

Outside diff comments:
In `@src/frontend/src/components/common/ImageViewer/index.tsx`:
- Around line 102-155: Add regression tests for the accessible names introduced
in ImageViewer, querying all five toolbar buttons by their localized names: zoom
in, zoom out, reset view, full screen, and download. In FlowMenu, add coverage
for the save-flow button’s localized accessible name; update the relevant test
files for both components.

---

Nitpick comments:
In
`@src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/__tests__/slider-value-edit.a11y.test.tsx`:
- Around line 54-64: Update the "should_enter_edit_mode_from_the_keyboard" test
to use the project’s user-level keyboard or browser interaction helper to press
Enter on the focused default_slider_display_value trigger, removing the manual
fireEvent.click call. Keep the assertion that slider_input appears so the test
verifies the real Enter activation path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 82674382-5162-4fca-9c47-0e4f44242ba3

📥 Commits

Reviewing files that changed from the base of the PR and between e59f7e2 and e25eae7.

📒 Files selected for processing (32)
  • src/frontend/src/CustomNodes/GenericNode/components/ListSelectionComponent/__tests__/listSelection.a11y.test.tsx
  • src/frontend/src/CustomNodes/GenericNode/components/ListSelectionComponent/index.tsx
  • src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx
  • src/frontend/src/CustomNodes/GenericNode/index.tsx
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx
  • src/frontend/src/alerts/error/index.tsx
  • src/frontend/src/alerts/notice/index.tsx
  • src/frontend/src/alerts/success/index.tsx
  • src/frontend/src/components/common/ImageViewer/index.tsx
  • src/frontend/src/components/common/renderIconComponent/components/renderKey/__tests__/renderKey.a11y.test.tsx
  • src/frontend/src/components/common/renderIconComponent/components/renderKey/index.tsx
  • src/frontend/src/components/core/appHeaderComponent/components/FlowMenu/index.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/inputComponent/components/popover/__tests__/optionBadge.a11y.test.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/inputComponent/components/popover/index.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/__tests__/slider-value-edit.a11y.test.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx
  • src/frontend/src/components/core/pdfViewer/index.tsx
  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/messages.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
  • src/frontend/src/modals/IOModal/components/chatView/components/chat-view.tsx
  • src/frontend/src/modals/modelProviderModal/__tests__/modelProviderModal.a11y.test.tsx
  • src/frontend/src/modals/modelProviderModal/index.tsx
  • src/frontend/src/modals/templatesModal/components/TemplateGetStartedCardComponent/index.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/__tests__/sidebarFilterComponent.test.tsx
  • src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarFilterComponent.tsx

Comment on lines +15 to 16
const { t } = useTranslation();
const [show, setShow] = useState(true);

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate relevant frontend files =="
git ls-files 'src/frontend/**' | sed -n '1,200p'

echo
echo "== target files =="
for f in src/frontend/src/alerts/error/index.tsx src/frontend/src/alerts/success/index.tsx; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    cat -n "$f"
  else
    echo "missing $f"
  fi
done

echo
echo "== Zustand usages in frontend/src alerts and nearby store files =="
rg -n "create Zustand|createZustand|create\(|use.*Zustand|store|setShow|show|visibility|toast" src/frontend/src -S || true

echo
echo "== package deps =="
if [ -f "package.json" ]; then jq -r '.dependencies.zustand // .devDependencies.zustand // empty' package.json; fi

Repository: langflow-ai/langflow

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target files =="
for f in src/frontend/src/alerts/error/index.tsx src/frontend/src/alerts/success/index.tsx; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    cat -n "$f"
  else
    echo "missing $f"
  fi
done

echo
echo "== alert store files =="
fd -a 'alert.*\.(tsx|ts)$|store' src/frontend/src/stores 2>/dev/null | sed 's#^\./##' | rg 'alert|stores' | head -50 || true

echo
echo "== alertStore implementation =="
if [ -f "src/frontend/src/stores/alertStore.ts" ]; then
  echo "--- src/frontend/src/stores/alertStore.ts ($(wc -l < src/frontend/src/stores/alertStore.ts) lines) ---"
  cat -n src/frontend/src/stores/alertStore.ts
fi

echo
echo "== focused Zustand/alert usages without globbing file count =="
rg -n "create\(.*alert|alertStore|showAlert|hideAlert|show.*toast|toast.*show|setToast|toast" src/frontend/src/stores src/frontend/src/alerts src/frontend/src/components/src -S | head -120 || true

Repository: langflow-ai/langflow

Length of output: 15909


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== alert display area =="
cat -n src/frontend/src/alerts/displayArea/index.tsx

echo
echo "== alert store type =="
fd 'AlertStoreType|alert' src/frontend/src/types -x sh -c 'echo "--- $1 ---"; cat -n "$1"' sh {}

echo
echo "== imports/usages around alert components =="
rg -n "ErrorAlert|SuccessAlert|displayArea|useAlertStore|removeAlert|tempNotificationList|show=" src/frontend/src/alerts src/frontend/src/components -S | head -200 || true

echo
echo "== simple deterministic check: local show state exists in changed alert components =="
python3 - <<'PY'
from pathlib import Path
for f in ("src/frontend/src/alerts/error/index.tsx", "src/frontend/src/alerts/success/index.tsx"):
    text = Path(f).read_text()
    print(f, "useState(show):", ("const [show, setShow] = useState(true)" in text), "imports(useEffect, useState):", ("import { useEffect, useState }" in text))
PY

Repository: langflow-ai/langflow

Length of output: 2975


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== alert store type files =="
git ls-files 'src/frontend/src/types/**alert*' | while read -r f; do
  echo "--- $f --"
  cat -n "$f"
done

echo
echo "== alert component files =="
git ls-files 'src/frontend/src/alerts/**' | while read -r f; do
  echo "--- $f -- ($(wc -l < "$f") lines) ---"
  sed -n '1,120p' "$f" | cat -n
done

echo
echo "== notice component for comparison =="
cat -n src/frontend/src/alerts/notice/index.tsx

Repository: langflow-ai/langflow

Length of output: 40094


Move toast visibility into the alert Zustand store.

Both ErrorAlert and SuccessAlert still manage their own toast dismissal visibility with useState(true). Track dismissal state in the alert store so these components do not bypass the required frontend Zustand state-management pattern.

📍 Affects 2 files
  • src/frontend/src/alerts/error/index.tsx#L15-L16 (this comment)
  • src/frontend/src/alerts/success/index.tsx#L12-L13
🤖 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/alerts/error/index.tsx` around lines 15 - 16, Move toast
dismissal visibility from local useState into the alert Zustand store in
src/frontend/src/alerts/error/index.tsx lines 15-16 and
src/frontend/src/alerts/success/index.tsx lines 12-13; update ErrorAlert and
SuccessAlert to read and update the store’s visibility state while preserving
their existing dismissal behavior.

Source: Coding guidelines

Comment on lines +17 to +22
const handleDismiss = () => {
setShow(false);
setTimeout(() => {
removeAlert(id);
}, 500);
};

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Cancel pending auto-dismiss timers after manual dismissal.

Manual dismissal removes the toast, but its 5-second timer still fires and invokes removeAlert again around T+5500ms. Make dismissal idempotent and clear pending timers; advance these tests past 5.5 seconds before asserting exactly one removal.

  • src/frontend/src/alerts/error/index.tsx#L17-L22: cancel the auto-dismiss work when manually dismissing.
  • src/frontend/src/alerts/notice/index.tsx#L74-L84: route the new button through cancellation-safe dismissal.
  • src/frontend/src/alerts/success/index.tsx#L14-L17: cancel the auto-dismiss work after immediate removal.
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L60-L65: verify error-toast removal remains exactly once after T+5500ms.
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L74-L77: add the same assertion for success.
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L86-L90: add the same assertion for notice.

As per coding guidelines, frontend tests should verify meaningful behavior for new functionality rather than only smoke-testing it.

📍 Affects 4 files
  • src/frontend/src/alerts/error/index.tsx#L17-L22 (this comment)
  • src/frontend/src/alerts/notice/index.tsx#L74-L84
  • src/frontend/src/alerts/success/index.tsx#L14-L17
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L60-L65
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L74-L77
  • src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L86-L90
🤖 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/alerts/error/index.tsx` around lines 17 - 22, Cancel the
pending auto-dismiss timer when alerts are manually dismissed so removal is
idempotent. Update handleDismiss in
src/frontend/src/alerts/error/index.tsx#L17-L22, route the new notice button
through cancellation-safe dismissal in
src/frontend/src/alerts/notice/index.tsx#L74-L84, and cancel the timer after
immediate removal in src/frontend/src/alerts/success/index.tsx#L14-L17. Extend
src/frontend/src/alerts/__tests__/toast-dismiss.a11y.test.tsx#L60-L65, `#L74-L77`,
and `#L86-L90` to advance beyond 5.5 seconds and assert each error, success, and
notice toast is removed exactly once.

Source: Coding guidelines

Comment on lines +246 to +259
<button
type="button"
onClick={() => {
setIsEditing(true);
setInputValue(valueAsNumber.toFixed(2));
}}
aria-label={t("paramRender.editSliderValue", {
value: valueAsNumber.toFixed(2),
})}
data-testid={`default_slider_display_value${editNode ? "_advanced" : ""}`}
className="relative bottom-[1px] font-mono text-sm hover:cursor-text"
>
{valueAsNumber.toFixed(2)}
</span>
</button>

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Propagate disabled state to both newly interactive controls.

Both buttons remain independently interactive when their surrounding component is disabled:

  • src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx#L246-L259: add disabled={disabled} to the slider value-edit button.
  • src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx#L239-L259: add disabled={disabled} to the password visibility button; pointer-events styling does not block keyboard activation.
📍 Affects 2 files
  • src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx#L246-L259 (this comment)
  • src/frontend/src/components/core/parameterRenderComponent/components/textAreaComponent/index.tsx#L239-L259
🤖 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/components/core/parameterRenderComponent/components/sliderComponent/index.tsx`
around lines 246 - 259, Propagate the disabled state to both interactive
buttons: add the existing disabled value to the slider value-edit button in
sliderComponent/index.tsx (lines 246-259) and the password visibility button in
textAreaComponent/index.tsx (lines 239-259), ensuring keyboard activation is
also blocked when disabled.

Comment on lines +199 to +211
const [completedAnnouncement, setCompletedAnnouncement] = useState("");
const wasBuildingRef = useRef(isBuilding);
useEffect(() => {
if (wasBuildingRef.current && !isBuilding) {
const lastMessage = chatHistory[chatHistory.length - 1];
if (lastMessage && !lastMessage.isSend) {
setCompletedAnnouncement(
typeof lastMessage.message === "string" ? lastMessage.message : "",
);
}
}
wasBuildingRef.current = isBuilding;
}, [isBuilding, chatHistory]);

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files of interest =="
git ls-files | rg '(^|/)chat-messages/messages\.tsx$|(^|/)chat-view\.tsx$' || true

echo
echo "== first file outline and relevant snippets =="
for f in $(git ls-files | rg '(^|/)chat-messages/messages\.tsx$|(^|/)chat-view\.tsx$'); do
  echo "--- $f ---"
  wc -l "$f"
  sed -n '160,235p' "$f"
  echo
done

echo "== searches for chatHistory/isBuilding/message lifecycle =="
rg -n "chatHistory|isBuilding|setCompletedAnnouncement|completedAnnouncement|completion|assistant|isSend" src/frontend/src/components/core/playgroundComponent/chat-view src/frontend/src/modals/IOModal/components/chatView/components 2>/dev/null | head -200

Repository: langflow-ai/langflow

Length of output: 25986


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== IOModal chat-view relevant lifecycle =="
sed -n '40,270p' src/frontend/src/modals/IOModal/components/chatView/components/chat-view.tsx

echo
echo "== useChatHistory relevant lifecycle =="
sed -n '1,270p' src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/hooks/use-chat-history.ts

echo
echo "== stream/duration hooks relevant =="
for f in $(git ls-files | rg 'src/frontend/src.*use-streaming-message\.ts$|src/frontend/src/.*/chat-messages/hooks/use-message-duration\.ts$|src/frontend/src/.*/chat-messages/hooks/use-message-duration\.ts$'); do
  echo "--- $f ---"
  wc -l "$f"
  sed -n '1,120p' "$f"
done

echo
echo "== flow store isBuilding definitions =="
rg -n "setIsBuilding|isBuilding|stopBuilding|setStartTime|setComplete" src/frontend/src -g '*.ts' -g '*.tsx' | head -250

Repository: langflow-ai/langflow

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== sendMessage/build flow call sites =="
rg -n "function sendMessage|const sendMessage|async .*sendMessage|buildFlow|setIsBuilding\\(true\\)|stopBuilding\\(|setIsBuilding\\(false\\)" src/frontend/src/modals/IOModal src/frontend/src/components/core/playgroundComponent -g '*.ts' -g '*.tsx' | head -220

echo
echo "== focused IOModal sendMessage section =="
sed -n '170,235p' src/frontend/src/modals/IOModal/playground-modal.tsx

echo
echo "== focused flow store build helpers =="
sed -n '340,390p' src/frontend/src/stores/flowStore.ts
rg -n "function buildFlow|const buildFlow|setIsBuilding\\(true\\)|stopBuilding\\(" src/frontend/src/stores/flowStore.ts src/frontend/src/hooks/use-webhook-events.ts src/frontend/src/components/core/chatComponents/HumanInputCard.tsx -A8 -B8 | head -220

Repository: langflow-ai/langflow

Length of output: 10111


Correlate completion announcements with newly committed assistant messages. The falling-edge isBuilding check still reads chatHistory?.[chatHistory.length - 1]; if that message belongs to a previous turn or completes via backend cache/update after the build flag clears, the status region will announce the wrong response or miss the new one. Track the assistant message identity and keep the pending completion attached until the current message has been announced.

📍 Affects 2 files
  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx#L199-L211 (this comment)
  • src/frontend/src/modals/IOModal/components/chatView/components/chat-view.tsx#L120-L137
🤖 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/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx`
around lines 199 - 211, Update the completion-announcement logic in messages.tsx
and the corresponding chat-view.tsx logic at lines 120-137 to track the current
assistant message identity rather than reading only the latest chatHistory
entry. Keep the completion pending when isBuilding falls before the new
assistant message is committed, then announce only that correlated message once
available and avoid announcing a prior-turn response.

Comment on lines +300 to +302
<div role="status" aria-live="polite" className="sr-only">
{completedAnnouncement}
</div>

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Force a DOM mutation for every completion announcement. Setting the same message string twice can be optimized away, preventing the second response from being announced.

  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx#L300-L302: clear or re-key the status region per completion.
  • src/frontend/src/modals/IOModal/components/chatView/components/chat-view.tsx#L257-L259: apply the same repeated-text handling.
📍 Affects 2 files
  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx#L300-L302 (this comment)
  • src/frontend/src/modals/IOModal/components/chatView/components/chat-view.tsx#L257-L259
🤖 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/components/core/playgroundComponent/chat-view/chat-messages/messages.tsx`
around lines 300 - 302, Force a DOM mutation for each completion announcement by
clearing or re-keying the status region around completedAnnouncement in
messages.tsx (lines 300-302) and chat-view.tsx (lines 257-259), so identical
consecutive messages are announced independently.

Comment on lines +66 to 68
tabIndex={0}
onKeyDown={handleKeyDown}
onClick={handleClick}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Expose the template card as an actionable control.

This focusable, click-driven div should use role="button" or a native button so assistive technologies announce its purpose. Add a regression test covering tab focus and Enter/Space activation.

As per coding guidelines, frontend bug fixes must include tests that verify the changed behavior.

🤖 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/modals/templatesModal/components/TemplateGetStartedCardComponent/index.tsx`
around lines 66 - 68, Add button semantics to the clickable template card in
TemplateGetStartedCardComponent by applying role="button" or replacing the div
with a native button, while preserving keyboard and click activation. Add a
regression test covering tab focus and activation with both Enter and Space.

Source: Coding guidelines

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 49%
49.53% (71755/144856) 70.35% (10048/14281) 46.77% (1645/3517)

Unit Test Results

Tests Skipped Failures Errors Time
5534 0 💤 0 ❌ 0 🔥 18m 5s ⏱️

viktoravelino and others added 2 commits July 29, 2026 11:06
The chat status live region rendered the full assistant message into an
sr-only node, duplicating every response in the DOM. Playwright text
locators then matched twice (fileUploadComponent strict-mode violation)
or matched content that should have been gone (bulk-delete-sessions).

Announce a short "Response complete" cue instead, keyed so repeats still
re-announce. Also clears the biome errors the PR's changed-file set
surfaced (unused imports, untyped test mocks) and refreshes the
detect-secrets baseline for the new i18n password labels.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 29, 2026
@viktoravelino viktoravelino self-assigned this Jul 29, 2026
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 46.81529% with 167 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.51%. Comparing base (281392d) to head (764a57f).
⚠️ Report is 1 commits behind head on release-1.12.0.

Files with missing lines Patch % Lines
...renderIconComponent/components/renderKey/index.tsx 52.17% 22 Missing ⚠️
src/frontend/src/CustomNodes/GenericNode/index.tsx 5.00% 19 Missing ⚠️
...Modal/components/chatView/components/chat-view.tsx 0.00% 17 Missing ⚠️
...oundComponent/chat-view/chat-messages/messages.tsx 15.78% 16 Missing ⚠️
...c/frontend/src/components/core/pdfViewer/index.tsx 0.00% 15 Missing ⚠️
src/frontend/src/alerts/success/index.tsx 27.77% 13 Missing ⚠️
src/frontend/src/alerts/error/index.tsx 40.00% 12 Missing ⚠️
src/frontend/src/alerts/notice/index.tsx 15.38% 11 Missing ⚠️
...tend/src/shared/hooks/use-response-complete-cue.ts 57.69% 11 Missing ⚠️
...c/frontend/src/modals/modelProviderModal/index.tsx 12.50% 7 Missing ⚠️
... and 6 more
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.12.0   #14300      +/-   ##
==================================================
+ Coverage           61.63%   62.51%   +0.88%     
==================================================
  Files                2416     2366      -50     
  Lines              242162   239341    -2821     
  Branches            36186    33716    -2470     
==================================================
+ Hits               149249   149623     +374     
+ Misses              90995    87898    -3097     
+ Partials             1918     1820      -98     
Flag Coverage Δ
frontend 61.33% <46.81%> (+1.46%) ⬆️

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

Files with missing lines Coverage Δ
...e/appHeaderComponent/components/FlowMenu/index.tsx 94.29% <100.00%> (+0.02%) ⬆️
...s/core/flowBuilderWelcome/flow-builder-welcome.tsx 97.56% <100.00%> (+0.04%) ⬆️
...onents/inputComponent/components/popover/index.tsx 92.37% <100.00%> (-1.21%) ⬇️
...nderComponent/components/sliderComponent/index.tsx 78.22% <100.00%> (+0.23%) ⬆️
...barComponent/components/sidebarFilterComponent.tsx 94.44% <100.00%> (+0.07%) ⬆️
...src/shared/components/response-complete-status.tsx 90.00% <100.00%> (ø)
...Nodes/GenericNode/components/outputModal/index.tsx 22.36% <0.00%> (-17.17%) ⬇️
...rc/components/common/renderIconComponent/index.tsx 60.78% <75.00%> (+18.28%) ⬆️
...mponents/TemplateGetStartedCardComponent/index.tsx 37.95% <0.00%> (-0.57%) ⬇️
...ontend/src/components/common/ImageViewer/index.tsx 0.00% <0.00%> (ø)
... and 12 more

... and 664 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.

…d focus order

Fills coverage gaps from the a11y quick-wins PR: chat log region and
response-complete announcement, ImageViewer/PdfViewer toolbar names,
password show/hide toggle, and template card tabindex.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 29, 2026

@Cristhianzl Cristhianzl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Jul 29, 2026
… response cue

- keep password toggle mounted while input is focused (visually hidden)
  so forward Tab reaches it
- add role=button and aria-label to template get-started card
- extract duplicated response-complete cue into shared hook + status
  component, used by both chat views
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 29, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Aug 5, 2026
QA round on PR #14300: sr-only text and keyed live-region children work
in Chromium but not WebKit.

- shortcuts: WebKit drops visually-clipped text from grid cell values,
  so name the shortcut wrapper explicitly (role=img + aria-label) and
  hide the icon visuals; covers settings grid and canvas tooltips
- chat: role=log list gets aria-live=off - React remounts earlier
  messages on send, which a live region re-announces as additions
  (full-history re-read in VoiceOver); completion cue now mutates one
  persistent text node instead of re-keying a child Safari drops;
  stabilize IOModal message keys to chat.id
- welcome: ignore Escape already consumed (defaultPrevented) by a Radix
  dialog so closing the templates modal no longer also closes the
  welcome; focus returns to the Browse more trigger

Refs LE-2041
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Aug 5, 2026
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Aug 5, 2026
QA VoiceOver pass: 'Response complete' alone forces the user to hunt
for the answer in a muted transcript. The status region is the reply's
only path to the screen reader, so it must carry the reply text —
matching the acceptance criterion (announce the completed reply once)
and standard practice for streamed AI chat.

- useResponseCompleteCue also captures the settled reply's text
- status region announces the markdown-stripped text; falls back to
  'Response complete' for non-text replies
- syntax stripped so VO does not read 'asterisk asterisk bold'

Refs LE-2041
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Aug 5, 2026
@viktoravelino
viktoravelino enabled auto-merge August 6, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y 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