Commit Graph
13526 Commits
Author SHA1 Message Date
Diego Imbert ee65da8d83 fix: make migration view editor read-only so its code can scroll 2026-06-20 16:14:53 +02:00
Diego Imbert 32732e599b feat: make datatable migrations opt-in per data table 2026-06-20 15:44:18 +02:00
Diego Imbert 56202da8b9 feat: record db manager DDL on data tables as migrations 2026-06-20 15:33:52 +02:00
Diego Imbert 4ead9cfb04 feat: refresh datatable schema after running a migration from the SQL REPL 2026-06-20 15:30:11 +02:00
Diego Imbert f066eac61d fix: re-prompt instead of stripping DDL when new-migration modal is cancelled 2026-06-20 15:10:01 +02:00
Diego Imbert cc0415b191 fix: ensure detected DDL ends with semicolon when wrapped in transaction 2026-06-20 14:54:00 +02:00
Diego Imbert d19d58ebc4 fix: validate datatable migration name and datatable at the API boundary 2026-06-20 14:51:23 +02:00
Diego Imbert f97a0b2f60 feat: default new datatable migration to a BEGIN/END transaction template 2026-06-20 14:45:00 +02:00
Diego Imbert 68d82dbe54 chore: regenerate CLI docs for datatable migrate commands 2026-06-20 14:41:44 +02:00
Diego Imbert e98dcd3579 fix: surface postgres error detail when datatable migrations fail to run 2026-06-18 23:34:55 +02:00
Diego Imbert d234001e63 feat: datatable migrate up/down default to all datatables, --datatable to target one 2026-06-18 21:07:35 +02:00
Diego Imbert 49a476fec7 feat: reject invalid datatable migrations on sync push 2026-06-18 21:04:49 +02:00
Diego Imbert dbdd09b9a2 feat: run datatable migrations as user-permissioned labeled jobs 2026-06-18 20:07:02 +02:00
Diego Imbert 52ef65c55e fix: exclude datatable migration sql files from script metadata generation 2026-06-18 19:44:16 +02:00
Diego Imbert b8c8faf629 fix: drop redundant datatable_migration label in sync output 2026-06-18 13:58:09 +02:00
Diego Imbert ed7586d61c refactor: move datatable migrations to migrations/datatable/ path 2026-06-18 10:33:25 +02:00
Diego Imbert bd5a047169 feat: sync datatable migrations as files via the workspace export 2026-06-17 19:52:28 +02:00
Diego Imbert 541a1407e0 fix: include postgres error detail in migration run/rollback failures 2026-06-17 19:35:17 +02:00
Diego Imbert 84078f33ce fix: revert created migration if create-and-run fails to run 2026-06-17 19:27:17 +02:00
Diego Imbert 2f15f39f41 fix: surface datatable migration API error details in toasts 2026-06-17 19:25:42 +02:00
Diego Imbert 7859ebfb38 feat: generate initial datatable migration via pg_dump 2026-06-17 19:24:26 +02:00
Diego Imbert d4f0083501 fix: avoid migrations list flicker on refresh after an action 2026-06-17 19:18:13 +02:00
Diego Imbert a79b9e7c43 feat: per-row revert button with out-of-order warning 2026-06-17 19:08:24 +02:00
Diego Imbert aa6ed90b60 feat: view migration content, run single migration, fix stacked modal 2026-06-17 18:36:42 +02:00
Diego Imbert 4de2dd6d59 feat: support running a single specific datatable migration 2026-06-17 18:34:52 +02:00
Diego Imbert 95ee90fc5a feat: prompt to create migration on DDL in datatable SQL editors 2026-06-17 18:14:29 +02:00
Diego Imbert a18fa7ccd6 feat: add datatable migrations management UI 2026-06-17 15:18:09 +02:00
Diego Imbert 6e1ce7fd4e feat: add datatable migrate new command to scaffold migrations 2026-06-17 11:47:47 +02:00
Diego Imbert b3002f5e24 feat: add datatable migrate up/down commands and post-push run prompt 2026-06-17 11:29:06 +02:00
Diego Imbert 1f48a470ba feat: sync datatable migrations as .up.sql/.down.sql files 2026-06-17 11:02:43 +02:00
Diego Imbert 5f2cb62527 feat: add route to run datatable migrations 2026-06-17 10:29:56 +02:00
Diego Imbert 6ba02002cd feat: add datatable_migrations table 2026-06-17 10:20:51 +02:00
Diego ImbertandClaude Opus 4.8 f6104ce05c fix: show last updated date per user in other-users-drafts modal (#9614)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:38:58 +02:00
GuilhemandClaude Opus 4.8 611c70acd2 feat(frontend): adapt AI-chat/sessions drafts to DB-backed model (#9601)
* 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>
2026-06-16 15:20:19 +02:00
Ruben FiszelandClaude Opus 4.8 41562c7d7c fix(nativets): respect custom CA certs in in-process fetch runtime (#9615)
* 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>
2026-06-16 14:39:36 +02:00
Diego Imbert bc0d5bf241 feat(frontend): consolidate draft-migration errors into a single toast + modal (#9612)
* Draft migration error modal

* nits
2026-06-16 14:12:08 +02:00
5a2405743b fix(ResourceForm): initialize JSON editor when resource type schema is unavailable (#9611)
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>
2026-06-16 13:41:04 +02:00
Ruben Fiszelandrubenfiszel 6b62b1d832 chore(main): release 1.727.0 (#9605)
* chore(main): release 1.727.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.727.0
2026-06-16 12:35:50 +02:00
Diego ImbertandClaude Opus 4.8 a44fc89eba fix(frontend): open draft-only apps in editor from home list (#9610)
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>
2026-06-16 12:34:59 +02:00
hugocasaandClaude Opus 4.8 51e82d7c6d fix(frontend): make UserDraft read-after-write work without live entry (#9609)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:25:33 +02:00
Ruben FiszelandClaude Opus 4.8 9e3c0decf9 fix(frontend): seed detached user-draft handles so new-item drawers render (#9608)
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>
2026-06-16 12:01:28 +02:00
hugocasaandClaude Fable 5 cd098700c2 fix(cli): harden legacy flow lock migration ordering and collision guard (#9557)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 10:25:37 +02:00
GuilhemandClaude Fable 5 8500435e82 fix(frontend): allow same-origin redirects in isValidLogoutRedirect (#9568)
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>
2026-06-16 10:25:11 +02:00
hugocasaandClaude Opus 4.8 252c1b35fc fix(cli): include __mod/ folder in gitSyncIncludePattern for scripts (#9606)
* 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>
2026-06-16 10:22:18 +02:00
hugocasaandClaude Fable 5 33ac287065 feat: support temp_script_refs in wmill dev for local relative imports (#9554)
* 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>
2026-06-16 10:21:37 +02:00
GuilhemandClaude Opus 4.8 c213801b5a fix(frontend): strip server-managed fields from value diffs (#9599)
* 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>
2026-06-16 08:58:22 +02:00
Ruben Fiszelandrubenfiszel 1cf402a9be chore(main): release 1.726.1 (#9603)
* chore(main): release 1.726.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.726.1
2026-06-16 00:58:38 +02:00
Diego ImbertandClaude Opus 4.8 24f32596e9 fix(apps): prevent decision tree graph editor crash on missing graph context (#9602)
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>
2026-06-16 00:48:27 +02:00
Diego ImbertandClaude Opus 4.8 4e4b2247ef fix: db-backed draft fixes — review-page UX, legacy drafts, session restore (#9600)
* 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>
2026-06-16 00:46:53 +02:00
Ruben Fiszelandrubenfiszel abe442bf42 chore(main): release 1.726.0 (#9598)
* chore(main): release 1.726.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.726.0
2026-06-15 20:22:16 +02:00