mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-06 00:02:30 +00:00
fix(frontend): session Drafts drawer uses raw_app kind for the raw-app diff (#9617)
* fix(frontend): session Drafts drawer uses raw_app kind for the raw-app diff Follow-up to #9601. DraftDiffDrawer mapped a raw_app row back to `app` before calling getDraftDiffValues(), but that helper sends `rawApp:true` only for the exact kind `raw_app` (which a never-deployed raw app needs). With `app` it hit the normal app endpoint and 404'd instead of rendering the added diff. `raw_app` isn't in the deploy-kind maps anyway, so just pass the row kind through. Caught by the Codex auto-review on #9601, which posted after that PR had already merged (locked conversation), so the fix lands separately here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): show friendly draft path + summary for all kinds in session Drafts drawer A never-deployed app/raw_app is parked at a synthetic `u/.../draft_<uuid>` storage path with the user's typed name in the draft JSON's `draft_path`; the Drafts drawer rendered that UUID path. The list endpoint already returns `draft_path` and `summary` for every kind, but `fetchDrafts` dropped them and the drawer only had the lazily-derived summary. Thread both through the shared row: `WorkspaceDiffDrawer` gains optional `displayPath` (shown in tree/header/search, while `path` stays the storage key for value-loading, item keys and edit links) and `summary` (preferred over the value-derived one, shown before the diff loads). `DraftDiffDrawer` populates them from the draft list (`draft_path ?? path`, `summary`). Both fields are opt-in via `?? path` / lazy fallback, so ForkDiffDrawer — the other consumer of the component — is unchanged. The symptom only surfaced for apps/raw apps because their storage path diverges from the friendly name; scripts already kept a readable path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): use friendly display path for single-segment draft tree nodes buildTree splits displayPathOf(d), but the `< 2 parts` branch still named the file node from the storage `path` — a draft whose friendly path is a bare name (no `/`) would show `…/draft_<uuid>` in the sidebar tree. Name it from displayPathOf(d) too, consistent with the rest of the tree/header/search. Addresses Codex and claude review nits on #9617. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7cb5c6e749
commit
46288b6143
@@ -61,7 +61,18 @@
|
||||
const baseKind = it.raw_app ? 'raw_app' : it.kind
|
||||
const kind = DEPLOY_KIND_BY_DRAFT_KIND[baseKind] ?? baseKind
|
||||
donly[`${kind}/${it.path}`] = it.draft_only
|
||||
return { kind, path: it.path, status: it.draft_only ? 'added' : 'modified' }
|
||||
// A never-deployed app/raw_app is parked at a synthetic `…/draft_<uuid>`
|
||||
// storage path with the user's typed name in `draft_path`; show that
|
||||
// (matches the home list) while `path` stays the storage key for loading.
|
||||
// `summary` comes straight from the draft row, so it shows for every kind
|
||||
// up front instead of only after the diff value loads.
|
||||
return {
|
||||
kind,
|
||||
path: it.path,
|
||||
displayPath: it.draft_path ?? it.path,
|
||||
summary: it.summary,
|
||||
status: it.draft_only ? 'added' : 'modified'
|
||||
}
|
||||
})
|
||||
draftOnlyByKey = donly
|
||||
} catch (e) {
|
||||
@@ -75,10 +86,11 @@
|
||||
|
||||
async function loadValues(d: DiffRow): Promise<{ before: unknown; after: unknown }> {
|
||||
const draftOnly = draftOnlyByKey[`${d.kind}/${d.path}`] ?? false
|
||||
// getDraftDiffValues works on the draft itemKind ('app' for raw apps too);
|
||||
// map the deploy-style display kind back to it.
|
||||
const kind: DraftKind =
|
||||
d.kind === 'raw_app' ? 'app' : ((DRAFT_KIND_BY_DEPLOY_KIND[d.kind] ?? d.kind) as DraftKind)
|
||||
// getDraftDiffValues keys on the draft itemKind: `raw_app` must stay
|
||||
// `raw_app` (the helper sends rawApp:true only for that exact kind, which a
|
||||
// never-deployed raw app needs, else it hits the normal app endpoint and
|
||||
// 404s). Only the trigger display kinds map back from their deploy-style names.
|
||||
const kind = (DRAFT_KIND_BY_DEPLOY_KIND[d.kind] ?? d.kind) as DraftKind
|
||||
const { deployed, draft } = await getDraftDiffValues(kind, d.path, workspaceId, draftOnly)
|
||||
// draft_only items have never been deployed → render as "added" (empty
|
||||
// before), matching how the fork drawer renders added items.
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
status: DiffStatus
|
||||
ahead?: number
|
||||
behind?: number
|
||||
/** Human-facing path; defaults to `path`. Lets a draft parked at a
|
||||
* synthetic storage path (`…/draft_<uuid>`) show its friendly typed path
|
||||
* while keys, value-loading and edit links stay keyed on `path`. */
|
||||
displayPath?: string
|
||||
/** Summary supplied by the data source. Preferred over the one derived
|
||||
* from the loaded diff value, and shown before that value loads. */
|
||||
summary?: string
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -88,6 +95,12 @@
|
||||
return `${d.kind}/${d.path}`
|
||||
}
|
||||
|
||||
// Friendly path for display only; `path` stays the storage key everywhere
|
||||
// keys/loads happen, so a never-deployed draft still loads from `…/draft_<uuid>`.
|
||||
function displayPathOf(d: DiffRow): string {
|
||||
return d.displayPath ?? d.path
|
||||
}
|
||||
|
||||
const KIND_LABELS: Record<string, string> = {
|
||||
script: 'Script',
|
||||
flow: 'Flow',
|
||||
@@ -183,9 +196,9 @@
|
||||
}
|
||||
const folderCache = new Map<string, FolderNode>()
|
||||
for (const d of rows) {
|
||||
const parts = d.path.split('/')
|
||||
const parts = displayPathOf(d).split('/')
|
||||
if (parts.length < 2) {
|
||||
root.children.push({ type: 'file', name: d.path, diff: d })
|
||||
root.children.push({ type: 'file', name: displayPathOf(d), diff: d })
|
||||
continue
|
||||
}
|
||||
const scopeKey = parts.slice(0, 2).join('/')
|
||||
@@ -226,8 +239,8 @@
|
||||
}
|
||||
|
||||
function searchableText(d: DiffRow): string {
|
||||
const parts = [d.path, KIND_LABELS[d.kind] ?? d.kind]
|
||||
const s = summaries[itemKey(d)]
|
||||
const parts = [displayPathOf(d), KIND_LABELS[d.kind] ?? d.kind]
|
||||
const s = summaries[itemKey(d)] ?? d.summary
|
||||
if (s) parts.push(s)
|
||||
return parts.join(' ')
|
||||
}
|
||||
@@ -433,12 +446,12 @@
|
||||
<WorkspaceItemRow
|
||||
kind={node.diff.kind as any}
|
||||
uniformHeight
|
||||
summary={summaries[key]}
|
||||
summary={summaries[key] ?? node.diff.summary}
|
||||
secondary={node.name}
|
||||
highlighted={key === highlightedKey}
|
||||
navKey={key}
|
||||
indent={depth * 12 + 20}
|
||||
title={node.diff.path}
|
||||
title={displayPathOf(node.diff)}
|
||||
onclick={() => {
|
||||
highlightedKey = key
|
||||
scrollToDiff(node.diff)
|
||||
@@ -556,6 +569,7 @@
|
||||
{@const StatusIcon = statusIcons[status]}
|
||||
{@const loaded = loadedDiffs[key]}
|
||||
{@const editUrl = editUrlFor?.(d)}
|
||||
{@const dpath = displayPathOf(d)}
|
||||
<details
|
||||
open
|
||||
id={rowId(d)}
|
||||
@@ -573,14 +587,14 @@
|
||||
{#if editUrl}
|
||||
<ExternalEditLink
|
||||
href={editUrl}
|
||||
title={d.path}
|
||||
title={dpath}
|
||||
class="text-xs text-primary font-mono truncate"
|
||||
>
|
||||
<span class="truncate">{d.path}</span>
|
||||
<span class="truncate">{dpath}</span>
|
||||
</ExternalEditLink>
|
||||
{:else}
|
||||
<div class="text-xs text-primary font-mono truncate" title={d.path}>
|
||||
{d.path}
|
||||
<div class="text-xs text-primary font-mono truncate" title={dpath}>
|
||||
{dpath}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user