* feat(frontend): adapt AI-chat/sessions drafts to DB-backed model
PR #9351 dropped UserDraft's localStorage layer; the chat adapter's
synchronous save->read-back threw "Could not read written draft". The
adapter now treats the backend as source of truth (in-tab cell used
opportunistically for live-preview coherence) with conflict-on-save,
and read tools fall back to the backend. Collapses the six writeXDraft
functions onto one generic writeDraft + typed per-kind WriteSpec
constants. Terminology: "local draft" -> "draft" (drafts are server-side).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(frontend): autosave indicator + draft-only diff guard in session editors
Thread an explicit (workspace, path) autosave target to the cloud
AutosaveIndicator in the Script/Flow/RawApp session previews so it
watches the same key saves land on (it previously watched an empty path
and never animated). Disable the Diff button with a hint for draft-only
(no_deployed) items consistently across the three editors. Adjust the
script topbar compact breakpoint/layout so the cloud icon is part of the
bar, and stop splitpanes over-constraining session panes on reload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): session draft diff viewer for schedule/resource/variable
Canonicalize both sides of the draft diff onto one field set and strip
runtime-only fields so rows aren't spuriously marked all-changed; mask
secret values. Map draft itemKinds to deploy-style kinds so the DiffRow
shows the correct icon/label.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): uniform diff-viewer row height regardless of summary
Diff-viewer leaf rows (WorkspaceItemRow) drew two lines when an item had a
summary and one line otherwise, giving unequal heights. Add an opt-in
`uniformHeight` prop that gives the text wrapper a shared min-height and
vertically centers the one-line case; enable it only from the diff viewer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(frontend): address review nits on the drafts diff/guard changes
- Reuse the exported TRIGGER_RUNTIME_IGNORE from utils_deployable instead of
a verbatim copy, so the runtime-field ignore list has one source of truth.
- Drop the now-redundant `(savedApp as any)` cast in RawAppEditorHeader; the
prop type already carries `no_deployed`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): add description parameter to the write_flow chat tool
write_flow had no way to set a flow's top-level description (the sibling
of summary in OpenFlow); patch_flow_json only edits the compact value, so
the field was unreachable from the AI chat. Thread an optional description
end-to-end: tool schema -> persisted draft -> read-back -> deploy body.
Structural patches (patch_flow_json/set_flow_module_code) pass no
description, so a previously-set description is preserved. Adds a
deployRequests regression test asserting a draft description reaches the
deploy body, overriding the deployed one.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): round-trip top-level fields in session preview draft sync
The session preview's two-way draft sync dedups on a per-kind signature
and mirrors fields between the editor store and the shared UserDraft cell.
Both omitted fields the chat can set, so with the preview open a change to
only that field was swallowed (identical signature) and then clobbered by
the editor's outbound save:
- flow: the signature and applyDraftToStore ignored top-level `description`.
- script: the signature keyed on `content` alone, dropping `summary`/`language`.
Add the missing fields to flowDraftSig and the script codec signature, and
copy `description` in the flow codec's applyDraftToStore (mirroring `summary`).
Raw-app already stringifies the whole draft, so it was unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): deploy draft-only flow from the session preview
Deploying a draft-only flow (a draft with no deployed row) from the session
preview hit two gaps the full-page flow editor already handled:
- create vs update: newFlow keyed on `!savedFlow.val`, but a draft-only flow
has a synthesized savedFlow (no_deployed=true), so deploy took updateFlow
against the draft path and 404'd "Flow not found". Key it on no_deployed too.
- friendly name: a brand-new flow is stored under a `draft_<uuid>` path with
its intended name in `draft_path`. Seed the builder's initialPath from
`draft_path` (as the full-page editor does) so the Path widget and deploy
use the friendly name instead of creating a flow named draft_<uuid>.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): deploy draft-only raw app from the session preview
Same create-vs-update bug as the flow session preview: newApp keyed on
`!savedRawApp.val`, but a draft-only app has a truthy synthesized savedApp
(getAppByPath with rawApp:true resolves to the draft kind instead of 404ing,
carrying no_deployed=true), so deploy took updateApp against a path with no
deployed row and 404'd "not found". Key newApp on no_deployed too so a
never-deployed app deploys via createApp. More reachable than the flow case:
it hit any never-deployed app, including chat-created ones at friendly paths.
Keying newApp on no_deployed also exposed that newEditedPath (the breadcrumb
path AND the createApp target) used newApp to mean "brand-new, generate a
random name". A draft-only app is newApp=true but already has a real path
(empty newPath at init, but appPath is set), so it showed and would deploy a
random `*_app` name. Prefer the real appPath before the random fallback, so
only a genuinely new app (appPath === '') still gets a generated suggestion;
the full-page editor is unaffected (it always sets newPath).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): don't re-save a draft after deploying from the session preview
Deploying from a session preview reloaded the editor (expected) but then
immediately POSTed a fresh draft. The full-page editor guards deploy with
discardDraftAfterDeploy (stopSync + arm-restart-on-first-interaction), but the
shared editor header skips that in a session pane (inSessionPane) and routes
post-deploy cleanup through sessionRuntime.syncPreviewWithDeployed, which did
discard + reload without the stopSync guard. UserDraft.discard keeps the cell
entry, so the reload's UserDraft.save fired the cell's reactive effect and
re-POSTed the just-deployed value as a draft.
Wrap the discard + reload in the same UserDraft.stopSync + armRestartOnFirst-
Interaction bracket. One place fixes all three kinds (script/flow/raw_app),
since they all funnel through syncPreviewWithDeployed; autosave resumes on the
next genuine edit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(frontend): address review findings on the session-preview drafts work
- Type `no_deployed` via the GetXByPathResponse/UserDraftOverlay types instead
of `(result as any)`/`(saved as any)` casts at the sites this branch added
(sessionRuntime, ScriptBuilder, FlowBuilder, + widened the script/flow
builder prop types). Pre-existing trigger/variable/resource-editor casts
left untouched.
- Drop a history-narrating comment parenthetical per the AGENTS.md comment
policy (RawAppEditorView).
- Add a unit test covering persistGlobalDraft's conflict-on-save / override
path (conflict-capable updateDraft mock; inert for existing tests).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): keep the friendly generated path for a brand-new raw app
The earlier draft-only newApp fix made newEditedPath prefer `appPath` before
the random suggestion, but a brand-new app is parked at the storage placeholder
`u/{user}/draft_{uuid}` (the /apps_raw/add redirect target), so it surfaced that
uuid instead of a friendly `<adjective>_app` suggestion. Reject a `draft_`
placeholder segment when choosing the path: a real named/draft-only path is
still kept, a placeholder falls through to the generated suggestion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): show the Diff-button tooltip when it's disabled
A disabled <button> fires no pointer events and browsers suppress its
native title, so the "deploy once to compare" explanation never showed on
hover for a draft-only item's Diff button. Wrap the button in a titled
element and set pointer-events-none on the button when disabled, so the
hover reaches the wrapper. Applied in ScriptBuilder, FlowBuilder, and
RawAppEditorHeader (covers both the full-page editors and the session preview).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): surface draft save failures and conflicts in the AI chat tools
Addresses Codex + Pi review findings on PR #9601 (three P1s, all in the
DB-backed draft adapter reporting success when the write didn't land):
- persistGlobalDraft reported {status:'saved'} even when UserDraftDbSyncer.save
failed (it records network/5xx into a failure map instead of throwing). Check
getState().state==='failed' after the save and return a new 'error' status;
finishDraftWrite now emits success:false with a retry hint.
- saveGlobalAppDraft dropped the conflict/error status (returned only the item),
so write_app_file/patch_app_file/write_app_runnable reported every stale or
failed write as saved. It now returns the full DraftPersistResult, and the six
app write tools route through a shared finishAppDraftWrite helper.
- fetchBackendDraftValue's catch{} swallowed non-404 errors (403/500/network),
collapsing them to "no draft" so the write merged from the deployed item and
lost in-progress draft edits. Narrow the catch to status===404; propagate the
rest.
Adds unit coverage: save-failure -> 'error', non-404 read -> propagates,
raw-app stale write -> 'conflict'. 71/71 pass, check:fast + full build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): surface failed draft deletes + strip tool-only override from schedule drafts
Addresses Codex's second-round review on PR #9601:
- [P1] deleteGlobalDraft reported success even when the server delete failed or
conflicted (UserDraftDbSyncer.save records failure state instead of throwing) —
so discard_local_draft / deploy_workspace_item / delete_workspace_item / the
/global_drafts delete could report a draft removed while the DB still had it.
Check getState().state and getConflict() after the awaited null save and throw,
mirroring the write-path guard.
- [P2] writeScheduleDraft persisted the tool-only `override` conflict flag into
the schedule draft value (mergeDraftConfig cloned every arg field). Strip
`override` in SCHEDULE_SPEC.buildDraft before merging.
Tests: failed server delete -> throws; schedule draft no longer contains
`override`. 73/73 pass, check:fast + full build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): /global_drafts "Clear all" deletes persisted drafts, not just cells
Codex review nit (P2): the dev-only global-drafts inspector's "Clear all" called
clearGlobalDrafts(), which only iterates in-tab UserDraft cells — any persisted
backend draft row not currently mounted as a cell survived, so the list re-showed
it after refresh. Iterate the listed drafts and delete each via the backend-aware
deleteGlobalDraft() (continue past per-row failures), matching the per-row delete,
then clear local cells + ephemeral secrets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(nativets): respect custom CA certs in in-process fetch runtime
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(nativets): dedupe CA file paths and clarify DENO_TLS_CA_STORE semantics
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(nativets): resolve CA env vars from worker-group config too
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When editing a resource whose type definition does not exist in the
workspace (e.g. custom types not yet synced), the JSON fallback editor
rendered empty. The pre-refactor ResourceEditor seeded rawCode from the
resource args in its loadResourceType() catch block; the new
ResourceForm only populated rawCode when the user toggled viewJsonSchema.
Add a reactive effect that seeds rawCode from args when the resource
type schema is unavailable, restoring the old behavior so the resource
data is visible in the JSON editor.
Fixes WIN-2045
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
A draft-only app (one that exists only in the `draft` table and was never
deployed) failed to load when opened from the home list: the row linked to
the viewer `/get/` route, whose `get_app_lite` backend handler 404s when
there is no deployed version.
Route `draft_only` apps to the `/edit/` route instead, matching the
existing behavior in ScriptRow and FlowRow. Covers both raw and regular
draft-only apps.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "Add a variable" drawer (and other editors built on `UserDraft.useMany`)
opened empty: for a brand-new item `editPath` is undefined so the spec path is
empty, which routes through `useMany`'s empty-path branch. That branch handed
out a `makeDetachedHandle()` whose cell was initialized to `undefined`,
ignoring the spec's `defaultValue`. The editor binds its form behind
`{#if current}` where `current = states[ws]?.draft`, so an undefined cell left
the drawer with just the title and a Save button.
Seed the detached handle with `defaultValue`, and re-seed it when the caller
supplies a fresh `defaultValue` reference (reopening the drawer clones a new
default) so a reopened editor starts clean instead of replaying the previous
session's edits — the reference is stable within a session, so live edits are
never clobbered. Also drop detached handles that fall out of the specs so they
don't leak.
Regression from #9351 (db-backed user drafts).
Fixes WIN-2054
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-hosted instances that embed their own UI (Windmill as backend, custom
app at the instance root) can't be redirected back to their app after OAuth
login: isValidLogoutRedirect rejects same-origin absolute URLs, so the login
callback falls back to a client-side goto('/') into Windmill's own dashboard.
Same-origin redirects are never open redirects (and toSameOriginRelativePath
already treats them as safe), so accept them.
Also make the test-setup window global configurable so vitest's stubGlobal
can redefine it across the window-stubbing test suites.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): include __mod/ folder in gitSyncIncludePattern for scripts
Scripts with companion modules use a `__mod/` folder layout on disk
(`path__mod/script.ts`, `path__mod/script.yaml`, ...). The default case of
`gitSyncIncludePattern` returned only `${path}.*`, which does not match files
inside `__mod/`. During git-sync deployment the `extraIncludes` filter then
excluded all module files from the pull, and the subsequent
`git add '${path}**'` failed with "pathspec did not match any files" because
nothing was written to disk.
Add the `${path}__mod/**` pattern so module files are pulled, mirroring the
existing dual-layout handling for flows (`.flow/*,__flow/*`) and apps.
Fixes WIN-2052
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(cli): e2e guard that module scripts' __mod/ files land on git-sync deploy branch
Add a promotion test mirroring the existing trigger/schedule cases: deploy a
script WITH companion modules (one flat, one nested) under use_individual_branch
and assert the `__mod/` entry point and module files land on the wm_deploy
branch. Without the gitSyncIncludePattern `__mod/**` fix the extra-includes
filter matches none of those files and the branch is created without them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: support temp_script_refs in wmill dev for local relative imports
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test: add unit tests for getAllTempScriptRefs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): strip server-managed fields from value diffs
The script editor's "Deployed <> Current" diff rendered spurious metadata
changes (created_at, created_by, extra_perms, lock_error_logs, ...) the user
never touched. Since #9351 the edit loader fetches the full Script row via
getScriptByPath (instead of the trimmed NewScript-shaped getScriptByPathWithDraft),
so the editing object carries these DB-managed fields. The deployed side is
trimmed in syncWithDeployed, so the two sides no longer match.
Normalize both sides at the shared chokepoint: cleanValueProperties now also
strips created_at, created_by, extra_perms, workspace_id, parent_hashes, lock
and lock_error_logs. These are never user-editable, so this also fixes the
draft<>current diff and unsaved-change detection, and benefits the flow/app
diff viewers that share the helper.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(frontend): cover cleanValueProperties; keep lock in diffs
Add unit tests for cleanValueProperties asserting the server-managed
bookkeeping keys are stripped while user-editable keys survive.
Keep `lock` out of the stripped set: it was part of the value comparison
before the full-DB-row loader (#9351) and version-to-version diff viewers
(WorkspaceItemDiffViewer) legitimately surface lockfile changes. Only the
fields that the full Script row newly introduced as diff noise are stripped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): keep extra_perms in shared diff, strip script noise at source
Address review: stripping `extra_perms` in the shared `cleanValueProperties`
hid folder sharing-permission changes in workspace/fork diffs (the backend's
compare_two_folders treats folder extra_perms as a real change). Remove it from
the global skip-list so folder diffs surface it again.
The script-editor noise it (and `lock`) would otherwise cause is now stripped at
the source instead: `ScriptBuilder.openDiffDrawer` nulls `lock`/`extra_perms` on
the current side to match the existing deployed-side strip in `syncWithDeployed`.
Also strip the draft-overlay bookkeeping fields the full DB row carries
(`draft_saved_at`, `draft_created_at`, `is_draft`, `other_drafts_users`) — they
leaked into the current side and showed as spurious metadata diffs.
Verified in browser: no-edit diff shows "No changes detected"; a summary edit
surfaces only that change, with no lock/extra_perms/draft metadata noise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NodeWrapper destructured `moveManager` from `getGraphContext()` unconditionally,
but FlowGraphContext is only set by the flow graph. The app decision-tree editor
reuses NodeWrapper without setting that context, so opening its Graph Editor threw
"Cannot destructure property 'moveManager' of getGraphContext(...) as it is undefined".
Guard the context with `?? {}` since `moveManager` is already used optionally.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): session-pane draft seeding + restore actions
Seed per-tab last_sync from the server draft's draft_saved_at in the
loadFlow/loadScript "no local draft" branches (mirroring loadRawApp) so the
seeding save attaches a matching last_sync and the server no longer clobbers
an existing server draft with a fresh created_at.
Replace the no-op loadFlow/loadRawApp-based diff-drawer restore handlers with
proper restoreDeployed/restoreDraft that reset the live UserDraft cell (the
inbound sync then updates the preview) and delete the per-user server draft,
mirroring ScriptEditorView. Add rawAppValueToDraft to project a deployed
raw-app value into the draft shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(api): move UserDraftOverlay/UserDraftItemKind out of openflow inline block
These two schemas were defined between the python-client's
"# -- INLINE START/END --" markers, whose contents build.sh replaces with the
openflow legacy wildcard $ref. That deleted both definitions during bundling
while ~19 path responses still referenced them, failing the python-client
build. Relocated them after the marker block.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(frontend): explain legacy drafts in the draft badge popover
The home-page draft badge lists each draft owner; a workspace-level row from
before the per-user drafts migration shows as "Legacy workspace draft". Add an
info tooltip next to it explaining that a legacy draft isn't tied to any user
(email NULL) so everyone with access to the path sees it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(compare): show friendly draft path on the review & deploy page
list_drafts now surfaces the draft JSON's `draft_path` (when set and different
from the storage path) alongside summary, mirroring the home-page list
endpoints. CompareDrafts displays it instead of the `u/{user}/draft_{uuid}`
storage path, while all fetch/deploy/discard calls keep using the storage path
(the draft's server-side key).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(compare): delete the storage-path draft when deploying a renamed draft
Deploying a draft from the review page replays the editor's create/update at
the draft's friendly path, which deletes the draft server-side only at that
path. A never-deployed item parked at `u/{user}/draft_{uuid}` therefore left
its storage-path draft behind on deploy and kept listing. Delete the
storage-path draft for every kind after a successful deploy, mirroring the
editors' discardDraftAfterDeploy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(compare): badge legacy drafts on the review & deploy page
list_drafts now reports `legacy_draft` (true when the listed row is a
workspace-level NULL-email draft and no per-user row exists at the path).
CompareDrafts shows a "Legacy draft" badge with a hover tooltip explaining
these predate the per-user drafts migration and aren't tied to a user.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(compare): allow discarding a legacy draft from the review page
Legacy drafts (workspace-level, email NULL) aren't owned by the authed user,
so the email-scoped draft delete in update_draft never matched them and the
discard was a silent no-op. Add a delete-only `legacy` flag that retargets the
DELETE (and the conflict re-read) to the NULL-email row, and route the review
page's discard of a legacy draft through it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(backend): prune orphaned sqlx offline cache entries
Re-ran the canonical update_sqlx.sh after rebasing windmill-ee-private onto
origin/main and re-running substitute_ee_code.sh. Compiling the full workspace
with all features recorded every live query and pruned 55 stale cache entries
no longer produced by any query (22 are the removed `draft_only`-on-app
lookups dropped by the db-backed user drafts work; the rest pre-existing
orphans). Orphan entries don't break offline builds — this is cleanup only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(drafts): stop migrated draft-only items flooding the home list
20260609165313_remove_draft_only inserted the legacy (email IS NULL) draft
stubs without an explicit created_at, so every row defaulted to the migration's
now() (transaction_timestamp, constant for the whole transaction) and they all
bunched at the migration instant — flooding the top of the newest-first home
list.
Add a corrective migration that resets those rows' created_at to the epoch so
they sort to the bottom (their real per-item timestamps are unrecoverable —
the source rows were deleted and the draft value carries no timestamp; editing
one bumps created_at to now() and floats it back up). The rows are identified
exactly via _sqlx_migrations.installed_on, which sqlx writes in the same
transaction as the migration so it is byte-identical to the inserted rows'
created_at; rows edited since no longer match and are left alone. Leaving
remove_draft_only intact (rather than neutralizing it) keeps its essential
schema work running everywhere; this migration runs right after and corrects
the timestamps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(migration): note both timestamps are timestamptz in draft created_at repair
Pre-empt a misread: draft.created_at became TIMESTAMPTZ in
20260514233244, so `created_at = installed_on` is an exact instant comparison,
not a tz-sensitive timestamp/timestamptz cast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(compare): resolve friendly draft path per kind + strip email from u/ path
list_drafts read the friendly path only from value->>'draft_path', which is
empty for scripts — the script editor binds the Path widget to script.path, so
the typed path round-trips through the draft JSON's own `path` (flows/apps/raw
-apps use draft_path). Read the right field per kind, matching the home-page
list endpoints, so renamed never-deployed scripts show their friendly name.
Also truncate the user segment at `@` when displaying a `u/{user}/…` path:
auto-generated draft slots are `u/{user}/draft_{uuid}`, and in the admins
workspace (or email-as-username setups) `{user}` is the full email
(`u/admin@windmill.dev/…` → `u/admin/…`). Display only — the path/key used for
fetch/deploy/discard is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(raw-app): make diff-drawer "restore to deployed" reset like the autosave indicator
The diff drawer's restoreDeployed ran the same runResetToDeployed as the
AutosaveIndicator's "Reset to deployed", but its onResetToDeployed callback
also did `redraw++`, remounting RawAppEditor mid-reset (inside the stopSync
bracket); the fresh mount's draft write resurrected the draft, so the restore
appeared to do nothing. Extract a single `reloadDeployed` callback (drop the
draft handle + reload without the draft overlay) and use it for the diff
drawer, the conflict modal, and the AutosaveIndicator so all three reset the
same way.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(compare): don't show auto-generated draft path as the bold title
A never-named draft lives at a synthetic `u/{user}/draft_{uuid}` slot. When it
had no summary and no friendly draft path, that uuid showed as the row's bold
title. Return '' from displayPath for auto-generated paths so they aren't
bolded — the row still shows the storage path in its secondary (grey) line.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(diff-drawer): remove obsolete draft-vs-current tab selector
The "Latest saved draft <> Current" comparison is obsolete. Remove the whole
diff-type tab selector; normal-mode diffs now always show deployed-vs-current,
simple-mode shows its single custom diff. Drop the now-unreachable
restore-to-draft button and the `restoreDraft` prop (plus the dead handlers in
the session editor views). The content/metadata selector is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(compare): make "Reset to deployed" work from the diff drawer
Route the raw-app session preview and the low-code app editor diff-drawer
restore through the same reset-to-deployed callback the AutosaveIndicator uses.
- Raw-app session: add a deployedOnly path to loadRawApp that bypasses the
draft (cell + server overlay) and reloads the deployed value; the diff
drawer's restore now runs it via runResetToDeployed instead of rebuilding the
draft shape in place (which hung and never reset). Also wires the in-session
AutosaveIndicator reset.
- Low-code app editor: drop the goto in the diff-drawer restoreDeployed that
re-ran the page load with the draft overlay on and resurrected the draft;
share one reloadDeployed across the diff drawer, AutosaveIndicator and the
load-latest-deploy modal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>