[cueweb/docs/images] Add CueGUI-style navigation framework, safety mode, attributes panel, and comprehensive UI/docs refresh#2353
Conversation
- New cueweb/components/ui/app-header.tsx: theme-aware OpenCue logo, two dropdowns mirroring CueGUI (Cuetopia -> Monitor Jobs; CueCommander -> Allocations, Limits, Monitor Cue, Monitor Hosts, Redirect, Services, Shows, Stuck Frame, Subscription Graphs, Subscriptions), ThemeToggle, and a Sign out button that always routes to /login. Hidden on /login.
- /login already handles both auth modes: empty NEXT_PUBLIC_AUTH_PROVIDER shows the "CueWeb Home" button; configured providers show their sign-in buttons.
- Unimplemented CueCommander routes 404 gracefully until their Category D tasks land.
- New cueweb/app/providers/session-provider.tsx wraps NextAuth's SessionProvider so useSession() works in the header.
- cueweb/app/layout.tsx mounts SessionProvider + AppHeader between ThemeProvider and {children}.
- cueweb/app/jobs/data-table.tsx: remove duplicate inline logo, theme toggle, and signout now that the global header owns them.
- Dark-mode contrast: elevated zinc-900 surface, stronger border, translucent foreground-based nav pills that read on either theme.
- cueweb/components/ui/cuewebicon.tsx: render the OpenCue icon followed by the "CueWeb" text. Drives the login, LDAP login, frame log, and comments pages.
- Favicon swapped to OpenCue logo (app/favicon.ico -> app/icon.png).
- Delete the now-unreferenced app/iconlight.png and app/icondark.png.
- Add the OpenCue brand kit to images/ (icon, horizontal, stacked x PNG + SVG x black + white) and the header logos to cueweb/public/.
- Replace hard-coded `white` / `lightgreen` and MUI ListItem with Tailwind semantic tokens: `bg-popover text-popover-foreground border-border` (matches shadcn DropdownMenuContent). - Already-monitored rows use `bg-green-500/20` (and `dark:bg-green-500/15`) for a subtle tint that reads on both themes. - Swap MUI ListItem for plain `<div role="button">` with Enter/Space activation; inter-row borders via `border-b border-border`. - Drop MUI imports (Box, Divider, ListItem, ListItemText) and truncate long job names.
- Update cueweb/README.md and all 8 docs under docs/_docs/ to describe the persistent header (theme-aware OpenCue logo + CueWeb wordmark, grouped Cuetopia / CueCommander dropdowns mirroring the CueGUI Views/Plugins menu, theme toggle, always-visible Sign out).
- README: switch the masthead image to a <picture> element pointing at public/opencue-icon-{black,white}.png and add a note above the existing screenshots that they predate the header.
- user-guide / tutorial / quick-start: replace the generic "Header" bullet with a full breakdown of the header's contents and behavior.
- reference: add a "Global Application Header" section listing every Cuetopia / CueCommander route and the /login behavior under each NEXT_PUBLIC_AUTH_PROVIDER configuration.
- developer-guide: expand the project structure tree to include app/icon.png, app/providers/session-provider.tsx, the new components/ui/app-header.tsx, and public/opencue-icon-{black,white}.png; add AppHeader / AppSessionProvider / CueWebIcon to the Core Components list.
- other-guides: insert the persistent-header bullet at the top of the numbered feature list (renumbered 2–16).
- concepts/cueweb-rest-gateway, getting-started/deploying-cueweb: smaller touch-ups (added LDAP, header note in Key Features, comment block above NEXT_PUBLIC_AUTH_PROVIDER in the prod .env sample).
- Refresh interface_screenshots/ (light + dark variants) so the README gallery matches the current UI.
…uebot Facility / Other / Help) - New cueweb/components/ui/app-sidebar.tsx: persistent left sidebar mounted in app/layout.tsx with grouped accordions (File, Cuebot Facility, Cuetopia, CueCommander, Other, Help). Collapsible to icons-only; expanded/collapsed state and each group's open/closed state persist via cueweb.sidebar.collapsed and cueweb.sidebar.openGroups. Hidden on /login. - AppHeader: shared nav now sourced from new cueweb/app/utils/menus.ts. Added File -> Disable Job Interaction, Cuebot Facility (local/dev/cloud/ external), Other -> Attributes, and Help dropdowns. The Help search box searches across every menu command via the new useMenuRegistry hook (matches render as "Group > Label"). Sign in / Sign out unchanged. - New cueweb/app/utils/use_disable_job_interaction.ts: persisted safety flag with CustomEvent + storage-event sync. JobActionButton in the jobs data table and every destructive entry in components/ui/context_menus/action-context-menu.tsx (job Pause/Retry Dead Frames/Eat Dead Frames/Kill; layer Kill/Eat/Retry/Retry Dead Frames; frame Retry/Eat/Kill) auto-disable when the flag is on. New cueweb/components/ui/read-only-banner.tsx renders an amber strip under the header with a "Re-enable" button. - New cueweb/app/utils/use_cuebot_facility.ts: selected facility persisted to cueweb.facility.selected, list from NEXT_PUBLIC_CUEBOT_FACILITIES (default local/dev/cloud/external). - New cueweb/app/utils/use_attributes_panel.ts + cueweb/components/ui/attributes-panel.tsx: docked Attributes drawer with selectable position (right/bottom/left/top), filter input, and a collapsible key/value tree for the currently-selected entity. New cueweb/app/utils/use_attribute_selection.ts holds the transient selection; clicking a row in app/jobs/data-table.tsx populates it. - New cueweb/app/utils/help_menu.ts: Online User Guide / Make a Suggestion / Report a Bug URLs matching CueGUI's cuegui.yaml defaults; overridable via NEXT_PUBLIC_DOCS_URL / SUGGESTIONS_URL / BUGS_URL. - New cueweb/app/utils/use_menu_registry.ts: aggregates every menu command (File / Cuebot Facility / Cuetopia / CueCommander / Other / Help) into a flat, filterable list for the Help search box. - Refresh cueweb/README.md and docs/_docs/reference/cueweb.md to describe the new menu bar, sidebar, panel and safety flag.
…Attributes panel
- cueweb/README.md and docs/_docs/quick-starts/quick-start-cueweb.md, tutorials/cueweb-tutorial.md, user-guides/cueweb-user-guide.md, other-guides/cueweb.md, concepts/cueweb-rest-gateway.md: describe the full six-menu header (File, Cuebot Facility, Cuetopia, CueCommander, Other, Help with global search), the collapsible left sidebar (same six groups, accordion behavior, persistent collapsed state), the Disable Job Interaction safety mode with read-only banner, and the
docked Attributes panel (right/bottom/left/top dock positions, live filter input).
- docs/_docs/other-guides/cueweb.md: feature list renumbered 1-19 with the four new items at the top.
- docs/_docs/reference/cueweb.md: extended "Global Application Header" with every menu and its items, plus new "Left Sidebar", "Disable Job Interaction (safety mode)", and "Attributes Panel" sections that cite source files, hooks, localStorage keys, and CustomEvent names.
- docs/_docs/developer-guide/cueweb-development.md: expanded the project-structure tree with the new app/utils/* hooks and components/ui/{app-sidebar,attributes-panel,read-only-banner}.tsx; added AppSidebar, AttributesPanel, ReadOnlyBanner to Core Components; added an "Application state hooks" subsection documenting useDisableJobInteraction, useCuebotFacility, useAttributesPanel, useAttributeSelection, useMenuRegistry and the shared menus.ts / help_menu.ts modules.
- docs/_docs/getting-started/deploying-cueweb.md: documented the new build-time env vars (NEXT_PUBLIC_CUEBOT_FACILITIES, NEXT_PUBLIC_DOCS_URL, NEXT_PUBLIC_SUGGESTIONS_URL, NEXT_PUBLIC_BUGS_URL) with the CueGUI canonical defaults.
📝 WalkthroughWalkthroughThis PR modernizes CueWeb's user interface by introducing a persistent global layout layer with state synchronization across tabs. It adds a top-level header with navigation menus, a collapsible sidebar, an attributes detail panel, and a read-only safety mode for destructive job actions. Individual pages are simplified by removing duplicate header chrome. ChangesCueWeb UI Modernization with Persistent State Management
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
cueweb/components/ui/search-dropdown.tsx (2)
110-110: ⚡ Quick winUse a stable key instead of index.
Using
indexas the key in a virtualized list that changes (e.g., when filtered) is an anti-pattern. React may reuse components incorrectly during reconciliation. Use a stable identifier likejob.namefor more predictable rendering.🔑 Proposed fix
<div - key={index} + key={job.name} role="button" tabIndex={0}🤖 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 `@cueweb/components/ui/search-dropdown.tsx` at line 110, Replace the unstable key={index} used in the virtualized list render inside the SearchDropdown component with a stable identifier from the item (e.g., use job.name or another unique field on the job object). Update the element that currently sets key={index} to instead set key={job.name} (or key={job.id} if available) so React can reconcile filtered/changed lists correctly; ensure the referenced symbol is the same item variable used in the map/rowRenderer where key is assigned.
104-106: ⚡ Quick winOptimize the added-job lookup with a memoized Set.
The
tableData.some()call runs a linear scan for every rendered item. With a largetableData, this can cause performance issues even in a virtualized list. Create aSetof added job names outside the item renderer for O(1) lookups.⚡ Proposed optimization
Add this
useMemohook after line 46 (afterlistRefdeclaration):const listRef = React.useRef<FixedSizeList | null>(null); + +const addedJobNames = React.useMemo( + () => new Set(tableData.map((job) => job.name)), + [tableData], +);Then replace the
isJobAddedcalculation:- const isJobAdded = tableData.some( - (existingJob: Job) => existingJob.name === job.name, - ); + const isJobAdded = addedJobNames.has(job.name);🤖 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 `@cueweb/components/ui/search-dropdown.tsx` around lines 104 - 106, Create a memoized Set of added job names to avoid repeated linear scans: use React's useMemo to build a Set from tableData (e.g., new Set(tableData.map(j => j.name))) declared near listRef (after its declaration) and then replace the per-item some() call that computes isJobAdded with a constant-time lookup using set.has(job.name). Update any references to the old variable name (isJobAdded) to use the new lookup and ensure the memo depends on tableData so it rebuilds when the list changes.
🤖 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 `@cueweb/components/ui/app-header.tsx`:
- Around line 153-158: The input's onKeyDown currently calls e.stopPropagation()
for every key, which prevents dropdown keyboard handling; update the onKeyDown
handler (the input with value={query} and setQuery) to conditionally stop
propagation only for keys that should not affect the parent menu (e.g., regular
character keys and Enter) and allow navigation/escape keys (Escape, ArrowUp,
ArrowDown, ArrowLeft, ArrowRight, Tab if desired) to bubble so the menu's
keyboard controls continue to work.
In `@cueweb/components/ui/app-sidebar.tsx`:
- Around line 364-376: The facility list uses custom role="radiogroup" and
role="radio" on buttons but lacks full radio keyboard semantics; update the
facilities.map rendering (the button that calls setFacility) to implement
complete radio behavior: either render native <input type="radio"> elements for
each facility bound to the facility state (or wrap a visually styled label
around such an input), or add the missing keyboard handlers on the button
(manage tabIndex, onKeyDown to handle
ArrowLeft/ArrowRight/ArrowUp/ArrowDown/Home/End to move focus and call
setFacility, ensure aria-checked is provided and focus is placed correctly).
Make these changes in the component that contains facilities.map and setFacility
so keyboard navigation and screen-reader semantics match an actual radio group.
In `@cueweb/components/ui/attributes-panel.tsx`:
- Around line 110-123: The toggle button in attributes-panel (the button using
setOpen and reading open to render ChevronDown/ChevronRight and label) is
missing an accessibility state; add aria-expanded={open} to that button so
assistive technologies announce the open/closed state of the attribute tree node
(keep the existing onClick, style, and className behavior and place
aria-expanded alongside them).
---
Nitpick comments:
In `@cueweb/components/ui/search-dropdown.tsx`:
- Line 110: Replace the unstable key={index} used in the virtualized list render
inside the SearchDropdown component with a stable identifier from the item
(e.g., use job.name or another unique field on the job object). Update the
element that currently sets key={index} to instead set key={job.name} (or
key={job.id} if available) so React can reconcile filtered/changed lists
correctly; ensure the referenced symbol is the same item variable used in the
map/rowRenderer where key is assigned.
- Around line 104-106: Create a memoized Set of added job names to avoid
repeated linear scans: use React's useMemo to build a Set from tableData (e.g.,
new Set(tableData.map(j => j.name))) declared near listRef (after its
declaration) and then replace the per-item some() call that computes isJobAdded
with a constant-time lookup using set.has(job.name). Update any references to
the old variable name (isJobAdded) to use the new lookup and ensure the memo
depends on tableData so it rebuilds when the list changes.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1a22e861-2b8f-436c-b294-ceea1a5ce6d9
⛔ Files ignored due to path filters (43)
cueweb/app/favicon.icois excluded by!**/*.icocueweb/app/icon.pngis excluded by!**/*.pngcueweb/app/icondark.pngis excluded by!**/*.pngcueweb/app/iconlight.pngis excluded by!**/*.pngcueweb/interface_screenshots/column _visibility_dropdown.pngis excluded by!**/*.pngcueweb/interface_screenshots/column _visibility_dropdown_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/frame.pngis excluded by!**/*.pngcueweb/interface_screenshots/frame_context_menu_open.pngis excluded by!**/*.pngcueweb/interface_screenshots/frame_context_menu_open_and_success_notification.pngis excluded by!**/*.pngcueweb/interface_screenshots/frame_context_menu_open_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/frame_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_context_menu_open.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_context_menu_open_and_success_notification.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_context_menu_open_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_data_table_filtering.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_data_table_filtering_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_search_functionality.pngis excluded by!**/*.pngcueweb/interface_screenshots/job_search_functionality_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/layer_context_menu_open.pngis excluded by!**/*.pngcueweb/interface_screenshots/layer_context_menu_open_and_success_notification.pngis excluded by!**/*.pngcueweb/interface_screenshots/layer_context_menu_open_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/layersframes.pngis excluded by!**/*.pngcueweb/interface_screenshots/layersframes_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/login.pngis excluded by!**/*.pngcueweb/interface_screenshots/mainpage.pngis excluded by!**/*.pngcueweb/interface_screenshots/mainpage_dark.pngis excluded by!**/*.pngcueweb/interface_screenshots/un-monitoring_selected_jobs-after.pngis excluded by!**/*.pngcueweb/interface_screenshots/un-monitoring_selected_jobs-before.pngis excluded by!**/*.pngcueweb/public/opencue-icon-black.pngis excluded by!**/*.pngcueweb/public/opencue-icon-white.pngis excluded by!**/*.pngcueweb/public/opencue_logo_small.pngis excluded by!**/*.pngimages/opencue-horizontal-black.pngis excluded by!**/*.pngimages/opencue-horizontal-black.svgis excluded by!**/*.svgimages/opencue-horizontal-white.pngis excluded by!**/*.pngimages/opencue-horizontal-white.svgis excluded by!**/*.svgimages/opencue-icon-black.pngis excluded by!**/*.pngimages/opencue-icon-black.svgis excluded by!**/*.svgimages/opencue-icon-white.pngis excluded by!**/*.pngimages/opencue-icon-white.svgis excluded by!**/*.svgimages/opencue-stacked-black.pngis excluded by!**/*.pngimages/opencue-stacked-black.svgis excluded by!**/*.svgimages/opencue-stacked-white.pngis excluded by!**/*.pngimages/opencue-stacked-white.svgis excluded by!**/*.svg
📒 Files selected for processing (28)
cueweb/README.mdcueweb/app/frames/[frame-name]/page.tsxcueweb/app/jobs/[job-name]/comments/page.tsxcueweb/app/jobs/data-table.tsxcueweb/app/layout.tsxcueweb/app/providers/session-provider.tsxcueweb/app/utils/help_menu.tscueweb/app/utils/menus.tscueweb/app/utils/use_attribute_selection.tscueweb/app/utils/use_attributes_panel.tscueweb/app/utils/use_cuebot_facility.tscueweb/app/utils/use_disable_job_interaction.tscueweb/app/utils/use_menu_registry.tscueweb/components/ui/app-header.tsxcueweb/components/ui/app-sidebar.tsxcueweb/components/ui/attributes-panel.tsxcueweb/components/ui/context_menus/action-context-menu.tsxcueweb/components/ui/cuewebicon.tsxcueweb/components/ui/read-only-banner.tsxcueweb/components/ui/search-dropdown.tsxdocs/_docs/concepts/cueweb-rest-gateway.mddocs/_docs/developer-guide/cueweb-development.mddocs/_docs/getting-started/deploying-cueweb.mddocs/_docs/other-guides/cueweb.mddocs/_docs/quick-starts/quick-start-cueweb.mddocs/_docs/reference/cueweb.mddocs/_docs/tutorials/cueweb-tutorial.mddocs/_docs/user-guides/cueweb-user-guide.md
💤 Files with no reviewable changes (2)
- cueweb/app/frames/[frame-name]/page.tsx
- cueweb/app/jobs/[job-name]/comments/page.tsx
| <input | ||
| type="search" | ||
| value={query} | ||
| onChange={(e) => setQuery(e.target.value)} | ||
| onKeyDown={(e) => e.stopPropagation()} | ||
| placeholder="Search menus" |
There was a problem hiding this comment.
Preserve dropdown keyboard controls in Help search
Stopping propagation for every key also swallows Escape/navigation keys for the menu while the input is focused.
Proposed fix
<input
type="search"
value={query}
onChange={(e) => setQuery(e.target.value)}
- onKeyDown={(e) => e.stopPropagation()}
+ onKeyDown={(e) => {
+ // Keep Radix typeahead disabled for text editing keys,
+ // but preserve menu keyboard controls (Esc/arrows/tab/etc).
+ if (
+ e.key.length === 1 ||
+ e.key === "Backspace" ||
+ e.key === "Delete"
+ ) {
+ e.stopPropagation();
+ }
+ }}
placeholder="Search menus"
aria-label="Search menus"
className="h-7 w-full bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none"
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <input | |
| type="search" | |
| value={query} | |
| onChange={(e) => setQuery(e.target.value)} | |
| onKeyDown={(e) => e.stopPropagation()} | |
| placeholder="Search menus" | |
| <input | |
| type="search" | |
| value={query} | |
| onChange={(e) => setQuery(e.target.value)} | |
| onKeyDown={(e) => { | |
| // Keep Radix typeahead disabled for text editing keys, | |
| // but preserve menu keyboard controls (Esc/arrows/tab/etc). | |
| if ( | |
| e.key.length === 1 || | |
| e.key === "Backspace" || | |
| e.key === "Delete" | |
| ) { | |
| e.stopPropagation(); | |
| } | |
| }} | |
| placeholder="Search menus" | |
| aria-label="Search menus" | |
| className="h-7 w-full bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none" | |
| /> |
🤖 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 `@cueweb/components/ui/app-header.tsx` around lines 153 - 158, The input's
onKeyDown currently calls e.stopPropagation() for every key, which prevents
dropdown keyboard handling; update the onKeyDown handler (the input with
value={query} and setQuery) to conditionally stop propagation only for keys that
should not affect the parent menu (e.g., regular character keys and Enter) and
allow navigation/escape keys (Escape, ArrowUp, ArrowDown, ArrowLeft, ArrowRight,
Tab if desired) to bubble so the menu's keyboard controls continue to work.
| role="radiogroup" | ||
| aria-label="Cuebot Facility" | ||
| className="ml-2 mt-1 space-y-1 border-l border-border pl-2 dark:border-zinc-800" | ||
| > | ||
| {facilities.map((f) => { | ||
| const active = f === facility; | ||
| return ( | ||
| <li key={f}> | ||
| <button | ||
| type="button" | ||
| role="radio" | ||
| aria-checked={active} | ||
| onClick={() => setFacility(f)} |
There was a problem hiding this comment.
Avoid incomplete radio semantics for facility selection
Custom radiogroup/radio roles should include full radio keyboard behavior; otherwise accessibility semantics are inconsistent.
Proposed fix
<ul
- role="radiogroup"
aria-label="Cuebot Facility"
className="ml-2 mt-1 space-y-1 border-l border-border pl-2 dark:border-zinc-800"
>
{facilities.map((f) => {
const active = f === facility;
return (
<li key={f}>
<button
type="button"
- role="radio"
- aria-checked={active}
+ aria-pressed={active}
onClick={() => setFacility(f)}
className={cn(📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| role="radiogroup" | |
| aria-label="Cuebot Facility" | |
| className="ml-2 mt-1 space-y-1 border-l border-border pl-2 dark:border-zinc-800" | |
| > | |
| {facilities.map((f) => { | |
| const active = f === facility; | |
| return ( | |
| <li key={f}> | |
| <button | |
| type="button" | |
| role="radio" | |
| aria-checked={active} | |
| onClick={() => setFacility(f)} | |
| <ul | |
| aria-label="Cuebot Facility" | |
| className="ml-2 mt-1 space-y-1 border-l border-border pl-2 dark:border-zinc-800" | |
| > | |
| {facilities.map((f) => { | |
| const active = f === facility; | |
| return ( | |
| <li key={f}> | |
| <button | |
| type="button" | |
| aria-pressed={active} | |
| onClick={() => setFacility(f)} |
🤖 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 `@cueweb/components/ui/app-sidebar.tsx` around lines 364 - 376, The facility
list uses custom role="radiogroup" and role="radio" on buttons but lacks full
radio keyboard semantics; update the facilities.map rendering (the button that
calls setFacility) to implement complete radio behavior: either render native
<input type="radio"> elements for each facility bound to the facility state (or
wrap a visually styled label around such an input), or add the missing keyboard
handlers on the button (manage tabIndex, onKeyDown to handle
ArrowLeft/ArrowRight/ArrowUp/ArrowDown/Home/End to move focus and call
setFacility, ensure aria-checked is provided and focus is placed correctly).
Make these changes in the component that contains facilities.map and setFacility
so keyboard navigation and screen-reader semantics match an actual radio group.
| <button | ||
| type="button" | ||
| onClick={() => setOpen((prev) => !prev)} | ||
| style={{ paddingLeft: depth * 12 }} | ||
| className="flex w-full items-center gap-1 rounded px-2 py-1 text-left text-xs font-semibold uppercase tracking-wide text-foreground hover:bg-foreground/5" | ||
| > | ||
| {open ? ( | ||
| <ChevronDown className="h-3 w-3 shrink-0" aria-hidden="true" /> | ||
| ) : ( | ||
| <ChevronRight className="h-3 w-3 shrink-0" aria-hidden="true" /> | ||
| )} | ||
| <span>{label}</span> | ||
| </button> | ||
| {open && <div>{childRows}</div>} |
There was a problem hiding this comment.
Expose expand/collapse state on attribute tree toggles
Add aria-expanded so assistive tech can announce node state.
Proposed fix
<button
type="button"
onClick={() => setOpen((prev) => !prev)}
+ aria-expanded={open}
style={{ paddingLeft: depth * 12 }}
className="flex w-full items-center gap-1 rounded px-2 py-1 text-left text-xs font-semibold uppercase tracking-wide text-foreground hover:bg-foreground/5"
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| type="button" | |
| onClick={() => setOpen((prev) => !prev)} | |
| style={{ paddingLeft: depth * 12 }} | |
| className="flex w-full items-center gap-1 rounded px-2 py-1 text-left text-xs font-semibold uppercase tracking-wide text-foreground hover:bg-foreground/5" | |
| > | |
| {open ? ( | |
| <ChevronDown className="h-3 w-3 shrink-0" aria-hidden="true" /> | |
| ) : ( | |
| <ChevronRight className="h-3 w-3 shrink-0" aria-hidden="true" /> | |
| )} | |
| <span>{label}</span> | |
| </button> | |
| {open && <div>{childRows}</div>} | |
| <button | |
| type="button" | |
| onClick={() => setOpen((prev) => !prev)} | |
| aria-expanded={open} | |
| style={{ paddingLeft: depth * 12 }} | |
| className="flex w-full items-center gap-1 rounded px-2 py-1 text-left text-xs font-semibold uppercase tracking-wide text-foreground hover:bg-foreground/5" | |
| > | |
| {open ? ( | |
| <ChevronDown className="h-3 w-3 shrink-0" aria-hidden="true" /> | |
| ) : ( | |
| <ChevronRight className="h-3 w-3 shrink-0" aria-hidden="true" /> | |
| )} | |
| <span>{label}</span> | |
| </button> | |
| {open && <div>{childRows}</div>} |
🤖 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 `@cueweb/components/ui/attributes-panel.tsx` around lines 110 - 123, The toggle
button in attributes-panel (the button using setOpen and reading open to render
ChevronDown/ChevronRight and label) is missing an accessibility state; add
aria-expanded={open} to that button so assistive technologies announce the
open/closed state of the attribute tree node (keep the existing onClick, style,
and className behavior and place aria-expanded alongside them).
Related Issues
Summarize your change.
[cueweb/docs] Add CueGUI-style navigation framework, safety mode, attributes panel, and comprehensive UI/docs refresh
Add global application header with grouped CueGUI navigation:
Add persistent collapsible left sidebar:
Add Disable Job Interaction safety mode:
Add dockable Attributes panel:
Add Cuebot Facility selector:
Add Help menu infrastructure:
Improve dark mode accessibility and consistency:
Refresh CueWeb branding and assets:
Refresh CueWeb documentation across README and docs/_docs/:
Summary by CodeRabbit
Release Notes
New Features
Improvements
Documentation