mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 00:03:00 +00:00
fix: the app canvas controls stay reachable, and an unnamed item says so
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) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
24223ef9cd
commit
72e678a923
@@ -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. -->
|
||||
<div class="group flex items-center gap-1 min-w-0">
|
||||
<span
|
||||
class="min-w-0 truncate text-xs font-medium text-emphasis"
|
||||
title={flowStore.val.summary}>{flowStore.val.summary}</span
|
||||
class="min-w-0 truncate text-xs {emptyString(flowStore.val.summary)
|
||||
? 'text-tertiary italic font-normal'
|
||||
: 'font-medium text-emphasis'}"
|
||||
title={flowStore.val.summary}
|
||||
>{emptyString(flowStore.val.summary) ? 'Add a summary...' : flowStore.val.summary}</span
|
||||
>
|
||||
{#if customUi?.topBar?.editablePath != false}
|
||||
<PathEditPopover
|
||||
penVisibility={emptyString(flowStore.val.summary) ? 'always' : 'hover'}
|
||||
bind:summary={flowStore.val.summary}
|
||||
summaryEditable={customUi?.topBar?.editableSummary != false}
|
||||
bind:path={$pathStore}
|
||||
|
||||
@@ -162,13 +162,20 @@ The row's height matches the sidebar's own header row, so the two read as one ba
|
||||
navigate the host's workspace. -->
|
||||
{#if !navHidden}
|
||||
<div class={twMerge('flex min-w-0', phone ? 'shrink min-w-[10rem]' : 'shrink-[0.1]')}>
|
||||
<NavBreadcrumb
|
||||
{item}
|
||||
{section}
|
||||
{narrow}
|
||||
afterName={content?.afterName}
|
||||
actingWorkspaceId={content?.actingWorkspaceId}
|
||||
/>
|
||||
<!-- Bridged like the actions below: what a page hangs off its own name renders here, out
|
||||
of the tree that named it, and the pen in there asks that tree who the acting user is
|
||||
before it offers to rename anything. -->
|
||||
{#key content?.contexts}
|
||||
<ContextBridge contexts={content?.contexts}>
|
||||
<NavBreadcrumb
|
||||
{item}
|
||||
{section}
|
||||
{narrow}
|
||||
afterName={content?.afterName}
|
||||
actingWorkspaceId={content?.actingWorkspaceId}
|
||||
/>
|
||||
</ContextBridge>
|
||||
{/key}
|
||||
</div>
|
||||
{/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. -->
|
||||
<span class="shrink-0 text-hint/40 text-xs px-0.5" aria-hidden="true">·</span>
|
||||
{#if item.summaryContent}
|
||||
{@render item.summaryContent()}
|
||||
{#key content?.contexts}
|
||||
<ContextBridge contexts={content?.contexts}>
|
||||
{@render item.summaryContent()}
|
||||
</ContextBridge>
|
||||
{/key}
|
||||
{:else}
|
||||
<span class="min-w-0 truncate text-xs font-medium text-emphasis">{item.summary}</span>
|
||||
{/if}
|
||||
|
||||
@@ -2342,11 +2342,16 @@
|
||||
named rather than where it is edited. The pen sits after it, at the end of what it
|
||||
renames. -->
|
||||
<div class="group flex items-center gap-1 min-w-0">
|
||||
<span class="min-w-0 truncate text-xs font-medium text-emphasis" title={script.summary}
|
||||
>{script.summary}</span
|
||||
<span
|
||||
class="min-w-0 truncate text-xs {emptyString(script.summary)
|
||||
? 'text-tertiary italic font-normal'
|
||||
: 'font-medium text-emphasis'}"
|
||||
title={script.summary}
|
||||
>{emptyString(script.summary) ? 'Add a summary...' : script.summary}</span
|
||||
>
|
||||
{#if customUi?.topBar?.editablePath != false}
|
||||
<PathEditPopover
|
||||
penVisibility={emptyString(script.summary) ? 'always' : 'hover'}
|
||||
bind:summary={script.summary}
|
||||
summaryEditable={customUi?.topBar?.editableSummary != false}
|
||||
bind:path={script.path}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { discardDraftAfterDeploy } from '$lib/userDraftToast'
|
||||
import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte'
|
||||
import { enterpriseLicense, userStore, userWorkspaces, workspaceStore } from '$lib/stores'
|
||||
import { isMac, type Item, userPathPrefix } from '$lib/utils'
|
||||
import { isMac, type Item, userPathPrefix, emptyString } from '$lib/utils'
|
||||
import { random_adj } from '$lib/components/random_positive_adjetive'
|
||||
import {
|
||||
AlignHorizontalSpaceAround,
|
||||
@@ -264,7 +264,11 @@
|
||||
// In the page header the buttons share the row with the breadcrumb, so they shed the canvas
|
||||
// toggles and fold Debug runs into the menu sooner: the whole group is ~840px and the trail
|
||||
// with the summary takes ~430px of the same row.
|
||||
const compactBelow = $derived(ownsPageHeader ? 1350 : 720)
|
||||
// Measured on the band: the canvas toggles are 240px, the rest of the actions 334, and the trail
|
||||
// with the summary about 430 — so the whole row fits down to ~1050. 1350 hid the toggles on an
|
||||
// ordinary laptop (a 1440 window with the rail out leaves 1232), and the menu below is what
|
||||
// keeps them reachable under this.
|
||||
const compactBelow = $derived(ownsPageHeader ? 1100 : 720)
|
||||
const compactTopbar = $derived.by(() => {
|
||||
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. -->
|
||||
<div class="group flex items-center gap-1 min-w-0">
|
||||
<span class="min-w-0 truncate text-xs font-medium text-emphasis" title={$summary}
|
||||
>{$summary}</span
|
||||
<span
|
||||
class="min-w-0 truncate text-xs {emptyString($summary)
|
||||
? 'text-tertiary italic font-normal'
|
||||
: 'font-medium text-emphasis'}"
|
||||
title={$summary}>{emptyString($summary) ? 'Add a summary...' : $summary}</span
|
||||
>
|
||||
<PathEditPopover
|
||||
penVisibility={emptyString($summary) ? 'always' : 'hover'}
|
||||
bind:summary={$summary}
|
||||
bind:path={newEditedPath}
|
||||
bind:snapshotPath={pathSnapshot}
|
||||
|
||||
@@ -50,8 +50,9 @@ export type PageHeaderContent = {
|
||||
* session's side panel. The band stops there instead of running over it, and the band floats
|
||||
* above the page rather than pushing it down, so that column starts at the top. */
|
||||
barRightInset?: number
|
||||
/** Contexts those buttons look up. They render under the header, not under the page that
|
||||
* wrote them, so anything the page's tree provides has to travel with them. */
|
||||
/** Contexts this registration's snippets look up — its actions, what it hangs after the name,
|
||||
* and its summary. They all render under the header rather than under the page that wrote
|
||||
* them, so anything the page's tree provides has to travel with them. */
|
||||
contexts?: Map<any, any>
|
||||
}
|
||||
|
||||
|
||||
@@ -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. -->
|
||||
<div class="group flex items-center gap-1 min-w-0">
|
||||
<span class="min-w-0 truncate text-xs font-medium text-emphasis" title={summary}>{summary}</span
|
||||
<span
|
||||
class="min-w-0 truncate text-xs {emptyString(summary)
|
||||
? 'text-tertiary italic font-normal'
|
||||
: 'font-medium text-emphasis'}"
|
||||
title={summary}>{emptyString(summary) ? 'Add a summary...' : summary}</span
|
||||
>
|
||||
<PathEditPopover
|
||||
penVisibility={emptyString(summary) ? 'always' : 'hover'}
|
||||
bind:summary
|
||||
bind:path={newEditedPath}
|
||||
bind:snapshotPath={pathSnapshot}
|
||||
|
||||
@@ -2392,7 +2392,6 @@
|
||||
section={{ label: mode === 'edit' ? 'Pipeline editor' : 'Pipeline' }}
|
||||
afterName={pipelineFolder}
|
||||
actions={pipelineActions}
|
||||
actionsFlexible
|
||||
/>
|
||||
|
||||
{#snippet pipelineFolder()}
|
||||
|
||||
Reference in New Issue
Block a user