Files
windmill/frontend/src/lib/components/raw_apps/RawAppModules.svelte
T
GuilhemandClaude Opus 4.7 b0ed27096d feat(editors): responsive top-bars + collapsible raw-app sidebar (#9237)
* feat(editors): responsive top-bars + script test-pane pixel-min + flow graph overlay

Editor top bars now collapse on narrow widths (measured via container
clientWidth, not viewport — they live inside drawers / session panes
where the viewport stays wide):

- FlowBuilder: Diff + Save draft fold into the ellipsis menu when
  the top bar narrows below 720px (Save draft keeps its ⌘S / Ctrl+S
  shortcut indicator). Test-flow button moves out of the top bar
  and into a graph-pane overlay matching the dev page; the overlay
  position flips from top-2 right-2 to top-14 left-1/2 when the
  graph pane itself is narrower than 800px. FlowEditor exposes a
  graphOverlay snippet prop for that.
- ScriptBuilder: Settings + Draft labels collapse to icon-only;
  a new DropdownV2 ellipsis surfaces Tag / Settings / Save draft
  when even icons don't fit. The ellipsis itself uses variant=subtle.
- AppEditorHeader / RawAppEditorHeader: fullscreen / dark-mode /
  breakpoint toggle group + Debug-runs / Jobs buttons hide; Save
  draft moves into the Deploy dropdown.
- EditorBar: a "Helpers" DropdownV2 collapse for Context var /
  Variable / S3 / Resource / Git repo / Resource type / Database /
  Ducklake / Data table / Reset when the bar narrows below 800px
  (EDITOR_BAR_HELPERS_COMPACT_THRESHOLD). Above that, the existing
  icon-only mode (1420px threshold) still applies.
- ScriptEditor's test pane gets a pixel-based minimum width (400px)
  derived from the splitpane's clientWidth. The Pane uses Svelte 5
  function-binding so the splitter writes to a raw $state while the
  splitpane reads the clamped derived value — no $effect, no
  release-time bounce, drag stops at the boundary. Cap raised to
  80% so the test pane can take most of the editor on very narrow
  layouts while leaving a sliver of code visible.
- VS Code button on ScriptEditor: collapses to icon-only below the
  EDITOR_BAR_WIDTH_THRESHOLD (1420px) instead of being hidden
  entirely by viewport `lg:` breakpoint; hidden completely when the
  editor is rendered inside a session pane.
- AI wand button on ScriptEditor + RawAppEditorHeader: hidden inside
  a session pane (detected via `getContext('aiChatManager')`) — the
  session owns its own AI chat.
- DeployButton: drops the unused `newFlow` gate (callers updated).
- FlowDiffViewer / FlowGraphDiffViewer: inlineDiff prop forwarding
  + onHeight callback on FlowGraphV2 so diff viewers can equalize
  side-by-side graph heights.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ui: unify Debug / wand / test-toggle button sizes + HideButton defaults

Two small consistency passes on shared button components:

- ScriptEditor's Debug, AI wand and Test-panel-toggle buttons all
  use unifiedSize="sm" so they line up in the toolbar; Test toggle
  switches from custom marine btnClasses to variant="accent-secondary".
  HideButton gains a passthrough unifiedSize prop so the wand and
  test toggle can match Debug without overriding btnClasses.
- HideButton's own defaults shift to variant="subtle" + sm
  unifiedSize, dropping the legacy color="light" / variant="contained"
  + tailwind-merge background overlay; the selected (hidden) state
  is now a tinted wrapper div instead of overriding btnClasses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ui(script): editor toolbar polish

Small consistency tweaks on the script editor's top-right overlay:

- Lowercase "test" / "Exit debug" panel labels.
- `bg-surface` on the overlay container so the absolute-positioned
  buttons read as a single panel over the graph rather than disjoint
  pills.
- Debug button picks up `destructive={debugMode}` so the active
  state reads as "you're in debug mode" instead of accent.
- Console and "Delegating to git repo" buttons drop the custom
  `btnClasses` border-on-surface treatment and switch from
  `size="xs"` to `unifiedSize="sm"` so they match the other buttons
  in the cluster.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(raw-app): collapsible file sidebar, default-collapsed in session preview

The raw-app editor's left sidebar (file tree, runnables, history) ate a
lot of horizontal space — fine in the standalone editor, painful in the
session preview pane where the chat is already taking half the screen.

Add a small collapse / expand toggle. Persist the user's preference in
localStorage so it sticks across opens.

Two independent localStorage keys via the new `sidebarStorageKey` prop:
- standalone editor: `raw-app-sidebar-collapsed` (default expanded)
- session preview:   `raw-app-sidebar-collapsed-preview` (default collapsed)

Otherwise the two contexts would race for the same key — whichever
opens first would dictate the other's default. Splitting the keys lets
each have its own remembered preference.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fixup(editors): use untyped getContext for AI-chat-manager session detection

The cherry-picks landed `getContext<AIChatManager>('aiChatManager')` to
hide per-editor AI/VSCode buttons when rendered inside a session pane.
The `AIChatManager` class is exported only on the sessions branch (used
for typing session-provided manager overrides). On `main` the manager
file exports only the singleton instance, so importing the class fails
the type-check.

The session-pane detection just needs a truthy/falsy probe — drop the
type parameter and the class import. `inSessionPane` ends up as
`getContext('aiChatManager')` (returns `unknown`, coerced to boolean
via `!!`). Same runtime behaviour, no class-export dependency.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ui(editors): flow test in top bar; ellipsis folds draft/jobs/tutorials

* refactor(app-editor): drop dead AppEditorTutorial button path

* ui(editors): wire compactHelpers in flow-step + raw-app inline editors

* ui(raw-app): sidebar Cmd/Ctrl+B toggle + uppercase section titles

* ui(editors): keep Diff/Settings inline as icon-only when narrow

* fix(editors): address review nits on test-pane/Helpers/thresholds

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:55:20 +00:00

86 lines
2.5 KiB
Svelte

<script lang="ts">
import { Loader2 } from 'lucide-svelte'
import PanelSection, {
SUBTLE_PANEL_TITLE
} from '../apps/editor/settingsPanel/common/PanelSection.svelte'
import TextInput from '../text_input/TextInput.svelte'
export type Modules = {
installed: Record<string, string>
discovered: {
direct: string[]
indirect: string[]
dev: string[]
}
}
let props = $props<{
modules: Modules | undefined
}>()
let search = $state('')
const filteredModules = $derived({
direct: search
? (props.modules?.discovered?.direct?.filter((mod) =>
mod.toLowerCase().includes(search.toLowerCase())
) ?? [])
: (props.modules?.discovered?.direct ?? []),
indirect: search
? (props.modules?.discovered?.indirect?.filter((mod) =>
mod.toLowerCase().includes(search.toLowerCase())
) ?? [])
: (props.modules?.discovered?.indirect ?? []),
dev: search
? (props.modules?.discovered?.dev?.filter((mod) =>
mod.toLowerCase().includes(search.toLowerCase())
) ?? [])
: (props.modules?.discovered?.dev ?? [])
})
</script>
<PanelSection
size="xs"
collapsible
initiallyCollapsed
titlePadding="!text-tertiary"
titleClass={SUBTLE_PANEL_TITLE}
fullHeight={false}
title="packages ({Object.keys(props.modules?.installed ?? {}).length})"
id="app-editor-frontend-panel-modules"
>
<TextInput inputProps={{ placeholder: 'Search packages' }} size="sm" bind:value={search} />
<div class="mt-2 flex flex-col gap-4 w-full">
{#each ['direct', 'indirect', 'dev'] as type}
{@const typeModules = filteredModules[type]}
{#if typeModules.length > 0}
<div class="flex flex-col gap-1">
<div class="text-xs px-2 text-hint text-2xs"
>{type}
<span>({typeModules.length})</span></div
>
{#each typeModules as mod (mod)}
<div class="text-xs px-2 text-primary font-mono flex justify-between w-full"
><div class="truncate">{mod}</div>
<div class="flex items-center gap-1">
{#if props.modules?.installed?.[mod]}
<span class="text-2xs px-2 text-hint">
{props.modules?.installed?.[mod]}
</span>
{:else}
<Loader2 class="w-4 h-4 animate-spin text-tertiary" />
{/if}
</div>
</div>
{/each}
</div>
{/if}
{/each}
{#if filteredModules.direct.length === 0 && filteredModules.indirect.length === 0 && filteredModules.dev.length === 0}
<span class="text-xs px-2 text-hint text-2xs"
>No packages found. Edit <b>package.json</b> to add them.</span
>
{/if}
</div>
</PanelSection>