Skip to content

feat: web ui design refresh - #4474

Open
bryce-seifert wants to merge 97 commits into
bitfocus:mainfrom
bryce-seifert:feat/uiRefresh
Open

bryce-seifert wants to merge 97 commits into
bitfocus:mainfrom
bryce-seifert:feat/uiRefresh

Conversation

@bryce-seifert

@bryce-seifert bryce-seifert commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

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:

  • Revamped sidebar with grouped navigation (Program / Connect / System), and better visual hierarchy for nested elements.
  • The old topbar is gone, each page now has a consistent PageHeader (icon + title + inline help). This also means the update message is now a banner in the sidebar footer as well.
  • New command palette that allows searching and jump to pages, connections, variables and actions from anywhere
  • On the Buttons page, modernized sidebar tabs (Pages / Page Variables /
    Presets / Recorder), and SplitPanels layout for list + detail pages that collapses sensibly on
    smaller screens.
  • Modernized the log pages, and unified the layout for both the System Log and connection logs
  • Cleaned up the design system and separated brand / primary / danger color roles, shared Button,
    Accordion, Toolbar, NonIdealState components,
  • Some other changes include the app loading / error UI and simplified modal headers

Here are some assorted screenshots, but I recommend just testing this branch to get a real feel of it:

Screenshot 2026-10-04 at 3 04 46 PM Screenshot 2026-10-04 at 3 05 06 PM Screenshot 2026-10-04 at 3 05 27 PM Screenshot 2026-10-04 at 3 05 56 PM

Summary by CodeRabbit

  • New Features

    • Added a searchable command palette with keyboard navigation, quick actions, and a page matrix for finding and configuring pages.
    • Added a dedicated Action Recorder page with options to save recordings to buttons or triggers.
    • Added searchable module setup, connection diagnostics, richer log filtering and copy controls, and custom-variable creation and editing.
    • Added connection search and status filters, configurable module update policies, and a dedicated Surfaces settings page.
    • Updated import flows with clearer options for preserving or replacing configuration.
  • Improvements

    • Refreshed navigation and layouts across settings, surfaces, buttons, and variables, with responsive designs and clearer status indicators.
    • Improved keyboard and screen-reader support, including keyboard-adjustable panels.
    • Added connection-loss and configuration-import screens, and marked Companion Cloud as deprecated.

bryce-seifert and others added 28 commits August 26, 2026 19:40
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
@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

We 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 @coderabbitai full review.

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

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough
📝 Walkthrough

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to e12dd

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)
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the pull request’s primary goal: a broad refresh of the web UI design.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch feat/uiRefresh

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

@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

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 win

Give the icon-only install controls accessible names.

The buttons contain no text, title, or aria-label. The title on the child FontAwesomeIcon does not reliably name the parent button.

Set the button title or aria-label to Remove version and Install 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 win

Expose each filter as a toggle button.

active adds aria-current="page", which does not describe these Stable, Beta, and Deprecated filters. Screen readers cannot determine whether each filter is enabled.

Add aria-pressed from the matching visibility value. The visual active prop 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 win

Expose 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 with aria-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 win

Use one status classification for counts and filtering.

These lines count a missing or unrecognized status as ok. ConnectionListItemWrapper only hides explicit good statuses 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 win

Reject unsuccessful help responses.

fetch resolves normally for HTTP 404 and 500 responses. The current code then renders the response body as module documentation.

Please check response.ok before 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 win

Keep bulk controls when the heading is empty.

Some ControlEntitiesEditor callers pass heading="". 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 null
webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx-153-153 (1)

153-153: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the edit store outside the tab content. InstanceGenericEditPanel creates InstanceEditPanelStore inside 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 win

Really 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 win

Small 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-router elsewhere in this area, so a Link works 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 win

Add the required separator after the custom properties.

Stylelint reports declaration-empty-line-before at Line 69. Add an empty line before width so 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 win

Update 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 win

Handle log lines without a timestamp.

LogViewerLine.time permits null, but dayjs(null).format(timeFormat) renders Invalid 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 win

Do not trap the sticky header inside overflow: hidden.

The new overflow: hidden makes .collections-nesting-table the sticky containing block. Because this element does not perform the page or panel scrolling, .collections-nesting-table-header scrolls away with the table.

Use overflow: clip if 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 win

Resolve the two Stylelint errors in the tab rules.

font: inherit at Line 66 resets the preceding font-weight: 500. Move the shorthand before the explicit weight or replace it with the required individual font properties.

The min-height: 300px declaration at Line 106 is also immediately overridden by min-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 win

Keep 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 win

Small 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 win

Nice loading panel. One small thing: the logo path is not base-path aware.

webui/src/Layout/SidebarHeader.tsx wraps its logo with makeAbsolutePath(). This src is 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 win

Great cleanup here. One behaviour gap: the Settings group only detects its first page.

basePath is taken from section.pages[0].path, which is /settings/general for SETTINGS_SECTION. SidebarNavGroup then computes pathname.startsWith(basePath), so on /settings/backups, /settings/buttons, /settings/protocols and /settings/advanced the group is neither highlighted nor auto-opened. VARIABLES_SECTION works 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 win

Use 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 win

Forward 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

📥 Commits

Reviewing files that changed from the base of the PR and between b407e51 and 7337182.

⛔ Files ignored due to path filters (1)
  • webui/public/img/logo-glass.png is excluded by !**/*.png
📒 Files selected for processing (174)
  • e2e/tests/button-editor.spec.ts
  • e2e/tests/import-export.spec.ts
  • e2e/tests/trigger-editor.spec.ts
  • webui/src/App.css
  • webui/src/App.tsx
  • webui/src/Buttons/ActionRecorder/Recorder.css
  • webui/src/Buttons/ActionRecorder/RecorderSession.tsx
  • webui/src/Buttons/ActionRecorder/RecorderSessionHeading.tsx
  • webui/src/Buttons/ActionRecorder/index.tsx
  • webui/src/Buttons/ButtonGridPanel.css
  • webui/src/Buttons/ButtonGridPanel.tsx
  • webui/src/Buttons/ButtonsSidebar.css
  • webui/src/Buttons/EditButton/ButtonEditorTabs.tsx
  • webui/src/Buttons/EditButton/ControlActionStepTab.tsx
  • webui/src/Buttons/EditButton/EditActionsRelease.tsx
  • webui/src/Buttons/EditButton/EditButton.tsx
  • webui/src/Buttons/PageMatrixModal.tsx
  • webui/src/Buttons/PageVariablesPanel.tsx
  • webui/src/Buttons/Pages.css
  • webui/src/Buttons/Pages.tsx
  • webui/src/Buttons/Presets/Presets.css
  • webui/src/Buttons/Presets/Presets.tsx
  • webui/src/Buttons/Presets/PresetsConnectionList.tsx
  • webui/src/Buttons/Presets/PresetsSectionsList.tsx
  • webui/src/Buttons/index.tsx
  • webui/src/Cloud/index.tsx
  • webui/src/Components/ActionMenu.tsx
  • webui/src/Components/Alert.css
  • webui/src/Components/Badge.css
  • webui/src/Components/Badge.tsx
  • webui/src/Components/Button.css
  • webui/src/Components/Button.tsx
  • webui/src/Components/Callout.css
  • webui/src/Components/CollectionsNestingTable/CollectionsNestingTable.css
  • webui/src/Components/CopyButton.tsx
  • webui/src/Components/GenericConfirmModal.tsx
  • webui/src/Components/InlineHelp.tsx
  • webui/src/Components/LogViewer.css
  • webui/src/Components/LogViewer.tsx
  • webui/src/Components/Modal.css
  • webui/src/Components/Modal.tsx
  • webui/src/Components/Notifications.css
  • webui/src/Components/Notifications.tsx
  • webui/src/Components/PillButton.css
  • webui/src/Components/PillButton.tsx
  • webui/src/Components/Popover.css
  • webui/src/Components/SearchBox.tsx
  • webui/src/Components/SwitchInputField.css
  • webui/src/Components/TabArea.css
  • webui/src/Components/TextInputField.tsx
  • webui/src/Components/VariablesTable.css
  • webui/src/Components/text-field.css
  • webui/src/Connections/AddConnectionPanel.tsx
  • webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx
  • webui/src/Connections/ConnectionEdit/ConnectionEditPanelHeading.tsx
  • webui/src/Connections/ConnectionList/ConnectionList.tsx
  • webui/src/Connections/ConnectionList/ConnectionListContext.tsx
  • webui/src/Connections/ConnectionList/ConnectionsTableRow.tsx
  • webui/src/Connections/ConnectionsPage.tsx
  • webui/src/Controls/Components/AddEntityDropdown.tsx
  • webui/src/Controls/Components/EntityCellControls.tsx
  • webui/src/Controls/Components/EntityChildGroup.tsx
  • webui/src/Controls/Components/EntityEditorHeadingProps.tsx
  • webui/src/Controls/Components/EntityEditorRow.tsx
  • webui/src/Controls/Components/EntityList.css
  • webui/src/Controls/ControlNotesEditor.tsx
  • webui/src/Controls/LocalVariablesEditor.tsx
  • webui/src/Emulator/ListHeader.tsx
  • webui/src/ImageLibrary/ImageLibraryEditor.tsx
  • webui/src/ImageLibrary/ImageLibraryGrid.tsx
  • webui/src/ImageLibrary/index.tsx
  • webui/src/ImportExport/Export.tsx
  • webui/src/ImportExport/Import/Full.tsx
  • webui/src/ImportExport/Import/Page.tsx
  • webui/src/ImportExport/Import/Triggers.tsx
  • webui/src/ImportExport/Import/index.tsx
  • webui/src/ImportExport/Reset.tsx
  • webui/src/ImportExport/index.tsx
  • webui/src/Instances/AddInstanceModal.tsx
  • webui/src/Instances/AddInstancePanel.css
  • webui/src/Instances/AddInstancePanel.tsx
  • webui/src/Instances/DebugLog.tsx
  • webui/src/Instances/HelpModal.tsx
  • webui/src/Instances/InstanceEdit/InstanceEditPanel.tsx
  • webui/src/Instances/List/InstanceStatusHelpers.ts
  • webui/src/Instances/List/InstanceTableStatusCell.tsx
  • webui/src/Instances/List/InstancesListTableRow.css
  • webui/src/Instances/List/InstancesListTableRow.tsx
  • webui/src/Instances/List/__tests__/InstanceStatusHelpers.test.ts
  • webui/src/Instances/ModuleHelpContent.tsx
  • webui/src/Instances/ModuleVersionsRefresh.tsx
  • webui/src/Layout/AdminLockContext.tsx
  • webui/src/Layout/CommandPalette.tsx
  • webui/src/Layout/CommandPaletteState.ts
  • webui/src/Layout/ConnectionLostOverlay.css
  • webui/src/Layout/ConnectionLostOverlay.tsx
  • webui/src/Layout/Header.css
  • webui/src/Layout/Header.tsx
  • webui/src/Layout/PageHeader.tsx
  • webui/src/Layout/PageIntro.css
  • webui/src/Layout/PageIntro.tsx
  • webui/src/Layout/PageMatrixState.ts
  • webui/src/Layout/PageTabs.css
  • webui/src/Layout/PageTabs.tsx
  • webui/src/Layout/PanelIcons.css
  • webui/src/Layout/PanelIcons.tsx
  • webui/src/Layout/Sidebar.css
  • webui/src/Layout/Sidebar.tsx
  • webui/src/Layout/SidebarHeader.tsx
  • webui/src/Layout/SplitPanels.css
  • webui/src/Layout/SplitPanels.tsx
  • webui/src/Layout/__tests__/PageTabs.test.tsx
  • webui/src/Layout/__tests__/SplitPanels.test.tsx
  • webui/src/Layout/__tests__/updateChannel.test.ts
  • webui/src/Layout/navRegistry.ts
  • webui/src/Layout/updateChannel.ts
  • webui/src/LogPanel.tsx
  • webui/src/Modules/ImportCustomModule.tsx
  • webui/src/Modules/ModuleManagePanel.tsx
  • webui/src/Modules/ModuleVersionsTable.tsx
  • webui/src/Modules/ModulesList.tsx
  • webui/src/Modules/RefreshModuleInfo.tsx
  • webui/src/Modules/RefreshModulesList.tsx
  • webui/src/Modules/index.tsx
  • webui/src/Modules/modules-manage.css
  • webui/src/Surfaces/AddEmulatorModal.tsx
  • webui/src/Surfaces/Discovery/SurfaceDiscoveryPage.tsx
  • webui/src/Surfaces/Discovery/SurfaceDiscoveryTable.tsx
  • webui/src/Surfaces/Instances/AddSurfaceInstancePanel.tsx
  • webui/src/Surfaces/Instances/SurfaceInstanceList/SurfaceInstanceList.tsx
  • webui/src/Surfaces/KnownSurfacesTable.tsx
  • webui/src/Surfaces/MainSurfacesPage.tsx
  • webui/src/Surfaces/Remote/RemoteSurfaces/RemoteSurfacesList.tsx
  • webui/src/Surfaces/Remote/RemoteSurfacesPage.tsx
  • webui/src/Surfaces/SurfaceSettingsPanel.tsx
  • webui/src/Surfaces/SurfacesNav.tsx
  • webui/src/Surfaces/surfaces.css
  • webui/src/TabletView/ConfigurePanel.tsx
  • webui/src/Triggers/EditPanel.tsx
  • webui/src/Triggers/EventEditor.tsx
  • webui/src/Triggers/Page.tsx
  • webui/src/Triggers/TriggersTableContext.tsx
  • webui/src/UserConfig/BackupRuleEditor.tsx
  • webui/src/UserConfig/Components/SettingsCard.tsx
  • webui/src/UserConfig/Components/UserConfigHeadingRow.tsx
  • webui/src/UserConfig/Components/UserConfigSwitchRow.tsx
  • webui/src/UserConfig/Sections/HttpsConfig.tsx
  • webui/src/UserConfig/SettingsNav.tsx
  • webui/src/UserConfig/advanced.tsx
  • webui/src/UserConfig/backups.tsx
  • webui/src/UserConfig/buttons.tsx
  • webui/src/UserConfig/general.tsx
  • webui/src/UserConfig/index.tsx
  • webui/src/UserConfig/protocols.tsx
  • webui/src/UserConfig/settings.css
  • webui/src/Variables/CustomVariablesList.tsx
  • webui/src/Variables/CustomVariablesListRow.tsx
  • webui/src/Variables/ExpressionVariables/EditPanel.tsx
  • webui/src/Variables/ExpressionVariables/ExpressionVariablesTableContext.tsx
  • webui/src/Variables/ExpressionVariables/Page.tsx
  • webui/src/Variables/VariablesNav.tsx
  • webui/src/Variables/index.tsx
  • webui/src/Wizard/index.tsx
  • webui/src/base.css
  • webui/src/common.css
  • webui/src/layout.css
  • webui/src/loading.css
  • webui/src/log.css
  • webui/src/nav.css
  • webui/src/routes/_app/connections/add.tsx
  • webui/src/routes/_app/connections/index.tsx
  • webui/src/routes/_app/triggers/index.tsx
  • webui/src/tailwind.css
  • webui/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.

Comment thread webui/src/common.css
Comment thread webui/src/Components/PillButton.css
Comment thread webui/src/TabletView/ConfigurePanel.tsx Outdated
Comment thread webui/src/tailwind.css Outdated
Comment thread webui/src/Triggers/EditPanel.tsx Outdated
Comment thread webui/src/Variables/ExpressionVariables/Page.tsx
- 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

@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: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 68be4b03-259e-46bc-be9a-becd382525c8
📥 Commits

Reviewing files that changed from the base of the PR and between c2b6fcf and 13e7dc0.

📒 Files selected for processing (36)
  • webui/src/Buttons/ButtonsSidebar.css
  • webui/src/Buttons/EditButton/EditActionsRelease.tsx
  • webui/src/Buttons/EditButton/EditButton.css
  • webui/src/Buttons/EditButton/EditButton.tsx
  • webui/src/Buttons/EditButton/FeedbackOverridesTab.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/ElementCommonProperties.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/ElementPropertiesEditor.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/ElementPropertiesUtil.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/ElementsList.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/LayeredButtonEditor.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/PinnedPropertiesEditor.tsx
  • webui/src/Buttons/Pages.tsx
  • webui/src/Buttons/Presets/Presets.css
  • webui/src/Buttons/Presets/PresetsSectionsList.tsx
  • webui/src/Buttons/index.tsx
  • webui/src/Components/PropertyFieldRow.tsx
  • webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx
  • webui/src/Connections/ConnectionsPage.tsx
  • webui/src/Instances/AddInstancePanel.css
  • webui/src/Instances/AddInstancePanel.tsx
  • webui/src/Instances/InstanceEdit/InstanceEditPanel.css
  • webui/src/Instances/InstanceEdit/InstanceEditPanel.tsx
  • webui/src/Instances/InstanceEdit/InstanceVersionChangeButton.tsx
  • webui/src/Instances/List/InstancesListTableRow.tsx
  • webui/src/Instances/UpdateInstanceToLatestBadge.tsx
  • webui/src/Modules/ModuleCatalog.ts
  • webui/src/Modules/ModuleManagePanel.tsx
  • webui/src/Modules/ModuleVersionUsageIcon.tsx
  • webui/src/Modules/ModuleVersionsTable.tsx
  • webui/src/Modules/ModulesList.tsx
  • webui/src/Modules/RefreshModuleInfo.tsx
  • webui/src/Modules/__tests__/ModuleCatalog.test.ts
  • webui/src/Modules/__tests__/ModuleVersionsTable.test.tsx
  • webui/src/Modules/modules-manage.css
  • webui/src/UserConfig/BackupRuleEditor.tsx
  • webui/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.

Comment thread webui/src/Instances/AddInstancePanel.tsx
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.

@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: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1171b09b-14ac-4594-964f-d85a7b7d457d
📥 Commits

Reviewing files that changed from the base of the PR and between 13e7dc0 and e12ddf7.

📒 Files selected for processing (27)
  • docs/user-guide/3_config/settings.md
  • docs/user-guide/7_surfaces/index.md
  • webui/src/Buttons/ButtonsSidebar.css
  • webui/src/Buttons/EditButton/ButtonEditorTabs.tsx
  • webui/src/Components/EditSectionCard.css
  • webui/src/Connections/ConnectionEdit/ConnectionEditPanel.tsx
  • webui/src/Instances/AddInstanceLimit.ts
  • webui/src/Instances/AddInstancePanel.tsx
  • webui/src/Instances/InstanceEdit/InstanceEditPanel.tsx
  • webui/src/Instances/__tests__/AddInstanceLimit.test.ts
  • webui/src/Layout/navRegistry.ts
  • webui/src/Modules/ModuleManagePanel.tsx
  • webui/src/Surfaces/EditPanel.tsx
  • webui/src/Surfaces/SurfaceSettingsPanel.tsx
  • webui/src/Triggers/EditPanel.tsx
  • webui/src/UserConfig/Sections/SurfacesConfig.tsx
  • webui/src/UserConfig/SettingsNav.tsx
  • webui/src/UserConfig/advanced.tsx
  • webui/src/UserConfig/buttons.tsx
  • webui/src/UserConfig/general.tsx
  • webui/src/UserConfig/index.tsx
  • webui/src/UserConfig/protocols.tsx
  • webui/src/UserConfig/surfaces.tsx
  • webui/src/routeTree.gen.ts
  • webui/src/routes/_app/settings/surfaces.tsx
  • webui/src/routes/_app/surfaces_/integrations/index.tsx
  • webui/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.

Comment thread webui/src/Instances/AddInstanceLimit.ts Outdated
@coderabbitai

coderabbitai Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews paused.

bryce-seifert and others added 14 commits October 4, 2026 10:55
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.
@bryce-seifert

Copy link
Copy Markdown
Member Author

@Julusian @krocheck

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:

  • dark more!
  • Top bar is back, with a reduced height. I do agree I think it's nice to keep. I put some additional items up there like dark mode switcher and search as well, which I think might make more sense than sidebar?
  • All of the split panels should share a similar styling now, and be more compact vertically with labels on the left. I have not yet forced module config layouts, however
  • All sections should have a sensible max width to avoid being to hard to follow on larger screens
  • Split some additional settings sections into the split panel format, including protocols and advanced. Also moved overall surface settings from Surfaces to Settings area
  • Tried to streamline adding notes to the various places to a similar style
  • Moved Action Recorder to it's own page
    ...and I'm sure there's more but those are the big ones.

@Julusian Julusian added this to the v5.2 milestone Oct 6, 2026

This branch has not been deployed

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

[BUG] Sidebar has inconsistent collapse chevrons (Request) Dark mode for the GUI [BUG] Feedback steps wraparound not working

3 participants