Skip to content

fix: add accessible fallback dialog title for publish modal#12641

Open
wwenrr wants to merge 4 commits intoSignificant-Gravitas:devfrom
wwenrr:fix/issue-11072
Open

fix: add accessible fallback dialog title for publish modal#12641
wwenrr wants to merge 4 commits intoSignificant-Gravitas:devfrom
wwenrr:fix/issue-11072

Conversation

@wwenrr
Copy link
Copy Markdown

@wwenrr wwenrr commented Apr 1, 2026

Summary

Fixes the accessibility issue reported in #11072 where a dialog could render without a valid accessible title.

When Dialog is used without a title prop (e.g. PublishAgentModal), the current implementation rendered <RXDialog.Title>{title}</RXDialog.Title> with title undefined. This fails Radix a11y requirements and triggers the runtime warning about missing DialogTitle.

This change ensures DialogWrap always provides a non-empty fallback title ("Dialog") for screen readers while keeping the visible UI unchanged when no title is provided.

Changes

  • In DialogWrap.tsx:
    • Added accessibleTitle = title ?? "Dialog"
    • Added hasVisibleTitle = Boolean(title)
    • Always render <RXDialog.Title> with either visible or sr-only style
    • Refactored close button into a reusable closeButton constant (no behavioral change)

Verification

  • prettier --check src/components/molecules/Dialog/components/DialogWrap.tsx
  • eslint src/components/molecules/Dialog/components/DialogWrap.tsx
  • Manual code-path verification:
    • PublishAgentModal uses <Dialog.Content> without passing title
    • After this fix, it still has a valid hidden DialogTitle, removing the a11y warning condition

Fixes #11072

majdyz and others added 2 commits March 27, 2026 13:11
…ificant-Gravitas#12561)

## Summary
Upgrade the frontend **Docker image** from **Node.js v21** (EOL since
June 2024) to **Node.js v22 LTS** (supported through April 2027).

> **Scope:** This only affects the **Dockerfile** used for local
development (`docker compose`) and CI. It does **not** affect Vercel
(which manages its own Node.js runtime) or Kubernetes (the frontend Helm
chart was removed in Dec 2025 — the frontend is deployed exclusively via
Vercel).

## Why
- Node v21.7.3 has a **known TransformStream race condition bug**
causing `TypeError: controller[kState].transformAlgorithm is not a
function` — this is
[BUILDER-3KF](https://significant-gravitas.sentry.io/issues/BUILDER-3KF)
with **567,000+ Sentry events**
- The error is entirely in Node.js internals
(`node:internal/webstreams/transformstream`), zero first-party code
- Node 21 is **not an LTS release** and has been EOL since June 2024
- `package.json` already declares `"engines": { "node": "22.x" }` — the
Dockerfile was inconsistent
- Node 22.x LTS (v22.22.1) fixes the TransformStream bug
- Next.js 15.4.x requires Node 18.18+, so Node 22 is fully compatible

## Changes
- `autogpt_platform/frontend/Dockerfile`: `node:21-alpine` →
`node:22.22-alpine3.23` (both `base` and `prod` stages)

## Test plan
- [ ] Verify frontend Docker image builds successfully via `docker
compose`
- [ ] Verify frontend starts and serves pages correctly in local Docker
environment
- [ ] Monitor Sentry for BUILDER-3KF — should drop to zero for
Docker-based runs
@wwenrr wwenrr requested a review from a team as a code owner April 1, 2026 15:50
@wwenrr wwenrr requested review from Pwuts and kcze and removed request for a team April 1, 2026 15:50
@github-project-automation github-project-automation bot moved this to 🆕 Needs initial review in AutoGPT development kanban Apr 1, 2026
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 1, 2026

CLA assistant check
All committers have signed the CLA.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

This PR targets the master branch but does not come from dev or a hotfix/* branch.

Automatically setting the base branch to dev.

@github-actions github-actions bot added the platform/frontend AutoGPT Platform - Front end label Apr 1, 2026
@github-actions github-actions bot changed the base branch from master to dev April 1, 2026 15:50
@github-actions github-actions bot added the size/m label Apr 1, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac63c8bb-96fb-447b-9640-1660a0e87f25

📥 Commits

Reviewing files that changed from the base of the PR and between c566111 and c11d788.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
✅ Files skipped from review due to trivial changes (1)
  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: check API types
  • GitHub Check: integration_test
  • GitHub Check: Seer Code Review
  • GitHub Check: end-to-end tests
  • GitHub Check: Check PR Status
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (typescript)

Walkthrough

Refactors DialogWrap header rendering: always supplies an accessible title (accessibleTitle) for screen readers, separates visible-title logic (hasVisibleTitle) from accessibility, consolidates title and close button JSX into reusable constants, and updates header padding to depend on hasVisibleTitle.

Changes

Cohort / File(s) Summary
Dialog Accessibility Refactor
autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
Always render a RXDialog.Title using accessibleTitle (defaults to "Dialog"), track visibility with hasVisibleTitle, consolidate title markup into titleNode, consolidate close button into closeButton, and update header bottom padding to use hasVisibleTitle.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I tuck a title soft where silence might roam,
"Dialog" for ears that read what sight can't comb.
A button curled close, a header made bright—
Small hops for code, big comfort at night. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding an accessible fallback dialog title to fix the accessibility issue in the publish modal.
Description check ✅ Passed The description clearly explains the accessibility problem, the solution implemented, and provides verification steps; it is directly related to the changeset.
Linked Issues check ✅ Passed The PR successfully addresses the core requirement from #11072 by ensuring DialogWrap always renders a valid DialogTitle with a fallback for screen readers.
Out of Scope Changes check ✅ Passed All changes are scoped to DialogWrap.tsx and directly address the accessibility issue; the close button refactoring is a minor improvement with no behavioral change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx`:
- Around line 42-43: The accessibleTitle currently uses nullish coalescing which
leaves an empty string as-is; change the assignment in DialogWrap.tsx to use
logical OR so empty string falls back to "Dialog" (replace accessibleTitle =
title ?? "Dialog" with accessibleTitle = title || "Dialog"); keep
hasVisibleTitle as a truthy check (hasVisibleTitle = Boolean(title) or !!title)
so it still correctly reflects whether a visible title was provided.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71c0a733-9974-471a-8329-8ee6957a3c59

📥 Commits

Reviewing files that changed from the base of the PR and between 1750c83 and c566111.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: check API types
  • GitHub Check: lint
  • GitHub Check: integration_test
  • GitHub Check: Seer Code Review
  • GitHub Check: end-to-end tests
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Analyze (python)
  • GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (12)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/
'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development

autogpt_platform/frontend/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g. graphID, useBackendAPI
Use function declarations (not arrow functions) for components and handlers
No dark: Tailwind classes — the design system handles dark mode
No any types unless the value genuinely can be anything
No linter suppressors (// @ts-ignore``, // eslint-disable) — fix the actual issue instead
Keep files under ~200 lines; extract sub-components or hooks into their own files when a file grows beyond this threshold
Keep render functions and hooks under ~50 lines; extract named helpers or sub-components when they grow longer
Use generated API hooks from `@/app/api/generated/endpoints/` following the pattern `use{Method}{Version}{OperationName}`; regenerate with `pnpm generate:api`
Use Tailwind CSS only for styling; use design tokens and Phosphor Icons only (no other icon libraries)
Do not use `useCallback` or `useMemo` unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/src/components/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Structure React components as: ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts (exception: small 3-4 line components can be inline; render-only components can be direct files)

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code using pnpm format
Never use components from src/components/__legacy__/*

Refer to @frontend/CLAUDE.md for frontend-specific commands, architecture, and development patterns

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts and use design system components from src/components/ (atoms, molecules, organisms)
Use generated API hooks from @/app/api/__generated__/endpoints/ with pattern use{Method}{Version}{OperationName} and regenerate with pnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local /components folder
Avoid large hooks, abstract logic into helpers.ts files when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not use useCallback or useMemo unless asked to optimize a given function

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/src/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Component props should be interface Props { ... } (not exported) unless the interface needs to be used outside the component

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never type with any, if no types available use unknown

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)

autogpt_platform/frontend/**/*.tsx: Use Next.js <Link> for internal navigation — never raw <a> tags
Put sub-components in local components/ folder; component props should be type Props = { ... } (not exported) unless it needs to be used outside the component
Use design system components from src/components/ (atoms, molecules, organisms); never use src/components/__legacy__/*

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)

Structure components as ComponentName/ComponentName.tsx + useComponentName.ts + helpers.ts

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
autogpt_platform/frontend/src/**

📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)

Avoid index and barrel files

Files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
🧠 Learnings (2)
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/frontend/**/*.{tsx,ts} : Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)

Applied to files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
📚 Learning: 2026-03-24T02:05:04.672Z
Learnt from: majdyz
Repo: Significant-Gravitas/AutoGPT PR: 12526
File: autogpt_platform/frontend/src/app/(platform)/copilot/CopilotPage.tsx:0-0
Timestamp: 2026-03-24T02:05:04.672Z
Learning: When gating React component logic on a React Query result (e.g., hooks like `useQuery` / `useGetV2GetCopilotUsage`), prefer destructuring and checking `isSuccess` (or aliasing it to a meaningful boolean like `isSuccess: hasUsage`) instead of relying on `!isLoading`. Reason: `isLoading` can be `false` in error/idle states where `data` may still be `undefined`, while `isSuccess` indicates the query completed successfully and `data` is populated.

Applied to files:

  • autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx
🔇 Additional comments (3)
autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx (3)

45-56: LGTM!

Good refactor extracting the close button into a reusable constant. The Button component from the design system and Phosphor Icon are correctly used, and the aria-label="Close" maintains accessibility.


58-64: Good accessibility pattern using sr-only fallback.

The approach of always rendering RXDialog.Title with either visible or sr-only styling correctly addresses the Radix accessibility warning while preserving the UI. This ensures screen readers always have a title to announce.

Note: This implementation depends on the accessibleTitle fix suggested above to work correctly.


127-135: LGTM!

The render integration is clean. Using hasVisibleTitle for conditional padding and the extracted titleNode/closeButton constants improves readability. The close button conditional isForceOpen && !handleClose correctly preserves the original behavior.

@wwenrr
Copy link
Copy Markdown
Author

wwenrr commented Apr 1, 2026

Addressed ✅

Updated DialogWrap fallback title assignment from nullish coalescing to logical OR:

  • accessibleTitle = title || "Dialog"

This now also handles empty-string titles by falling back to "Dialog", while keeping hasVisibleTitle = Boolean(title) unchanged as suggested.

Re-verified with:

  • prettier --check src/components/molecules/Dialog/components/DialogWrap.tsx
  • eslint src/components/molecules/Dialog/components/DialogWrap.tsx

@wwenrr
Copy link
Copy Markdown
Author

wwenrr commented Apr 1, 2026

Synced this branch with via Update branch.\n\nAs expected, the Dockerfile delta is now gone from this PR, and only the DialogWrap accessibility fix remains in scope.

@wwenrr
Copy link
Copy Markdown
Author

wwenrr commented Apr 1, 2026

Updated the PR branch with latest dev branch. Dockerfile changes are no longer part of this PR; it now contains only the DialogWrap accessibility fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform/frontend AutoGPT Platform - Front end size/m

Projects

Status: 🆕 Needs initial review
Status: No status

Development

Successfully merging this pull request may close these issues.

DialogContent requires a DialogTitle for the component to be accessible for screen reader users in PublishAgentModal.tsx

3 participants