mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 08:05:44 +00:00
feat(raw_apps): surface UI Builder build errors over the preview pane (#9316)
* feat(raw_apps): surface UI Builder build errors over the preview pane Companion to the matching change in the UI Builder repo (see linked PR), which stops rendering the build-error overlay over the VS Code editor iframe and instead emits a `buildError` postMessage on every build (message: undefined on success to clear). Listen for that message on the existing window message handler (already source-gated by the UI Builder iframe), store it in a `buildError` $state, and surface it in two places: * A red banner over the preview iframe, sibling to the existing logs overlay (`top-12 left-2 right-2 z-20` so it clears the tab bar) — failures appear right where the user looks for the rendered output. * The Preview tab's icon and label tint red (`text-red-600 dark:text-red-400`, matching the existing error convention in raw_apps) — important in single-tab mode where the preview pane is collapsed to 0px and the banner would be hidden. Done by mapping `leftPaneTabs` / `rightPaneTabs` through a small `tintPreviewOnError` helper so the source-of-truth `tabs` array is untouched (DnD, ordering, fallback selection keep using the original previewTab object). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(raw_apps): use Alert component for the build-error banner Replace the hand-rolled red div with the shared `Alert` component (`type="error"`, `title="Build failed"`). The error text stays in a `<pre>` child so multi-line bundler output keeps its formatting, with `max-h-60` so a long error never takes over the whole preview pane. The absolute-positioned wrapper (`top-12 left-2 right-2 z-20`) and the `role="alert"` move to that wrapper so the Alert component itself stays unstyled at the call site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(raw_apps): solid bg-surface backing behind build-error Alert The Alert's error background is semi-transparent in dark mode (`bg-red-900/40` in `common/alert/model.ts`), so the preview iframe shows through when the banner is laid over it. Add a `::before` pseudo on the Alert root with `bg-surface` (matched `rounded-md`, `-z-10` so it sits behind the red bg) to give it a solid plate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(raw_apps): isolate banner stacking context, DRY tab tint chain Two small follow-ups from review: * Add `isolate` to the build-error banner wrapper so the `before:-z-10` pseudo's stacking context is pinned locally — it works today because `position: absolute` + `z-20` creates one, but `isolate` makes the dependency self-documenting and survives a future refactor that removes the explicit `z-20`. * Extract `tintTabs = (ts) => ts.map(tintPreviewOnError)` so the two `$derived` blocks for leftPaneTabs / rightPaneTabs read identically. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(raw_apps): trim build-error overlay comments Per review feedback. Keep only the load-bearing facts (bg-surface backs the Alert's translucent red, isolate pins the pseudo stacking, the `message: undefined` clear convention) and drop the prose context that duplicated what the code already shows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(raw_apps): bump bundled ui_builder to 00c9834 Brings in the postMessage emission from windmill-labs/windmill-code-ui-builder#9 (merged) so this PR's host listener actually receives `buildError` events. SHA verified against the R2 artifact. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
tristantr
co-authored by
Claude Opus 4.7
parent
106e77e8d2
commit
45bae59e9c
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"baseUrl": "https://pub-06154ed168a24e73a86ab84db6bf15d8.r2.dev",
|
||||
"version": "b4f6219",
|
||||
"sha256": "69575342aab968fc32a89d3410c21bf888b0f00ce5c68fe80936d3adc1359b36"
|
||||
"version": "00c9834",
|
||||
"sha256": "5757e5b9cbf79c20d507dc4c588640368e84b873cb48f3806ca8c67fd1aa625f"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import RawAppEditorHeader from './RawAppEditorHeader.svelte'
|
||||
import RawAppYamlEditor, { type RawAppYamlUpdate } from './RawAppYamlEditor.svelte'
|
||||
import type Drawer from '../common/drawer/Drawer.svelte'
|
||||
import Alert from '../common/alert/Alert.svelte'
|
||||
import { type Policy, WorkspaceService } from '$lib/gen'
|
||||
import DiffDrawer from '../DiffDrawer.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
@@ -195,6 +196,9 @@
|
||||
// them as an overlay inside the preview pane (right side) so they're
|
||||
// visually tied to the build output, not to the source editor.
|
||||
let logs = $state('')
|
||||
|
||||
// Latest UI Builder error; cleared on next successful build.
|
||||
let buildError = $state<string | undefined>(undefined)
|
||||
let logsCollapsed = $state(false)
|
||||
let logsDiv: HTMLDivElement | undefined = $state(undefined)
|
||||
$effect(() => {
|
||||
@@ -229,13 +233,20 @@
|
||||
? 'file'
|
||||
: 'runnable'
|
||||
)
|
||||
// Tint the Preview tab red so the error is visible when Preview isn't active.
|
||||
function tintPreviewOnError(t: TabItem): TabItem {
|
||||
if (t.id !== PREVIEW_TAB_ID || !buildError) return t
|
||||
const errClass = 'text-red-600 dark:text-red-400'
|
||||
return { ...t, iconClass: errClass, labelClass: errClass }
|
||||
}
|
||||
const tintTabs = (ts: TabItem[]) => ts.map(tintPreviewOnError)
|
||||
// Single mode: both bars mirror the full list (the visible pane carries
|
||||
// every tab). Split mode: left = files/runnables, right = Preview only.
|
||||
const leftPaneTabs = $derived<TabItem[]>(
|
||||
splitWithPreview ? tabs.filter((t) => t.id !== PREVIEW_TAB_ID) : tabs
|
||||
tintTabs(splitWithPreview ? tabs.filter((t) => t.id !== PREVIEW_TAB_ID) : tabs)
|
||||
)
|
||||
const rightPaneTabs = $derived<TabItem[]>(
|
||||
splitWithPreview ? tabs.filter((t) => t.id === PREVIEW_TAB_ID) : tabs
|
||||
tintTabs(splitWithPreview ? tabs.filter((t) => t.id === PREVIEW_TAB_ID) : tabs)
|
||||
)
|
||||
// In split mode the right bar always highlights Preview, regardless of the
|
||||
// left pane's active file/runnable.
|
||||
@@ -938,6 +949,12 @@
|
||||
return
|
||||
}
|
||||
|
||||
// `message: undefined` arrives on the next successful build and clears the banner.
|
||||
if (fromUiBuilder && e.data.type === 'buildError') {
|
||||
buildError = typeof e.data.message === 'string' ? e.data.message : undefined
|
||||
return
|
||||
}
|
||||
|
||||
// Inspector events come exclusively from the preview iframe.
|
||||
if (fromPreview && e.data.type === 'inspectorSelect') {
|
||||
inspectorElement = e.data.element as InspectorElementInfo
|
||||
@@ -1557,6 +1574,20 @@
|
||||
src="/ui_builder/app-preview.html"
|
||||
class="w-full flex-1 block"
|
||||
></iframe>
|
||||
{#if buildError}
|
||||
<!-- top-12 clears the tab bar; `before:bg-surface` backs the
|
||||
Alert's translucent red; `isolate` pins the pseudo's stacking context. -->
|
||||
<div class="absolute top-12 left-2 right-2 z-20 isolate" role="alert">
|
||||
<Alert
|
||||
type="error"
|
||||
title="Build failed"
|
||||
class="relative before:absolute before:inset-0 before:-z-10 before:rounded-md before:bg-surface before:content-['']"
|
||||
>
|
||||
<pre
|
||||
class="overflow-auto whitespace-pre-wrap text-xs max-h-60">{buildError}</pre>
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
{#if logs}
|
||||
<div
|
||||
class="absolute right-0 bottom-0 z-20 max-w-[500px] w-full flex flex-col text-xs p-1 border border-border-light rounded-tl-md bg-surface text-primary {logsCollapsed
|
||||
|
||||
Reference in New Issue
Block a user