mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat: condensed top bar for session preview editors (#10011)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
const {
|
||||
loading = false,
|
||||
loadingSave = false,
|
||||
dropdownItems = []
|
||||
dropdownItems = [],
|
||||
unifiedSize = 'md'
|
||||
}: {
|
||||
loading?: boolean
|
||||
loadingSave?: boolean
|
||||
@@ -14,6 +15,7 @@
|
||||
label: string
|
||||
onClick: () => void
|
||||
}>
|
||||
unifiedSize?: 'sm' | 'md' | 'lg'
|
||||
} = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -28,7 +30,7 @@
|
||||
disabled={loading}
|
||||
loading={loadingSave}
|
||||
variant="accent"
|
||||
unifiedSize="md"
|
||||
{unifiedSize}
|
||||
startIcon={{ icon: Save }}
|
||||
on:click={() => dispatch('save')}
|
||||
{dropdownItems}
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
* inline. Breadcrumb navigation still works — only the rename UI is
|
||||
* gated. */
|
||||
pathEditable?: boolean
|
||||
/** When true, the whole path/breadcrumb row (and its pen popover) is
|
||||
* dropped, leaving only the summary. Used by the condensed session-
|
||||
* preview top bar to save vertical room. */
|
||||
hidePath?: boolean
|
||||
/** Workspace whose items the breadcrumb picker lists. Session live
|
||||
* editors pass their acting workspace so the picker isn't scoped to the
|
||||
* navigation workspace; falls back to $workspaceStore in the picker. */
|
||||
@@ -60,6 +64,7 @@
|
||||
penVisibility = 'hover',
|
||||
summaryEditable = true,
|
||||
pathEditable = true,
|
||||
hidePath = false,
|
||||
workspaceId
|
||||
}: Props = $props()
|
||||
|
||||
@@ -135,109 +140,111 @@
|
||||
|
||||
<div class="inline-block max-w-full align-top group px-2 py-0.5 leading-tight">
|
||||
<!-- Path row -->
|
||||
<div class="flex items-center max-w-full text-2xs text-secondary font-mono">
|
||||
<nav aria-label="Breadcrumb" class="contents">
|
||||
<BreadcrumbSegment
|
||||
label={KIND_LABEL_LOWER[kind]}
|
||||
initialScope={undefined}
|
||||
initialHighlight={kindKey(kind)}
|
||||
isCurrent={!segments}
|
||||
{currentItem}
|
||||
{workspaceId}
|
||||
onPick={handlePickerSelect}
|
||||
/>
|
||||
{#if segments}
|
||||
{#each segments.dirs as dir, i (dir.fullPath)}
|
||||
{@const dKey = dirKey('all', dir.fullPath)}
|
||||
<BreadcrumbSegment
|
||||
label={dir.name}
|
||||
withChevron
|
||||
extraClass={i === 0 ? 'gap-0.5 min-w-0 max-w-[40%]' : 'gap-0.5 min-w-0'}
|
||||
initialScope={i === 0
|
||||
? { kind: 'all' }
|
||||
: { kind: 'all', dir: segments.dirs[i - 1].fullPath }}
|
||||
initialHighlight={dKey}
|
||||
{currentItem}
|
||||
{workspaceId}
|
||||
onPick={handlePickerSelect}
|
||||
/>
|
||||
{/each}
|
||||
{@const leafKey = leafKeyFor(kind, segments.leaf.fullPath)}
|
||||
{@const leafParent = segments.dirs[segments.dirs.length - 1]?.fullPath}
|
||||
{#if !hidePath}
|
||||
<div class="flex items-center max-w-full text-2xs text-secondary font-mono">
|
||||
<nav aria-label="Breadcrumb" class="contents">
|
||||
<BreadcrumbSegment
|
||||
label={segments.leaf.name}
|
||||
withChevron
|
||||
extraClass="gap-0.5 min-w-0"
|
||||
initialScope={leafParent ? { kind: 'all', dir: leafParent } : { kind: 'all' }}
|
||||
initialHighlight={leafKey}
|
||||
isCurrent
|
||||
label={KIND_LABEL_LOWER[kind]}
|
||||
initialScope={undefined}
|
||||
initialHighlight={kindKey(kind)}
|
||||
isCurrent={!segments}
|
||||
{currentItem}
|
||||
{workspaceId}
|
||||
onPick={handlePickerSelect}
|
||||
/>
|
||||
{/if}
|
||||
</nav>
|
||||
|
||||
<!-- Pen → path-edit popover. Skipped entirely when path editing is
|
||||
disabled so the user doesn't see an inert button. -->
|
||||
{#if pathEditable}
|
||||
<Popover
|
||||
placement="bottom-start"
|
||||
contentClasses="p-4"
|
||||
usePointerDownOutside
|
||||
excludeSelectors=".drawer"
|
||||
disableFocusTrap
|
||||
closeOnOtherPopoverOpen
|
||||
bind:isOpen={() => pathPopoverOpen, setPathPopoverOpen}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="xs"
|
||||
iconOnly
|
||||
startIcon={{ icon: Pencil }}
|
||||
title="Edit path"
|
||||
aria-label="Edit path"
|
||||
btnClasses={penVisibility === 'hover' && !pathPopoverOpen
|
||||
? 'opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100'
|
||||
: ''}
|
||||
{#if segments}
|
||||
{#each segments.dirs as dir, i (dir.fullPath)}
|
||||
{@const dKey = dirKey('all', dir.fullPath)}
|
||||
<BreadcrumbSegment
|
||||
label={dir.name}
|
||||
withChevron
|
||||
extraClass={i === 0 ? 'gap-0.5 min-w-0 max-w-[40%]' : 'gap-0.5 min-w-0'}
|
||||
initialScope={i === 0
|
||||
? { kind: 'all' }
|
||||
: { kind: 'all', dir: segments.dirs[i - 1].fullPath }}
|
||||
initialHighlight={dKey}
|
||||
{currentItem}
|
||||
{workspaceId}
|
||||
onPick={handlePickerSelect}
|
||||
/>
|
||||
{/each}
|
||||
{@const leafKey = leafKeyFor(kind, segments.leaf.fullPath)}
|
||||
{@const leafParent = segments.dirs[segments.dirs.length - 1]?.fullPath}
|
||||
<BreadcrumbSegment
|
||||
label={segments.leaf.name}
|
||||
withChevron
|
||||
extraClass="gap-0.5 min-w-0"
|
||||
initialScope={leafParent ? { kind: 'all', dir: leafParent } : { kind: 'all' }}
|
||||
initialHighlight={leafKey}
|
||||
isCurrent
|
||||
{currentItem}
|
||||
{workspaceId}
|
||||
onPick={handlePickerSelect}
|
||||
/>
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<div class="flex flex-col gap-6 w-[480px]">
|
||||
{#if own}
|
||||
<Path
|
||||
autofocus
|
||||
bind:path
|
||||
initialPath={snapshotPath ?? path ?? ''}
|
||||
namePlaceholder={kind}
|
||||
{kind}
|
||||
size="sm"
|
||||
drawerOffset={4000}
|
||||
/>
|
||||
{#if savedPath && path && path !== savedPath}
|
||||
<Alert
|
||||
type="info"
|
||||
size="xs"
|
||||
title="Deploy the {kind} to make the path change effective."
|
||||
{/if}
|
||||
</nav>
|
||||
|
||||
<!-- Pen → path-edit popover. Skipped entirely when path editing is
|
||||
disabled so the user doesn't see an inert button. -->
|
||||
{#if pathEditable}
|
||||
<Popover
|
||||
placement="bottom-start"
|
||||
contentClasses="p-4"
|
||||
usePointerDownOutside
|
||||
excludeSelectors=".drawer"
|
||||
disableFocusTrap
|
||||
closeOnOtherPopoverOpen
|
||||
bind:isOpen={() => pathPopoverOpen, setPathPopoverOpen}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="xs"
|
||||
iconOnly
|
||||
startIcon={{ icon: Pencil }}
|
||||
title="Edit path"
|
||||
aria-label="Edit path"
|
||||
btnClasses={penVisibility === 'hover' && !pathPopoverOpen
|
||||
? 'opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100'
|
||||
: ''}
|
||||
/>
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<div class="flex flex-col gap-6 w-[480px]">
|
||||
{#if own}
|
||||
<Path
|
||||
autofocus
|
||||
bind:path
|
||||
initialPath={snapshotPath ?? path ?? ''}
|
||||
namePlaceholder={kind}
|
||||
{kind}
|
||||
size="sm"
|
||||
drawerOffset={4000}
|
||||
/>
|
||||
{#if savedPath && path && path !== savedPath}
|
||||
<Alert
|
||||
type="info"
|
||||
size="xs"
|
||||
title="Deploy the {kind} to make the path change effective."
|
||||
/>
|
||||
{/if}
|
||||
{#if onBehalfOfEmail}
|
||||
<Alert type="info" title="Run on behalf of" size="xs">
|
||||
This flow will be redeployed on behalf of you ({$userStore?.email}) instead of {onBehalfOfEmail}
|
||||
</Alert>
|
||||
{/if}
|
||||
{:else}
|
||||
<Label label="Path">
|
||||
<span class="text-xs font-mono text-secondary">{path}</span>
|
||||
<p class="text-2xs text-tertiary mt-1">Only the owner can change the path</p>
|
||||
</Label>
|
||||
{/if}
|
||||
{#if onBehalfOfEmail}
|
||||
<Alert type="info" title="Run on behalf of" size="xs">
|
||||
This flow will be redeployed on behalf of you ({$userStore?.email}) instead of {onBehalfOfEmail}
|
||||
</Alert>
|
||||
{/if}
|
||||
{:else}
|
||||
<Label label="Path">
|
||||
<span class="text-xs font-mono text-secondary">{path}</span>
|
||||
<p class="text-2xs text-tertiary mt-1">Only the owner can change the path</p>
|
||||
</Label>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Summary -->
|
||||
<div class="max-w-full -mt-[2px]" title={summary}>
|
||||
|
||||
@@ -136,9 +136,14 @@
|
||||
loadedFromDraft = false,
|
||||
othersDraftsCount = 0,
|
||||
onOpenOthersDrafts,
|
||||
onTestJob
|
||||
onTestJob,
|
||||
condensedHeader = false
|
||||
}: FlowBuilderProps = $props()
|
||||
|
||||
// Top-bar button size + bar height. Condensed (session preview) uses the
|
||||
// smallest well-supported unified size (`sm`) so the bar is thinner.
|
||||
const headerBtnSize = $derived(condensedHeader ? 'sm' : 'md')
|
||||
|
||||
// The workspace this editor operates on: deploy, save-draft, trigger loading
|
||||
// and the AutosaveIndicator all target it. Falls back to the global store, so
|
||||
// the full-page editor is unchanged; the sessions preview overrides it to the
|
||||
@@ -1101,7 +1106,9 @@
|
||||
<!-- Nav between steps-->
|
||||
<div
|
||||
bind:clientWidth={topbarWidth}
|
||||
class="justify-between flex flex-row items-center pl-2 pr-4 space-x-4 scrollbar-hidden overflow-x-auto max-h-12 h-full relative"
|
||||
class="justify-between flex flex-row items-center pl-2 pr-4 space-x-4 scrollbar-hidden overflow-x-auto h-full relative {condensedHeader
|
||||
? 'max-h-9'
|
||||
: 'max-h-12'}"
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2 min-w-0">
|
||||
<div class="min-w-0 overflow-hidden">
|
||||
@@ -1110,6 +1117,7 @@
|
||||
bind:path={$pathStore}
|
||||
savedPath={initialPath}
|
||||
onBehalfOfEmail={$savedOnBehalfOfEmail}
|
||||
hidePath={condensedHeader}
|
||||
workspaceId={autosaveWorkspace}
|
||||
onNavigate={(item) => onNavigate?.(item)}
|
||||
/>
|
||||
@@ -1132,7 +1140,7 @@
|
||||
<Awareness />
|
||||
{/if}
|
||||
<div class="relative">
|
||||
<Dropdown items={getMoreItems} />
|
||||
<Dropdown items={getMoreItems} size={headerBtnSize} fixedHeight={!condensedHeader} />
|
||||
{#if $tutorialsToDo.includes(getTutorialIndex('flow-live-tutorial')) || $tutorialsToDo.includes(getTutorialIndex('troubleshoot-flow'))}
|
||||
<span
|
||||
class="absolute top-0.5 right-0.5 block w-2 h-2 rounded-full bg-surface-accent-primary pointer-events-none"
|
||||
@@ -1152,7 +1160,7 @@
|
||||
<div title={diffTitle} class={diffDisabled ? 'flex cursor-not-allowed' : 'flex'}>
|
||||
<Button
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
on:click={() => openDiffDrawer()}
|
||||
disabled={diffDisabled}
|
||||
btnClasses={diffDisabled ? 'pointer-events-none' : undefined}
|
||||
@@ -1172,6 +1180,7 @@
|
||||
on:save={async ({ detail }) => await handleSaveFlow(detail)}
|
||||
{loading}
|
||||
{loadingSave}
|
||||
unifiedSize={headerBtnSize}
|
||||
{dropdownItems}
|
||||
/>
|
||||
</div>
|
||||
@@ -1182,6 +1191,7 @@
|
||||
{#snippet previewButtons()}
|
||||
<FlowPreviewButtons
|
||||
{suspendStatus}
|
||||
unifiedSize={headerBtnSize}
|
||||
on:openTriggers={(e) => {
|
||||
select('Trigger')
|
||||
handleSelectTriggerFromKind(triggersState, triggersCount, initialPath, e.detail.kind)
|
||||
|
||||
@@ -140,9 +140,14 @@
|
||||
onResetToDeployed,
|
||||
loadedFromDraft = false,
|
||||
othersDraftsCount = 0,
|
||||
onOpenOthersDrafts
|
||||
onOpenOthersDrafts,
|
||||
condensedHeader = false
|
||||
}: ScriptBuilderProps = $props()
|
||||
|
||||
// Top-bar button size + bar height. Condensed (session preview) uses the
|
||||
// smallest well-supported unified size (`sm`) so the bar is thinner.
|
||||
const headerBtnSize = $derived(condensedHeader ? 'sm' : 'md')
|
||||
|
||||
export function getInitialAndModifiedValues(): SavedAndModifiedValue {
|
||||
return {
|
||||
savedValue: savedScript,
|
||||
@@ -1898,7 +1903,10 @@
|
||||
</Drawer>
|
||||
|
||||
<div class="flex flex-col h-full">
|
||||
<div bind:clientWidth={topbarWidth} class="flex h-12 items-center px-4">
|
||||
<div
|
||||
bind:clientWidth={topbarWidth}
|
||||
class="flex items-center px-4 {condensedHeader ? 'h-9' : 'h-12'}"
|
||||
>
|
||||
<div class="flex gap-2 lg:gap-2 w-full items-center">
|
||||
<div class="flex flex-row items-center gap-2 min-w-0 shrink">
|
||||
<button
|
||||
@@ -1908,7 +1916,7 @@
|
||||
metadataOpen = true
|
||||
}}
|
||||
>
|
||||
<LanguageIcon lang={script.language} size={24} />
|
||||
<LanguageIcon lang={script.language} size={condensedHeader ? 18 : 24} />
|
||||
</button>
|
||||
{#if customUi?.topBar?.path != false}
|
||||
<div class="min-w-0 overflow-hidden">
|
||||
@@ -1919,6 +1927,7 @@
|
||||
kind="script"
|
||||
summaryEditable={customUi?.topBar?.editableSummary != false}
|
||||
pathEditable={customUi?.topBar?.editablePath != false}
|
||||
hidePath={condensedHeader}
|
||||
workspaceId={autosaveWorkspace}
|
||||
onNavigate={(item) => onNavigate?.(item)}
|
||||
/>
|
||||
@@ -1954,7 +1963,7 @@
|
||||
aiId="script-builder-settings"
|
||||
aiDescription="Script builder settings to configure metadata, runtime, triggers, and generated UI."
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
on:click={() => (metadataOpen = true)}
|
||||
startIcon={{ icon: Settings }}
|
||||
iconOnly={compactTopbar}
|
||||
@@ -1977,7 +1986,7 @@
|
||||
<div title={diffTitle} class={diffDisabled ? 'flex cursor-not-allowed' : 'flex'}>
|
||||
<Button
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
on:click={() => openDiffDrawer()}
|
||||
disabled={diffDisabled}
|
||||
btnClasses={diffDisabled ? 'pointer-events-none' : undefined}
|
||||
@@ -1995,7 +2004,7 @@
|
||||
{#snippet buttonReplacement()}
|
||||
<Button
|
||||
nonCaptureEvent
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
variant="subtle"
|
||||
startIcon={{ icon: EllipsisVertical }}
|
||||
iconOnly
|
||||
@@ -2015,6 +2024,7 @@
|
||||
nullTag={script.language}
|
||||
placeholder={customUi?.tagSelectPlaceholder}
|
||||
bind:tag={script.tag}
|
||||
size={headerBtnSize}
|
||||
workspaceId={opWorkspace}
|
||||
/>
|
||||
</div>
|
||||
@@ -2027,6 +2037,7 @@
|
||||
<DeployButton
|
||||
loading={!fullyLoaded}
|
||||
{loadingSave}
|
||||
unifiedSize={headerBtnSize}
|
||||
dropdownItems={computeDropdownItems(initialPath, savedScript)}
|
||||
on:save={({ detail }) => handleEditScript(false, detail)}
|
||||
/>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
disabled = false,
|
||||
placeholder,
|
||||
inputClass,
|
||||
size = 'md',
|
||||
workspaceId = undefined
|
||||
}: {
|
||||
tag: string | undefined
|
||||
@@ -27,6 +28,9 @@
|
||||
language?: string
|
||||
class?: string
|
||||
inputClass?: string
|
||||
/** Forwarded to the underlying Select — controls the input height. The
|
||||
* condensed session top bar passes `sm` to match its smaller buttons. */
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
// Workspace to read custom tags and worker availability from. Defaults to
|
||||
// $workspaceStore. Session editors act on a workspace that differs from the
|
||||
// navigation one, so they pass their effective workspace to keep the tag
|
||||
@@ -164,6 +168,7 @@
|
||||
clearable
|
||||
class="w-full"
|
||||
bind:open
|
||||
{size}
|
||||
{inputClass}
|
||||
{disabled}
|
||||
placeholder={nullTag ? nullTag : (placeholder ?? 'lang default')}
|
||||
|
||||
@@ -62,4 +62,8 @@ export type FlowBuilderProps = {
|
||||
// Fired whenever a test run is started from the flow editor, with the
|
||||
// preview job id. Used by whitelabel embedders to track test jobs.
|
||||
onTestJob?: (e: { jobId: string }) => void
|
||||
// Condensed top bar: smaller (sm) buttons, a shorter bar, and the
|
||||
// EditorHeader's path/breadcrumb row dropped (summary only). Used by the
|
||||
// session preview to save vertical room.
|
||||
condensedHeader?: boolean
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import type { ButtonType } from '$lib/components/common/button/model'
|
||||
|
||||
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
|
||||
import FlowPreviewContent from '$lib/components/FlowPreviewContent.svelte'
|
||||
@@ -18,6 +19,7 @@
|
||||
onJobDone?: () => void
|
||||
localModuleStates?: Record<string, GraphModuleState>
|
||||
suspendStatus: StateStore<Record<string, { job: Job; nb: number }>>
|
||||
unifiedSize?: ButtonType.UnifiedSize
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -25,7 +27,8 @@
|
||||
onRunPreview,
|
||||
onJobDone,
|
||||
localModuleStates = $bindable({}),
|
||||
suspendStatus
|
||||
suspendStatus,
|
||||
unifiedSize = 'md'
|
||||
}: Props = $props()
|
||||
|
||||
const { selectionManager } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
@@ -143,7 +146,7 @@
|
||||
<Button
|
||||
variant="accent-secondary"
|
||||
wrapperClasses="whitespace-nowrap"
|
||||
unifiedSize="md"
|
||||
{unifiedSize}
|
||||
on:click={() => {
|
||||
previewMode = 'whole'
|
||||
previewOpen = !previewOpen
|
||||
|
||||
@@ -132,6 +132,10 @@
|
||||
// prop for the same reason as `onRestore` — `on:savedNewAppPath` forwarding
|
||||
// through these runes-mode components is dropped.
|
||||
onSavedNewAppPath?: (path: string) => void
|
||||
// Condensed top bar: smaller (sm) buttons, a shorter bar, and the
|
||||
// EditorHeader's path/breadcrumb row dropped (summary only). Used by the
|
||||
// session preview to save vertical room.
|
||||
condensedHeader?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -162,7 +166,8 @@
|
||||
onRuntimeLogRequester = undefined,
|
||||
onRunsProvider = undefined,
|
||||
onRestore,
|
||||
onSavedNewAppPath
|
||||
onSavedNewAppPath,
|
||||
condensedHeader = false
|
||||
}: Props = $props()
|
||||
export const version: number | undefined = undefined
|
||||
|
||||
@@ -1678,6 +1683,7 @@
|
||||
onOpenYamlEditor={() => yamlEditorDrawer?.openDrawer()}
|
||||
sidebarCollapsed={sidebarCollapsed.val}
|
||||
onToggleSidebar={() => (sidebarCollapsed.val = !sidebarCollapsed.val)}
|
||||
{condensedHeader}
|
||||
/>
|
||||
|
||||
<RawAppYamlEditor
|
||||
|
||||
@@ -137,6 +137,10 @@
|
||||
onOpenYamlEditor?: () => void
|
||||
sidebarCollapsed?: boolean
|
||||
onToggleSidebar?: () => void
|
||||
/** Condensed top bar: smaller (sm) buttons, a shorter bar, and the
|
||||
* EditorHeader's path/breadcrumb row dropped (summary only). Used by the
|
||||
* session preview to save vertical room. */
|
||||
condensedHeader?: boolean
|
||||
onNavigate?: (item: import('$lib/components/workspacePicker').WorkspaceItem) => void
|
||||
liveEditorDraftStoragePath?: string
|
||||
/** Indicator-only overrides for the sessions preview: the AutosaveIndicator
|
||||
@@ -194,6 +198,7 @@
|
||||
onOpenYamlEditor = undefined,
|
||||
sidebarCollapsed = false,
|
||||
onToggleSidebar = undefined,
|
||||
condensedHeader = false,
|
||||
onNavigate = undefined,
|
||||
liveEditorDraftStoragePath = undefined,
|
||||
autosaveWorkspace = undefined,
|
||||
@@ -282,6 +287,10 @@
|
||||
let topbarWidth = $state(0)
|
||||
const compactTopbar = $derived(topbarWidth > 0 && topbarWidth < 720)
|
||||
|
||||
// Top-bar button size + bar height. Condensed (session preview) uses the
|
||||
// smallest well-supported unified size (`sm`) so the bar is thinner.
|
||||
const headerBtnSize = $derived(condensedHeader ? 'sm' : 'md')
|
||||
|
||||
async function publishToHub() {
|
||||
if (!app) return
|
||||
publishingToHub = true
|
||||
@@ -770,7 +779,9 @@
|
||||
|
||||
<div
|
||||
bind:clientWidth={topbarWidth}
|
||||
class="flex flex-row justify-between gap-2 gap-y-2 px-2 items-center overflow-y-visible overflow-x-auto max-h-12 h-12 shrink-0"
|
||||
class="flex flex-row justify-between gap-2 gap-y-2 px-2 items-center overflow-y-visible overflow-x-auto shrink-0 {condensedHeader
|
||||
? 'max-h-9 h-9'
|
||||
: 'max-h-12 h-12'}"
|
||||
>
|
||||
<!-- Identity block: shrinks/truncates first so the cloud indicator and the
|
||||
action buttons stay visible. Without min-w-0 the breadcrumb + summary
|
||||
@@ -794,6 +805,7 @@
|
||||
savedPath={appPath || newPath || undefined}
|
||||
kind="app"
|
||||
raw_app
|
||||
hidePath={condensedHeader}
|
||||
workspaceId={autosaveWorkspace}
|
||||
onNavigate={(item) => (onNavigate ? onNavigate(item) : goto(editPathFor(item)))}
|
||||
/>
|
||||
@@ -822,7 +834,7 @@
|
||||
{#snippet buttonReplacement()}
|
||||
<Button
|
||||
nonCaptureEvent
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
variant="subtle"
|
||||
startIcon={{ icon: EllipsisVertical }}
|
||||
iconOnly
|
||||
@@ -843,7 +855,7 @@
|
||||
>
|
||||
<Button
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
on:click={() => openDiffDrawer()}
|
||||
disabled={!savedApp || newApp || savedApp?.no_deployed === true}
|
||||
btnClasses={!savedApp || newApp || savedApp?.no_deployed === true
|
||||
@@ -865,7 +877,7 @@
|
||||
jobsDrawerOpen = true
|
||||
}}
|
||||
color="light"
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
variant="default"
|
||||
btnClasses="relative"
|
||||
>
|
||||
@@ -900,7 +912,7 @@
|
||||
>
|
||||
{#snippet fallback()}
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
variant="default"
|
||||
onClick={() => aiChatManager.toggleOpen()}
|
||||
startIcon={{ icon: WandSparkles }}
|
||||
@@ -915,7 +927,7 @@
|
||||
loading={loading.save}
|
||||
startIcon={{ icon: Save }}
|
||||
on:click={save}
|
||||
unifiedSize="md"
|
||||
unifiedSize={headerBtnSize}
|
||||
variant="accent"
|
||||
dropdownItems={appPath != ''
|
||||
? () => [
|
||||
|
||||
@@ -92,4 +92,8 @@ export interface ScriptBuilderProps {
|
||||
othersDraftsCount?: number
|
||||
// Wired by the route to flip the OtherUsersDraftsModal open.
|
||||
onOpenOthersDrafts?: () => void
|
||||
// Condensed top bar: smaller (sm) buttons, a shorter bar, and the
|
||||
// EditorHeader's path/breadcrumb row dropped (summary only). Used by the
|
||||
// session preview to save vertical room.
|
||||
condensedHeader?: boolean
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
bind:savedFlow={cell.saved.val}
|
||||
{diffDrawer}
|
||||
{onNavigate}
|
||||
condensedHeader={true}
|
||||
customUi={{ topBar: { aiBuilder: false } }}
|
||||
onDeploy={() => {
|
||||
// FlowBuilder has no deploy toast and the session stays put, so toast
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
newApp={!cell.saved.val || cell.saved.val.no_deployed === true}
|
||||
{diffDrawer}
|
||||
{onNavigate}
|
||||
condensedHeader={true}
|
||||
onResetToDeployed={reloadDeployed}
|
||||
onDeploy={(e) => {
|
||||
// Sync the preview to deployed (raw apps deploy only from this editor).
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
neverShowMeta={true}
|
||||
fullyLoaded={!cell.slot.loading}
|
||||
disableHistoryChange={true}
|
||||
condensedHeader={true}
|
||||
{diffDrawer}
|
||||
{onNavigate}
|
||||
{initialTestPanelCollapsed}
|
||||
|
||||
Reference in New Issue
Block a user