From 72e678a9238ae91df864c1869a4159ae97f08cad Mon Sep 17 00:00:00 2001 From: Guilhem Lemouel Date: Thu, 1 Oct 2026 03:00:12 -0700 Subject: [PATCH] fix: the app canvas controls stay reachable, and an unnamed item says so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex found the app editor's canvas controls unreachable on an ordinary laptop: the owning route collapsed at 1350px, and a 1440 window with the rail out leaves 1232, so the width, theme and breakpoint toggles were hidden with nothing in the menu to replace them — and the breakpoint is the only way onto the mobile layout. Measured on the band, the toggles are 240px beside 334 of other actions and a ~430 trail, so they fit to about 1050: the threshold is 1100 now, and below it each of the three keeps a menu entry rather than disappearing. An item with no summary read as a bare `·` with an invisible pen after it, since the plain text replaced a field that had a placeholder. It now reads "Add a summary..." in the italic SummaryPathDisplay uses for the same state, and the pen stops hiding when there is nothing to hover. Three more from the review: - `actionsFlexible` says "these actions can give width back", which is true of the Runs filter row and not of the pipeline's row of fixed buttons. - `pathSnapshot ?? (newEditedPath || …)` keeps the `||` chain the five rename sites read and the declaration documents; `??` had made the rest unreachable, since `newEditedPath` is a string that is never undefined. - The band bridged `contexts` onto the actions alone, while the pen that decides whether a path is the caller's to change renders in `summaryContent`. The breadcrumb's `afterName` and the summary are bridged the same way now, so that permission check reads the tree that registered it. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/lib/components/FlowBuilder.svelte | 11 +++-- .../src/lib/components/PageHeaderBar.svelte | 27 +++++++---- .../src/lib/components/ScriptBuilder.svelte | 9 +++- .../apps/editor/AppEditorHeader.svelte | 46 ++++++++++++++++--- .../components/pageHeaderRegistry.svelte.ts | 5 +- .../raw_apps/RawAppEditorHeader.svelte | 11 +++-- .../(logged)/pipeline/[folder]/+page.svelte | 1 - 7 files changed, 85 insertions(+), 25 deletions(-) diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index fcb92ebe95..85532edcb6 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -28,7 +28,8 @@ userPathPrefix, type Item, type StateStore, - type Value + type Value, + emptyString } from '$lib/utils' import { sendUserToast } from '$lib/toast' import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte' @@ -1658,11 +1659,15 @@ it renames. -->
{flowStore.val.summary}{emptyString(flowStore.val.summary) ? 'Add a summary...' : flowStore.val.summary} {#if customUi?.topBar?.editablePath != false} {#if !navHidden}
- + + {#key content?.contexts} + + + + {/key}
{/if} @@ -181,7 +188,11 @@ The row's height matches the sidebar's own header row, so the two read as one ba carries it down with the summary instead of stranding it on the line above. --> {#if item.summaryContent} - {@render item.summaryContent()} + {#key content?.contexts} + + {@render item.summaryContent()} + + {/key} {:else} {item.summary} {/if} diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index 3619f670b0..8be4a05bb9 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -2342,11 +2342,16 @@ named rather than where it is edited. The pen sits after it, at the end of what it renames. -->
- {script.summary}{emptyString(script.summary) ? 'Add a summary...' : script.summary} {#if customUi?.topBar?.editablePath != false} { const w = ownsPageHeader ? pageHeader.barWidth : topbarWidth return w > 0 && w < compactBelow @@ -620,7 +624,33 @@ selectedJobId = $jobs[$jobs.length - 1] } $jobsDrawerOpen = true - }, + } + }, + // The canvas toggles stand down with the bar, and the breakpoint among them is the + // only way onto the mobile layout — so each one keeps an entry here. + { + displayName: $breakpoint === 'sm' ? 'Computer view' : 'Mobile view', + icon: $breakpoint === 'sm' ? Laptop2 : Smartphone, + action: () => ($breakpoint = $breakpoint === 'sm' ? 'lg' : 'sm') + }, + { + displayName: $app?.fullscreen ? 'Centered canvas' : 'Full-width canvas', + icon: $app?.fullscreen ? AlignHorizontalSpaceAround : Expand, + action: () => { + if ($app) $app.fullscreen = !$app.fullscreen + } + }, + { + displayName: + $app?.darkMode === undefined + ? 'Theme: automatic' + : $app.darkMode + ? 'Theme: dark' + : 'Theme: light', + icon: $app?.darkMode === undefined ? SunMoon : $app.darkMode ? Moon : Sun, + // Cycles auto → light → dark, the order the toggle group reads in. + action: () => + setTheme($app?.darkMode === undefined ? false : $app.darkMode ? undefined : true), separatorBottom: true } ] @@ -953,7 +983,7 @@ // will create. Same fallback chain the rename sites read. // Frozen while the pen's popover is open so the trail holds still as the user types. kind: 'app', - path: pathSnapshot ?? newEditedPath ?? $appPath ?? newPath ?? undefined, + path: pathSnapshot ?? (newEditedPath || $appPath || newPath || undefined), summaryContent: appSummary }} actions={appHeaderActions} @@ -994,10 +1024,14 @@ named rather than where it is edited. `title` so one the band truncates can still be read. The pen sits after it, at the end of what it renames. -->
- {$summary}{emptyString($summary) ? 'Add a summary...' : $summary} } diff --git a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte index bee4f9a6b8..cb0f958ccd 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte @@ -3,7 +3,7 @@ import { base } from '$lib/base' import RawAppRecordSession from '$lib/components/workspaceSettings/RawAppRecordSession.svelte' import Button from '$lib/components/common/button/Button.svelte' - import { isMac, userPathPrefix } from '$lib/utils' + import { isMac, userPathPrefix, emptyString } from '$lib/utils' import { editPathFor } from '$lib/components/workspacePicker' import { invalidateWorkspacePaths } from '$lib/components/PathNameAutocomplete.svelte' @@ -943,7 +943,7 @@ // will create — which is why `newEditedPath` refuses the placeholder. Frozen while the // pen's popover is open so the trail holds still as the user types. kind: 'app', - path: pathSnapshot ?? newEditedPath ?? appPath ?? newPath ?? undefined, + path: pathSnapshot ?? (newEditedPath || appPath || newPath || undefined), summaryContent: appSummary }} actions={rawAppHeaderActions} @@ -1025,9 +1025,14 @@ named rather than where it is edited. `title` so one the band truncates can still be read. The pen sits after it, at the end of what it renames. -->
- {summary}{emptyString(summary) ? 'Add a summary...' : summary} {#snippet pipelineFolder()}