Repository navigation
feat: web ui design refresh - #4474
bryce-seifert wants to merge 97 commits into
Conversation
Add shared `PageIntro` and `PageTabs` layout components, plus reusable panel icon and module-type badge styles, then apply them across settings, surfaces, variables, import/export, and split-panel pages. This also consolidates status badge rendering, trims duplicate utility-heavy markup, and aligns responsive/layout behavior with shared helpers.
Replace the full-height divider line with a centered resize grip in `SplitPanels`, and add hover/active styling plus a reduced-motion fallback. This makes the drag affordance clearer without visually separating the panels.
Replaces generic `compact`/`stacked` modifiers on `secondary-panel-simple-header` with explicit `panel-header-compact` and `panel-header-stacked` names in both styles and React usages. This clarifies intent and avoids overly broad class names while preserving the existing panel header behavior.
Treat `showing='primary'` as an always-collapsed secondary panel: the root now gets a single-column layout class, the secondary is fully hidden (not just below `xl`), and the primary takes the full width at all breakpoints. Resizable mode is also disabled while collapsed so no drag handle appears and the saved split percentage is preserved for when the secondary is reopened. Updated SplitPanels tests to cover the new visibility, layout class, and resize behavior.
Splits the single `--color-primary` red into three distinct semantic tokens: - `--color-brand` (#d50215): identity only — logo, page-title icon, active sidebar indicator, inline links/nav. - `--color-primary` (#1f242e): safe interactive affordances — primary buttons, checked controls, tab selection underline, focus rings. - `--color-danger` (#c8102e): destructive actions only — danger buttons. Updates GenericConfirmModal and ResetWizardModal to use `color="danger"` on their confirm buttons (all callers are confirming a destructive action). Updates SwitchInputField to use new `--color-switch-off` / `--color-switch-off-hover` tokens for a visually distinct unchecked state. Updates notification badge to use `--color-brand`.
Reworks several web UI interactions and presentation details, including clearer action buttons/labels, improved typography/status styling, and updated empty-state/help text across buttons, triggers, instances, surfaces, and settings screens. The button grid now auto-scales to fit viewport space (removing manual drawScale/zoom wiring), and button panel/tab behavior was simplified for large-screen split-panel layouts. Accessibility and navigation were improved by adding automatic aria-label fallback support in Button/CopyButton, keyboard support for split-panel resizing, exact route matching for PageTabs, and a new test to ensure only the correct tab is highlighted on nested routes.
Removes embedded logo images from wizard/export/reset modal titles and drops the now-unused `makeAbsolutePath` import. Refactors `InstanceDebugLog` into an observer-driven page layout with connection/status subscriptions, PageHeader integration, improved controls, and richer per-line rendering. Aligns `LogPanel` line styling with the new format (fixed-width timestamps/source, level badges, system info rows), makes `PageHeader` resilient when sidebar context is absent, and adds `settings.css` rules to hide the first category spacer/top border in user config tables.
Moves the connection-lost and config-importing overlays out of `App.tsx` into a new `ConnectionLostOverlay.tsx` module, replacing legacy ID-based CSS overlays with reusable React components styled via Tailwind/theme classes. The new overlays add clearer messaging, improved visual hierarchy, and explicit actions/state indicators (including a reload button for lost connections), while simplifying `App.css` by removing obsolete overlay and clearfix rules.
Expose the Getting Started Wizard from the help menu so users can reopen the initial setup flow after onboarding. Also adjust action-menu and sidebar icon spacing so the new entry and existing items align consistently.
Redesigned the import workflow and user config pages with card-based sections, clearer action states, and updated typography/spacing. The import screens now use a unified page header, improved connection mapping and trigger/page import controls, and shared config option rows for full-import selection. User settings pages were split into cleaner surface blocks, with revamped HTTPS and backup rule editors and updated table/category styling to match the new visual structure.
Introduces a global command palette (Cmd/Ctrl+K and /) with fuzzy search for navigation, pages/buttons, connections, triggers, variables, and quick actions. Adds a new Page Matrix modal for browsing and configuring pages from the buttons view. Also overhauls multiple editor and admin surfaces (button step UX, trigger editor flow, system log controls/view, cloud page, add-instance filtering, entity row/header styling), updates icon usage in several components, and refreshes shared CSS styles for alerts/callouts/panels. The text input variable picker logic was expanded to support both `$(...)` and `$...` insertion flows.
Resolve conflicts in favour of the button grid rework (bitfocus#4434) for the grid itself, keeping the UI refresh elsewhere: - Buttons/{index,ButtonGridPanel,ButtonInfiniteGrid}.tsx and ActionRecorder/ButtonPicker.tsx taken wholesale from main - App.tsx: keep the refreshed connection-lost/importing overlays, but drive the importing one from the new shared importTaskStatus store - ImportExport/Import: adopt main's task-status-driven full import and the new ButtonPreview props Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # webui/src/Instances/ModuleVersionsRefresh.tsx # webui/src/Modules/RefreshModulesList.tsx
Polish several web UI management screens with more consistent toolbar layouts, button styling, and status/filter treatments. This updates the shared search box to use inline search/clear icons, replaces several ButtonGroup-based action rows with flexible layouts, and restyles module/surface visibility filters and surface/custom-variable table rows for a cleaner, more compact presentation.
# Conflicts: # webui/src/UserConfig/BackupRuleEditor.tsx
|
Important Review skippedWe couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedUse the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 Walkthrough📝 WalkthroughPriority: ➖ Normal Merge Risk: 🟡 Moderate · up to Some users may be unable to add an eligible surface instance, while previously identified navigation, accessibility, and display issues remain unresolved. Address the material issues before merging unless their impact is explicitly accepted. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1⚔️ Resolve merge conflicts 💡
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (19)
webui/src/Modules/ModuleVersionsTable.tsx-323-329 (1)
323-329: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winGive the icon-only install controls accessible names.
The buttons contain no text,
title, oraria-label. The title on the childFontAwesomeIcondoes not reliably name the parent button.Set the button title or
aria-labeltoRemove versionandInstall version. Include the disabled removal explanation on the button.Based on learnings, icon-only buttons must have accessible labels.
Also applies to: 399-405
Source: Learnings
webui/src/Modules/ModuleVersionsTable.tsx-105-128 (1)
105-128: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winExpose each filter as a toggle button.
activeaddsaria-current="page", which does not describe these Stable, Beta, and Deprecated filters. Screen readers cannot determine whether each filter is enabled.Add
aria-pressedfrom the matching visibility value. The visualactiveprop can remain.Based on learnings, custom toggle controls must expose their current state.
Source: Learnings
webui/src/Triggers/EditPanel.tsx-240-244 (1)
240-244: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winExpose the disclosure state to assistive technology.
The button expands and collapses content, but it does not provide
aria-expanded. Screen-reader users cannot determine the current state.Add
aria-expanded={showVariablesAndNotes}and connect the button to the content witharia-controls.Based on learnings, custom disclosure controls must expose their state through ARIA.
Source: Learnings
webui/src/Connections/ConnectionList/ConnectionList.tsx-105-116 (1)
105-116: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse one status classification for counts and filtering.
These lines count a missing or unrecognized status as
ok.ConnectionListItemWrapperonly hides explicitgoodstatuses when the OK filter is off. A connecting or status-less connection therefore remains visible after the user disables OK.Disabled connections have a similar mismatch. The count classifies them only as Disabled, but the row can also be hidden by its retained warning or error status.
Please classify each connection once. Use the same classification for both counts and visibility checks.
webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx-67-68 (1)
67-68: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReject unsuccessful help responses.
fetchresolves normally for HTTP 404 and 500 responses. The current code then renders the response body as module documentation.Please check
response.okbefore reading the body.Proposed fix
const response = await fetch(helpUrl) + if (!response.ok) { + throw new Error(`HTTP ${response.status}`) + } return response.text()webui/src/Controls/Components/EntityEditorHeadingProps.tsx-26-26 (1)
26-26: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep bulk controls when the heading is empty.
Some
ControlEntitiesEditorcallers passheading="". If those lists contain entities, this return removes the existing Expand all and Collapse all controls.Only return when the heading, actions, and child entities are all absent.
Proposed fix
- if (!heading && (!headingActions || headingActions.length === 0)) return null + if (!heading && (!headingActions || headingActions.length === 0) && childEntityIds.length === 0) return nullwebui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx-153-153 (1)
153-153: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the edit store outside the tab content.
InstanceGenericEditPanelcreatesInstanceEditPanelStoreinside the conditionally mounted Settings tab. When the user opens Help or Diagnostics, React unmounts the panel and its store, so unsaved settings can be lost when the user returns. Move the store to a component that remains mounted while the tabs change.webui/src/Instances/AddInstancePanel.tsx-705-711 (1)
705-711: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReally nice catalog rework. One wording detail for the surface flow.
This panel serves both connections and surfaces, and line 687 already branches on
service.moduleType. The configure step then hardcodes connection wording: the label at line 706 ("Connection Label"), the helper text at line 710, and the submit button at line 787 ("Create Connection"). A user adding a surface instance sees connection wording.Deriving the noun once keeps it consistent.
♻️ Suggested change
+ const instanceNoun = service.moduleType === ModuleInstanceType.Connection ? 'Connection' : 'Surface' ... <label htmlFor={labelFieldId} className="block text-xs font-semibold text-body mb-1"> - Connection Label + {instanceNoun} Label </label> <TextInputField id={labelFieldId} value={instanceLabel} setValue={setInstanceLabel} immediateValue /> <p className="text-2xs text-muted mt-1 mb-0"> - A unique name used to reference this connection across actions, feedbacks, and triggers. + A unique name used to reference this {instanceNoun.toLowerCase()} across actions, feedbacks, and triggers. </p>And at line 787:
- <FontAwesomeIcon icon={faPlus} className="me-1.5" /> Create Connection + <FontAwesomeIcon icon={faPlus} className="me-1.5" /> Create {instanceNoun}webui/src/ImportExport/Import/Full.tsx-338-343 (1)
338-343: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winSmall link nit:
href="settings"is relative and leaves the router.Lines 339 and 373 use
<a href="settings">. A relative href resolves against the current URL path, so the target changes with a trailing slash, and the browser does a full page reload instead of a client-side navigation. The file already imports from@tanstack/react-routerelsewhere in this area, so aLinkworks well here.♻️ Suggested change (apply to both links)
- <a href="settings" className="text-primary hover:underline"> + <Link to="/settings" className="text-primary hover:underline"> Settings - </a>{' '} + </Link>{' '}webui/src/Components/Badge.css-69-69 (1)
69-69: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd the required separator after the custom properties.
Stylelint reports
declaration-empty-line-beforeat Line 69. Add an empty line beforewidthso the stylesheet passes validation.Proposed fix
--spinner2-size: 0.75rem; --spinner2-stroke: 0.125rem; + width: var(--spinner2-size);Source: Linters/SAST tools
webui/src/Components/Button.css-120-130 (1)
120-130: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUpdate the dark-theme primary overrides.
The existing dark-theme rules at Lines 673-682, 751-760, and 813-820 still replace these primary tokens with red values. Primary, outline-primary, and ghost-primary actions therefore remain red in dark mode, while this change reserves red for destructive actions.
Use the corresponding
--color-primary*tokens in those dark-theme overrides.Also applies to: 348-360, 536-545
webui/src/Components/LogViewer.tsx-86-86 (1)
86-86: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winHandle log lines without a timestamp.
LogViewerLine.timepermitsnull, butdayjs(null).format(timeFormat)rendersInvalid Date. A valid timestamp-free log row therefore displays incorrect text.Render an empty timestamp or a deliberate placeholder when
line.time == null.Proposed fix
- {dayjs(line.time).format(timeFormat)} + {line.time == null ? '' : dayjs(line.time).format(timeFormat)}webui/src/Components/CollectionsNestingTable/CollectionsNestingTable.css-4-4 (1)
4-4: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDo not trap the sticky header inside
overflow: hidden.The new
overflow: hiddenmakes.collections-nesting-tablethe sticky containing block. Because this element does not perform the page or panel scrolling,.collections-nesting-table-headerscrolls away with the table.Use
overflow: clipif supported by the target browsers, or move the clipping and rounded corners to a separate wrapper.Also applies to: 10-16
webui/src/Components/TabArea.css-66-66 (1)
66-66: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winResolve the two Stylelint errors in the tab rules.
font: inheritat Line 66 resets the precedingfont-weight: 500. Move the shorthand before the explicit weight or replace it with the required individual font properties.The
min-height: 300pxdeclaration at Line 106 is also immediately overridden bymin-height: 0. Remove the obsolete declaration.These errors can fail stylesheet validation.
Also applies to: 106-110
Source: Linters/SAST tools
webui/src/Components/Modal.tsx-218-220 (1)
218-220: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the modal close control in the tab order.
tabIndex={-1}prevents keyboard users from reaching the visible close button. Remove this property so the dialog exposes all interactive controls through sequential keyboard navigation.Proposed fix
- <Dialog.Close className="panel-icon-button ms-auto" aria-label="Close modal" tabIndex={-1}> - <FontAwesomeIcon icon={faTimes} className="text-sm" /> + <Dialog.Close className="panel-icon-button ms-auto" aria-label="Close modal"> + <FontAwesomeIcon icon={faTimes} className="text-sm" aria-hidden="true" /> </Dialog.Close>Based on learnings, modal controls must support keyboard focus and provide an accessible name.
Source: Learnings
webui/src/Buttons/PageMatrixModal.tsx-122-124 (1)
122-124: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winSmall copy nit: the page count is hardcoded.
The subtitle says "all 99 pages", but the modal lists
pages.data, which can hold a different number of pages. The filter pill already shows the real total.✏️ Suggested fix
- <p className="text-2xs text-muted m-0"> - Visual overview of all 99 pages in your broadcast configuration - </p> + <p className="text-2xs text-muted m-0"> + Visual overview of all {pageCardsData.length} pages in your broadcast configuration + </p>webui/src/App.tsx-297-301 (1)
297-301: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winNice loading panel. One small thing: the logo path is not base-path aware.
webui/src/Layout/SidebarHeader.tsxwraps its logo withmakeAbsolutePath(). Thissrcis a bare absolute path, so the image will not resolve when Companion is served under a sub-path.🔧 Suggested fix
<img - src="/img/icons/128x128.png" + src={makeAbsolutePath('/img/icons/128x128.png')} alt="Bitfocus Companion" className="w-full h-full object-contain rounded-xl" />Add the import if it is not already present:
import { makeAbsolutePath } from './Resources/util.js'webui/src/Layout/Sidebar.tsx-347-355 (1)
347-355: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winGreat cleanup here. One behaviour gap: the Settings group only detects its first page.
basePathis taken fromsection.pages[0].path, which is/settings/generalforSETTINGS_SECTION.SidebarNavGroupthen computespathname.startsWith(basePath), so on/settings/backups,/settings/buttons,/settings/protocolsand/settings/advancedthe group is neither highlighted nor auto-opened.VARIABLES_SECTIONworks only by coincidence, because its first page is the section root.An explicit section base path fixes both sections.
🔧 Suggested fix
In
webui/src/Layout/navRegistry.ts, add the field and set it per section:export interface NavSection { id: string label: string icon: IconDefinition + /** Path prefix that marks this whole section active. */ + basePath: string pages: readonly NavPage[] }Then in this file:
- <SidebarNavGroup name={section.label} icon={section.icon} basePath={section.pages[0].path}> + <SidebarNavGroup name={section.label} icon={section.icon} basePath={section.basePath}>webui/src/ImportExport/Import/Full.tsx-382-382 (1)
382-382: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse the full-reset mode for this disabled check. When no component is selected,
sanitiseSelection(..., true)converts the selection to reset actions. The import controller accepts that configuration and performs the reset; it does not require a selected import component.- const anythingEnabled = isAnythingEnabled(sanitiseSelection(values, snapshot, false)) + const anythingEnabled = isAnythingEnabled(sanitiseSelection(values, snapshot, true))
🧹 Nitpick comments (1)
webui/src/Components/PillButton.tsx (1)
6-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winForward native HTML and ARIA properties from shared components. Both component APIs restrict downstream accessibility configuration instead of extending the native element contract.
webui/src/Components/PillButton.tsx#L6-L16: extend native button properties and spread the remaining properties onto<button>.webui/src/Components/Badge.tsx#L23-L31: extend native span properties and spread the remaining properties onto<span>.Based on learnings, reusable shared UI components must expose optional ARIA attributes for downstream accessibility customization.
Source: Learnings
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Advanced
Run ID: 2900a1b3-19e1-470c-943b-e1cfe038fc65
⛔ Files ignored due to path filters (1)
webui/public/img/logo-glass.pngis excluded by!**/*.png
📒 Files selected for processing (174)
e2e/tests/button-editor.spec.tse2e/tests/import-export.spec.tse2e/tests/trigger-editor.spec.tswebui/src/App.csswebui/src/App.tsxwebui/src/Buttons/ActionRecorder/Recorder.csswebui/src/Buttons/ActionRecorder/RecorderSession.tsxwebui/src/Buttons/ActionRecorder/RecorderSessionHeading.tsxwebui/src/Buttons/ActionRecorder/index.tsxwebui/src/Buttons/ButtonGridPanel.csswebui/src/Buttons/ButtonGridPanel.tsxwebui/src/Buttons/ButtonsSidebar.csswebui/src/Buttons/EditButton/ButtonEditorTabs.tsxwebui/src/Buttons/EditButton/ControlActionStepTab.tsxwebui/src/Buttons/EditButton/EditActionsRelease.tsxwebui/src/Buttons/EditButton/EditButton.tsxwebui/src/Buttons/PageMatrixModal.tsxwebui/src/Buttons/PageVariablesPanel.tsxwebui/src/Buttons/Pages.csswebui/src/Buttons/Pages.tsxwebui/src/Buttons/Presets/Presets.csswebui/src/Buttons/Presets/Presets.tsxwebui/src/Buttons/Presets/PresetsConnectionList.tsxwebui/src/Buttons/Presets/PresetsSectionsList.tsxwebui/src/Buttons/index.tsxwebui/src/Cloud/index.tsxwebui/src/Components/ActionMenu.tsxwebui/src/Components/Alert.csswebui/src/Components/Badge.csswebui/src/Components/Badge.tsxwebui/src/Components/Button.csswebui/src/Components/Button.tsxwebui/src/Components/Callout.csswebui/src/Components/CollectionsNestingTable/CollectionsNestingTable.csswebui/src/Components/CopyButton.tsxwebui/src/Components/GenericConfirmModal.tsxwebui/src/Components/InlineHelp.tsxwebui/src/Components/LogViewer.csswebui/src/Components/LogViewer.tsxwebui/src/Components/Modal.csswebui/src/Components/Modal.tsxwebui/src/Components/Notifications.csswebui/src/Components/Notifications.tsxwebui/src/Components/PillButton.csswebui/src/Components/PillButton.tsxwebui/src/Components/Popover.csswebui/src/Components/SearchBox.tsxwebui/src/Components/SwitchInputField.csswebui/src/Components/TabArea.csswebui/src/Components/TextInputField.tsxwebui/src/Components/VariablesTable.csswebui/src/Components/text-field.csswebui/src/Connections/AddConnectionPanel.tsxwebui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsxwebui/src/Connections/ConnectionEdit/ConnectionEditPanelHeading.tsxwebui/src/Connections/ConnectionList/ConnectionList.tsxwebui/src/Connections/ConnectionList/ConnectionListContext.tsxwebui/src/Connections/ConnectionList/ConnectionsTableRow.tsxwebui/src/Connections/ConnectionsPage.tsxwebui/src/Controls/Components/AddEntityDropdown.tsxwebui/src/Controls/Components/EntityCellControls.tsxwebui/src/Controls/Components/EntityChildGroup.tsxwebui/src/Controls/Components/EntityEditorHeadingProps.tsxwebui/src/Controls/Components/EntityEditorRow.tsxwebui/src/Controls/Components/EntityList.csswebui/src/Controls/ControlNotesEditor.tsxwebui/src/Controls/LocalVariablesEditor.tsxwebui/src/Emulator/ListHeader.tsxwebui/src/ImageLibrary/ImageLibraryEditor.tsxwebui/src/ImageLibrary/ImageLibraryGrid.tsxwebui/src/ImageLibrary/index.tsxwebui/src/ImportExport/Export.tsxwebui/src/ImportExport/Import/Full.tsxwebui/src/ImportExport/Import/Page.tsxwebui/src/ImportExport/Import/Triggers.tsxwebui/src/ImportExport/Import/index.tsxwebui/src/ImportExport/Reset.tsxwebui/src/ImportExport/index.tsxwebui/src/Instances/AddInstanceModal.tsxwebui/src/Instances/AddInstancePanel.csswebui/src/Instances/AddInstancePanel.tsxwebui/src/Instances/DebugLog.tsxwebui/src/Instances/HelpModal.tsxwebui/src/Instances/InstanceEdit/InstanceEditPanel.tsxwebui/src/Instances/List/InstanceStatusHelpers.tswebui/src/Instances/List/InstanceTableStatusCell.tsxwebui/src/Instances/List/InstancesListTableRow.csswebui/src/Instances/List/InstancesListTableRow.tsxwebui/src/Instances/List/__tests__/InstanceStatusHelpers.test.tswebui/src/Instances/ModuleHelpContent.tsxwebui/src/Instances/ModuleVersionsRefresh.tsxwebui/src/Layout/AdminLockContext.tsxwebui/src/Layout/CommandPalette.tsxwebui/src/Layout/CommandPaletteState.tswebui/src/Layout/ConnectionLostOverlay.csswebui/src/Layout/ConnectionLostOverlay.tsxwebui/src/Layout/Header.csswebui/src/Layout/Header.tsxwebui/src/Layout/PageHeader.tsxwebui/src/Layout/PageIntro.csswebui/src/Layout/PageIntro.tsxwebui/src/Layout/PageMatrixState.tswebui/src/Layout/PageTabs.csswebui/src/Layout/PageTabs.tsxwebui/src/Layout/PanelIcons.csswebui/src/Layout/PanelIcons.tsxwebui/src/Layout/Sidebar.csswebui/src/Layout/Sidebar.tsxwebui/src/Layout/SidebarHeader.tsxwebui/src/Layout/SplitPanels.csswebui/src/Layout/SplitPanels.tsxwebui/src/Layout/__tests__/PageTabs.test.tsxwebui/src/Layout/__tests__/SplitPanels.test.tsxwebui/src/Layout/__tests__/updateChannel.test.tswebui/src/Layout/navRegistry.tswebui/src/Layout/updateChannel.tswebui/src/LogPanel.tsxwebui/src/Modules/ImportCustomModule.tsxwebui/src/Modules/ModuleManagePanel.tsxwebui/src/Modules/ModuleVersionsTable.tsxwebui/src/Modules/ModulesList.tsxwebui/src/Modules/RefreshModuleInfo.tsxwebui/src/Modules/RefreshModulesList.tsxwebui/src/Modules/index.tsxwebui/src/Modules/modules-manage.csswebui/src/Surfaces/AddEmulatorModal.tsxwebui/src/Surfaces/Discovery/SurfaceDiscoveryPage.tsxwebui/src/Surfaces/Discovery/SurfaceDiscoveryTable.tsxwebui/src/Surfaces/Instances/AddSurfaceInstancePanel.tsxwebui/src/Surfaces/Instances/SurfaceInstanceList/SurfaceInstanceList.tsxwebui/src/Surfaces/KnownSurfacesTable.tsxwebui/src/Surfaces/MainSurfacesPage.tsxwebui/src/Surfaces/Remote/RemoteSurfaces/RemoteSurfacesList.tsxwebui/src/Surfaces/Remote/RemoteSurfacesPage.tsxwebui/src/Surfaces/SurfaceSettingsPanel.tsxwebui/src/Surfaces/SurfacesNav.tsxwebui/src/Surfaces/surfaces.csswebui/src/TabletView/ConfigurePanel.tsxwebui/src/Triggers/EditPanel.tsxwebui/src/Triggers/EventEditor.tsxwebui/src/Triggers/Page.tsxwebui/src/Triggers/TriggersTableContext.tsxwebui/src/UserConfig/BackupRuleEditor.tsxwebui/src/UserConfig/Components/SettingsCard.tsxwebui/src/UserConfig/Components/UserConfigHeadingRow.tsxwebui/src/UserConfig/Components/UserConfigSwitchRow.tsxwebui/src/UserConfig/Sections/HttpsConfig.tsxwebui/src/UserConfig/SettingsNav.tsxwebui/src/UserConfig/advanced.tsxwebui/src/UserConfig/backups.tsxwebui/src/UserConfig/buttons.tsxwebui/src/UserConfig/general.tsxwebui/src/UserConfig/index.tsxwebui/src/UserConfig/protocols.tsxwebui/src/UserConfig/settings.csswebui/src/Variables/CustomVariablesList.tsxwebui/src/Variables/CustomVariablesListRow.tsxwebui/src/Variables/ExpressionVariables/EditPanel.tsxwebui/src/Variables/ExpressionVariables/ExpressionVariablesTableContext.tsxwebui/src/Variables/ExpressionVariables/Page.tsxwebui/src/Variables/VariablesNav.tsxwebui/src/Variables/index.tsxwebui/src/Wizard/index.tsxwebui/src/base.csswebui/src/common.csswebui/src/layout.csswebui/src/loading.csswebui/src/log.csswebui/src/nav.csswebui/src/routes/_app/connections/add.tsxwebui/src/routes/_app/connections/index.tsxwebui/src/routes/_app/triggers/index.tsxwebui/src/tailwind.csswebui/src/utilities.css
💤 Files with no reviewable changes (5)
- webui/src/Layout/Header.css
- webui/src/log.css
- webui/src/loading.css
- webui/src/Layout/Header.tsx
- webui/src/Instances/AddInstanceModal.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
- Add aligned property rows, dedicated pin controls, and compact sections - Improve layer spacing, group tree lines, and pinned-view navigation - Stabilize summary spacing and refresh the empty-button state - Simplify preset placement controls and sidebar spacing
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
68be4b03-259e-46bc-be9a-becd382525c8
📒 Files selected for processing (36)
webui/src/Buttons/ButtonsSidebar.csswebui/src/Buttons/EditButton/EditActionsRelease.tsxwebui/src/Buttons/EditButton/EditButton.csswebui/src/Buttons/EditButton/EditButton.tsxwebui/src/Buttons/EditButton/FeedbackOverridesTab.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/ElementCommonProperties.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/ElementPropertiesEditor.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/ElementPropertiesUtil.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/ElementsList.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/LayeredButtonEditor.tsxwebui/src/Buttons/EditButton/LayeredButtonEditor/PinnedPropertiesEditor.tsxwebui/src/Buttons/Pages.tsxwebui/src/Buttons/Presets/Presets.csswebui/src/Buttons/Presets/PresetsSectionsList.tsxwebui/src/Buttons/index.tsxwebui/src/Components/PropertyFieldRow.tsxwebui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsxwebui/src/Connections/ConnectionsPage.tsxwebui/src/Instances/AddInstancePanel.csswebui/src/Instances/AddInstancePanel.tsxwebui/src/Instances/InstanceEdit/InstanceEditPanel.csswebui/src/Instances/InstanceEdit/InstanceEditPanel.tsxwebui/src/Instances/InstanceEdit/InstanceVersionChangeButton.tsxwebui/src/Instances/List/InstancesListTableRow.tsxwebui/src/Instances/UpdateInstanceToLatestBadge.tsxwebui/src/Modules/ModuleCatalog.tswebui/src/Modules/ModuleManagePanel.tsxwebui/src/Modules/ModuleVersionUsageIcon.tsxwebui/src/Modules/ModuleVersionsTable.tsxwebui/src/Modules/ModulesList.tsxwebui/src/Modules/RefreshModuleInfo.tsxwebui/src/Modules/__tests__/ModuleCatalog.test.tswebui/src/Modules/__tests__/ModuleVersionsTable.test.tsxwebui/src/Modules/modules-manage.csswebui/src/UserConfig/BackupRuleEditor.tsxwebui/src/routes/_app/settings/backups/$ruleId.tsx
🚧 Files skipped from review as they are similar to previous changes (13)
- webui/src/Connections/ConnectionsPage.tsx
- webui/src/routes/_app/settings/backups/$ruleId.tsx
- webui/src/Instances/AddInstancePanel.css
- webui/src/Instances/InstanceEdit/InstanceEditPanel.css
- webui/src/Buttons/Presets/Presets.css
- webui/src/Buttons/ButtonsSidebar.css
- webui/src/Buttons/EditButton/EditActionsRelease.tsx
- webui/src/Modules/modules-manage.css
- webui/src/Buttons/Presets/PresetsSectionsList.tsx
- webui/src/Instances/List/InstancesListTableRow.tsx
- webui/src/UserConfig/BackupRuleEditor.tsx
- webui/src/Instances/InstanceEdit/InstanceVersionChangeButton.tsx
- webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.
Much like the global buttons settings, so that they aren't missed in the surfaces tabs
Add a `--container-readable` (56rem) theme token, giving a `max-w-readable` utility, so form content stops widening on large screens and labels stay close to their values. - Settings pages (index, general, buttons, surfaces, protocols, advanced) - Shared `.edit-section` (connections, surface integrations, variables, image library, backups), plus the connection Docs tab and the instance save footer - Trigger editor, surface settings panel, modules manager (including the versions table) - Buttons sidebar sections (Pages, Page Variables, Presets) Panel headers and the page tab strips still span the full width.
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
1171b09b-14ac-4594-964f-d85a7b7d457d
📒 Files selected for processing (27)
docs/user-guide/3_config/settings.mddocs/user-guide/7_surfaces/index.mdwebui/src/Buttons/ButtonsSidebar.csswebui/src/Buttons/EditButton/ButtonEditorTabs.tsxwebui/src/Components/EditSectionCard.csswebui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsxwebui/src/Instances/AddInstanceLimit.tswebui/src/Instances/AddInstancePanel.tsxwebui/src/Instances/InstanceEdit/InstanceEditPanel.tsxwebui/src/Instances/__tests__/AddInstanceLimit.test.tswebui/src/Layout/navRegistry.tswebui/src/Modules/ModuleManagePanel.tsxwebui/src/Surfaces/EditPanel.tsxwebui/src/Surfaces/SurfaceSettingsPanel.tsxwebui/src/Triggers/EditPanel.tsxwebui/src/UserConfig/Sections/SurfacesConfig.tsxwebui/src/UserConfig/SettingsNav.tsxwebui/src/UserConfig/advanced.tsxwebui/src/UserConfig/buttons.tsxwebui/src/UserConfig/general.tsxwebui/src/UserConfig/index.tsxwebui/src/UserConfig/protocols.tsxwebui/src/UserConfig/surfaces.tsxwebui/src/routeTree.gen.tswebui/src/routes/_app/settings/surfaces.tsxwebui/src/routes/_app/surfaces_/integrations/index.tsxwebui/src/tailwind.css
💤 Files with no reviewable changes (1)
- webui/src/Surfaces/SurfaceSettingsPanel.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
- webui/src/UserConfig/general.tsx
- webui/src/UserConfig/protocols.tsx
- webui/src/UserConfig/buttons.tsx
- webui/src/Modules/ModuleManagePanel.tsx
- webui/src/Surfaces/EditPanel.tsx
- webui/src/Components/EditSectionCard.css
- webui/src/Buttons/ButtonsSidebar.css
- webui/src/Triggers/EditPanel.tsx
- webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx
- webui/src/Instances/InstanceEdit/InstanceEditPanel.tsx
- webui/src/Instances/AddInstancePanel.tsx
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.
✅ Action performedReviews paused. |
Pass the module type to getLatestVersion in the surface instance limit gate, following its new signature on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r tabs
- Notes: share one notes UI (Add note button + preview strip with inline
editor) across buttons, triggers, custom and expression variables, replacing
the button-only header notes, the trigger's collapsed bottom card and the
expression variable's Notes field. Each editor passes in how its notes save
(useNotesEditor / useControlNotesSetter); ControlNotesEditor is removed.
- Triggers: notes sit under the trigger name; local variables move to a
Behaviour / Local Variables tab pair, matching the button editor.
- TabArea: add a required `variant` ('underline' | 'pills'). The button
editor's pill tabs move from its own stylesheet into this variant, now also
used by triggers; existing tab bars pass 'underline'.
- Custom variables: add optional `notes` with a setNotes endpoint. Notes are
internal, so they don't announce a definition change.
- Variable panels: custom and expression variables share a first "Variable"
row (full reference, copy button, Add note); the note shows below General
Settings.
- TopBar: a 44px header across the app frame. Left: a breadcrumb from the nav
registry ("Settings ' Protocols"; the page's own title for top-level pages),
linking back to the page from its child routes, plus the page's help. The
current page crumb is the page's <h1>. Right: install name, an amber
"update available" pill linking to the download, search (⌘K), a labelled
Help menu (life-ring, so it isn't confused with the page's "?") and lock.
On mobile it carries the menu button, replacing the floating toggle.
- PageHeader: inside the app frame it hands its title/icon/help to the bar
via TopBarPageContext and renders nothing, removing the per-page title row;
standalone pages (e.g. a debug log window) still draw it themselves.
- Sidebar: now navigation only. Search, Help, update notice, install name and
lock move to the bar; the footer keeps the version and collapse control.
- Extract useHelpMenuItems, useUpdateInfo (still hidden on experimental
builds) and useTabNotifications (shared by the sidebar badges).
- navRegistry: add navLocationForPath, used for the breadcrumb.
- layout: .body fills what the bar leaves of the frame instead of
max-height: 100%.
- Theme: a light/dark/system preference kept per browser (localStorage, synced across tabs). System follows prefers-color-scheme live. Applied as data-theme + color-scheme on <html> by Theme/ThemeState.ts, and before first paint by an inline script in index.html - Tokens: a :root[data-theme='dark'] block in tailwind.css gives every themed --color-* token a dark value; color-mix/var() tokens recompute from them. Tokens that must not change (button canvas, button grid, armed state, text-on-dark, backdrop) are listed in Theme/themeTokens.ts. Adds a `dark:` custom variant for one-offs. - New tokens where primary doubled as text or a selected fill: --color-primary-text, --color-variable-text, --color-tab-active-bg/-border. - Cleanup: raw Tailwind palette classes (~105 in 30 files) mapped to the status tone tokens; hard-coded colors in CSS/TSX moved to tokens (shadows, modal/wizard overlays, close button, sidebar, variable value pill, colour picker chrome, PRIMARY_COLOR for spinners). - Monaco: a companion-expression-dark theme, picked from the resolved theme. - UI: a theme menu (palette icon) in the top bar, an Appearance card on Settings > General, and "Use … Theme" command palette actions. - Storybook: a Light/Dark toolbar; the canvas follows the theme. - Docs: Appearance section in the settings guide.
|
I think this is probably another good stopping point for some more feedback, if you have time to dive into the branch again. I've tried to address most of the initial feedback, but I'm sure I've missed some things / also changed some other things that might get some additional feedback. Big changes since the initial review:
|
closes #673
closes #4103
closes #4362
This turned out to be quite a large diff, and I think will need some discussion on some components. But wanted to get this out there to start that and get some feedback.
The main goal is to modernize the web UI a bit, with these being the key changes:
PageHeader(icon + title + inline help). This also means the update message is now a banner in the sidebar footer as well.Presets / Recorder), and
SplitPanelslayout for list + detail pages that collapses sensibly onsmaller screens.
Button,Accordion,Toolbar,NonIdealStatecomponents,Here are some assorted screenshots, but I recommend just testing this branch to get a real feel of it:
Summary by CodeRabbit
New Features
Improvements