mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 16:02:19 +00:00
3eeccaf9682b7803fdf5be8dcbc4d243e0ba2e49
13518 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3eeccaf968 |
feat: add ducklake schema support to the database manager (#9633)
* feat: add ducklake schema support to the database manager Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: support schema in wmill.ducklake("name:schema") template helper Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: preserve schema when parsing ducklake asset/favorite paths Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: regenerate system prompts for ducklake schema syntax doc Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
25a891041d |
wire DB-backed autosave into the whitelabel flow SDK (#9637)
* fix(frontend): wire DB-backed autosave into the whitelabel flow SDK FlowWrapper (the @windmill-labs/components flow editor entry) was never updated after DB-backed user drafts moved autosave wiring to the page layer, so the SDK editor had no autosave and never rendered the AutosaveIndicator. Back the bound store with a per-user UserDraft handle (workspace-guarded so it no-ops before a workspace exists) and pass liveEditorDraftStoragePath so the indicator and Ctrl/Cmd+S flush engage. Also set $workspaceStore on the /test_dev/sdk_flow harness page, which lives outside the (logged) layout and so had an empty workspace store (mirrors the sibling sdk_resource page). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): shared test_dev header to log in + set the SDK token Add a common TestDevHeader (rendered by a test_dev/+layout) that logs in (email/password → bearer token), lets a token be pasted/set manually, picks the workspace, loads the user, and persists the session across reloads — mirroring the React SDK's initializeClients. test_dev routes live outside the (logged) layout, so this is the single place that wires OpenAPI.TOKEN + workspaceStore + userStore for the SDK demo pages. Drop the now-redundant per-page workspace/user wiring from sdk_flow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): reuse usePageDraftSync in the flow SDK instead of a parallel copy FlowWrapper hand-rolled UserDraft.useMany + a manual seed effect, duplicating the core of usePageDraftSync but dropping recordRemoteSync/seedBaseline/discardIf — a divergence that would drift. The only reason it couldn't reuse the helper was that useReactive passes workspace straight into useMany, whose reconcile called resolveWorkspace() (which throws) before the detached-handle check. Make reconcile resolve the workspace without throwing and treat an absent workspace like an empty path — handing out a detached, local-only handle that re-keys into a real entry once the workspace resolves. FlowWrapper then reuses usePageDraftSync directly, keeping one code path for the page and SDK editors. Seed via the spec's defaultValue (threaded through usePageDraftSync -> useReactive -> useMany, captured once on first acquire and swallowed by the syncer's seed guard) rather than a manual first-write effect, dropping the fragile skipNextWrite assumption and the seededPath bookkeeping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): wire DB-backed autosave into the whitelabel script SDK ScriptWrapper had the same gap FlowWrapper did: ScriptBuilder delegates its draft handle to the page (it only stop/restart-syncs and flushes by userDraftPath), so the SDK's plain `bind:script` never reached a UserDraft handle — no autosave, no indicator. Back it with usePageDraftSync<script> (bind:script={draftSync.draft}, userDraftPath), seeded from the consumer's script via defaultValue. Same one-code-path reuse as the flow SDK. AppWrapper needs no change: AppEditor already self-acquires its handle (UserDraft.use('app', ...)), so apps autosave already — and now also tolerate mounting before login via the reconcile change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): gate SDK editors on a resolved workspace Before a workspace exists the draft handle is detached (local-only); editing into it and then having the workspace resolve re-keys to a fresh real entry seeded from the original value, silently dropping those edits. Gate the flow, script, and app SDK editors on `$workspaceStore` so no editing happens until the real draft key exists. Embedders set the workspace before rendering (React SDK initializeClients); the test_dev header sets it on mount. AppEditor additionally acquires its handle at init from a non-reactive workspace, so gating AppWrapper also ensures it mounts with the workspace already set rather than permanently detached. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): add sdk_app test_dev page for the app editor SDK Exercises AppWrapper the same way sdk_flow/sdk_script exercise their editors, under the shared TestDevHeader. Confirms the app editor's self-managed autosave + AutosaveIndicator work via the SDK wrapper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3c0e38b589 |
fix(git-sync): bump default sync script to hub/28719 (windmill-cli 1.728.1) for WAC modules (#9649)
Points LATEST_GIT_SYNC_SCRIPT_PATH at the republished sync-script-to-git-repo (windmill-labs/windmill-integrations#155) pinning windmill-cli@1.728.1, which carries the gitSyncIncludePattern __mod/** fix (#9606). On-deploy git-sync was running windmill-cli@1.713.2 and filtered workflow-as-code (WAC v2 / module) scripts stored under <path>__mod/ out of the deploy pull, so they never reached the repo. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e26a9239a6 |
feat: zero-setup oauth client credentials for registry providers (#9559)
* feat: zero-setup oauth client credentials for registry-declared providers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: support client-credentials-only custom oauth providers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add coupa client credentials provider to oauth registry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: clarify oauth resource connect auth-method selection Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: support shared instance-level oauth client credentials Admins can designate an instance OAuth entry's credentials as client credentials; the connect dialog then runs the exchange server-side with them instead of asking each user for their own. Replaces the per-provider "Support Client Credentials Flow" toggle with a grant-type selector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: update ee-repo-ref to be9f23b2c06b8b6ee0cd3e4d9f16bcd9e90129fb This commit updates the EE repository reference after PR #613 was merged in windmill-ee-private. Previous ee-repo-ref: 05643cbbc8c1bebf3509c691c5811b4057d96485 New ee-repo-ref: be9f23b2c06b8b6ee0cd3e4d9f16bcd9e90129fb Automated by sync-ee-ref workflow. * feat: allow both grant types on an instance oauth entry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: bring-your-own oauth credentials from the others section Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: segmented oauth grant-type selector, always show grant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: enable client credentials for 5 more oauth providers Verified against official docs: bitbucket, linkedin, spotify, xero and zoho support the standard client_credentials grant with a plain client_id + client_secret, compatible with Windmill's token exchange. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: hide create-manually link on the managed oauth connect path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: enable client credentials for salesforce and servicenow Salesforce CC requires the org's My Domain token endpoint (login.salesforce.com is unsupported for that grant), so add an optional cc_token_url registry field that the connect form prefills for the client-credentials path instead of the shared token_url. ServiceNow uses the same instance host for both grants, so it only needs its token URL and req_body_auth surfaced at the top level. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add instance-level client-credentials token url override Some providers use a per-org/instance-specific token endpoint for the client-credentials grant that differs from the authorization-code URL. Add an optional cc_token_url on the instance OAuth entry, surfaced in instance settings (prefilled from the registry template) when client credentials is selected, and used for the CC exchange and refresh while auth-code keeps its own token URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style: remove redundant grant-type tags from oauth auth cards Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: extract reusable RadioCard component for the oauth auth chooser A token-based selectable card (label, description, selected, onSelect, optional icon) replacing the inline cards in the connect dialog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: hide sign-in option on the bring-your-own oauth path Picking a provider from "Others" means bring your own credentials, so the auth-code "Sign in" card (which uses the instance client) no longer shows there — it goes straight to the client-credentials form. The two-flow chooser stays on the instance-configured path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: restrict client-credentials token url to caller-supplied creds Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: resolve client-credentials id and secret all-or-nothing Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: host-pin client-credentials token url via instance-name input For registry providers whose CC token URL is instance-templated (Coupa, Salesforce My Domain, ServiceNow), the connect dialog and instance settings collect an instance name and the backend substitutes it into the fixed-host template, validating it as a hostname label. A free-form token URL is no longer accepted for these providers, so the exchange host cannot be redirected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: client-credentials token url always comes from the registry Bring-your-own CC is registry-only: the token URL is resolved server-side from the built-in registry (host-pinned via an instance name for templated providers, the fixed registry URL otherwise) and rejected for custom resource types. The caller-supplied token URL field is removed from the connect dialog and the API. Adds unit tests for the resolver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: address CC review - sandbox CC config and instance-templated providers Resolve `_sandbox` provider keys to the parent registry entry in the instance settings and connect-dialog helpers, so salesforce_sandbox (and future sandbox entries) can enable client credentials. Use the effective CC token URL template (cc_token_url or token_url) so the instance-name field works for Coupa/ServiceNow, and hide that field when a connect_config_template already owns the instance input (ServiceNow). Document the authorization contract on resolve_instance_cc_credentials. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: unify instance-templated oauth onto connect_config_template Remove the separate cc_token_url and cc_instance config fields. An instance- templated provider now declares one connect_config_template (auth_url optional for client-credentials-only providers like Coupa); the CC flow reads its token URL, label and strip_suffix to host-pin the exchange. Coupa and ServiceNow move to connect_config_template; Coupa stays drawer-only (no auth_url -> excluded from instance settings). Salesforce CC is removed for now (its auth-code/CC host split needs the endpoint-profiles model). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: cc_scopes defaults and instance config for client credentials Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: store empty auth_url for cc-only templated oauth providers Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: address review nits - sandbox key lookup, template doc, deref specs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: default shared client-credentials connect to cc_scopes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: support bring-your-own client credentials for instance-configured providers Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: move oauth grant-type help into per-option tooltips Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: keep instance-configured oauth providers selectable from Others Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: preserve admin-configured scopes for custom client-credentials providers Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: use cc scopes on cc refresh and enforce cc grant for bring-your-own Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: require {instance} in leftmost host label for cc token url templates Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: drop token_url from unauthenticated get_connect response Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: fill byo templated resource args from the entered instance Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 136f4634aca61e74ccb045372358a1e3f6b23e75 This commit updates the EE repository reference after PR #616 was merged in windmill-ee-private. Previous ee-repo-ref: b5083e266492e908456e39401778a9cdcea46e94 New ee-repo-ref: 136f4634aca61e74ccb045372358a1e3f6b23e75 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
ba69d8147b |
fix(frontend): show AI sessions when AI unconfigured, with disabled chat (#9644)
Previously the AI sessions sidebar section was hidden entirely when AI was not configured at the workspace level. Now the section stays visible and the per-session chat input is disabled with an explanatory message, mirroring the sidebar AI chat behavior. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e87ff79ecf |
fix(ai_evals): adapt global eval harness to DB-backed user drafts (#9641)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e80c62b958 |
docs(cli): improve generate-metadata guidance, fix description parser (#9635)
* docs(cli): improve generate-metadata guidance, fix description parser Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): surface dependency version bumps after generate-metadata Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): explain generate-metadata scope, import cascade, and --dry-run troubleshooting Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8021775f5f |
fix(drafts): preserve original timestamp when migrating localStorage drafts (#9638)
The localStorage→DB user-draft migration upserted via /drafts/update, whose SQL always stamped created_at = now(). Every migrated draft therefore resurfaced to the top as freshly created, regardless of its real age. Add an optional created_at override to the update_draft request, threaded into the upsert as COALESCE($8, now()) / created_at = EXCLUDED.created_at. Normal saves omit it and still stamp now(); the migration passes the draft's original write time (or epoch 0 when unknown) so migrated drafts keep their age. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1d87ca5958 |
address codex review (app draft no-op, view-only diff, comment) (#9639)
Three issues from the Codex PR review of the low-code app deploy + summary work: - [P1] The summary mirror onto the autosaved App value broke the autosave's no-op detection for deployed apps: `discardIf` compares the live value against the deployed baseline, but the baseline (the deployed App value) carried no summary while the live value now always does — so a draft reverted to the deployed state never compared equal and a no-op draft was persisted instead of deleted. Carry the deployed summary onto the baseline so the comparison matches (a summary-only edit still counts as a real change). - [P2] "Show diff" stayed enabled for view-only (`mine=false`) rows in the "Show all drafts" view, but the diff only fetches the current user's draft overlay — wrong diff for another user's deployed-row draft, 404 for their draft-only row. Hide it for foreign rows; own/legacy rows keep it. - [P2] Reword the `rawAppDraftValue` doc comment to state the current invariant (must read a draft's top-level `files`) instead of referencing past drafting history, per AGENTS.md. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e09cd5862c |
feat: per-user draft review & deploy page (gating, badges, rename, raw-app deploy fixes) (#9625)
* feat: per-user draft gating, badges and rename display on deploy page Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): don't strike the path when a draft adds a summary to a summary-less item Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): don't strike draft-only items' auto-generated path against the pretty path Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): deploy raw-app drafts from top-level files so the bundle isn't dropped Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): share raw-app source→draft-value projection across chat and deploy page Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): deploy renamed/new flow, app and raw-app drafts at draft_path, not the temp storage path Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): add a design-system Checkbox and use it for deploy-page row/select-all checkboxes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: "Show all drafts" toggle on the deploy-drafts page Replace the deploy-drafts page's legacy-hiding "Only my drafts" toggle with a "Show all drafts" toggle that switches the listing scope between the current user's own drafts (+ legacy no-owner rows) and every user's drafts in the workspace. Backend (`drafts.rs`, `openapi.yaml`): - `/drafts/list` gains an `all_users` query param that drops the owner filter, and a per-row `mine` flag (own draft or legacy no-owner row). `DISTINCT ON` now prefers the user's own row, then the legacy row, then another user's, so `mine`/`legacy_draft` describe the kept row. Frontend (`CompareDrafts.svelte`, `workspaceDrafts.svelte.ts`): - "Show all drafts" toggle (default off). The all-users superset is fetched lazily via the shared resource only while the toggle is on, so the page's fork draft-count (own drafts) is unaffected. - Other users' drafts are view-only: disabled checkbox + Discard with a "belongs to another user" tooltip; Show diff stays enabled. Selection, select-all and the deploy count only ever include the user's own drafts. The multi-user warning triangle shows on owned rows only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(backend): gate all_users draft listing by read permission Addresses the PR review on the per-user deploy-drafts page: - `/drafts/list?all_users=true` previously had only `WHERE workspace_id = $1` with no read-permission check, so any non-operator could enumerate every draft's path, summary and authors — including items they can't read. Now rows the caller doesn't own (`mine = false`) are gated through `require_can_read_path` (the same gate `/drafts/get` uses) and dropped when unreadable; both its `NotFound` and `NotAuthorized` denials are treated as "not visible". - Skip the per-row `require_can_write_path` probe on those non-owned rows (they're never selectable — `isSelectable` requires `mine`): set `can_write = false` directly, removing a redundant N RLS write-probes when `all_users` is on. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): only confirm destructive draft discards on the deploy page Discarding a draft is non-destructive in every case except removing the last draft of a never-deployed item (`draft_only` with no other user's draft), which permanently deletes it. Confirm only that case; reverting a draft over a deployed item, or discarding your copy while another user still holds a draft, now runs immediately (the ⚠️ already signals the multi-user case). Drops the redundant "other users still have a draft" / "deployed version unaffected" confirmation branches. Harden the destructive check: it keyed off `otherDraftUsers()`, which subtracts `currentUsername`; while `$userStore.username` is unhydrated, your own draft looked like another user's, flipping a draft-only item to "non-destructive" and deleting it with no confirmation. Now: deployed counterpart → never destructive; `draft_only` with unknown `currentUsername` → treated as destructive (confirm). The delete modal also shows the friendly `draft_path` instead of the raw `draft_{uuid}` storage path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): deploy low-code app drafts (value + summary persistence) A visual (low-code) app draft is autosaved as the *bare* App value (grid/theme/... plus a draft-only `draft_path`), not wrapped in { value, summary, policy } like script/flow drafts. The Review & Deploy page read `requestBody.value = d.value` — undefined for that shape — so deploying any low-code app draft (created or edited) sent no value and failed. Read the value from the draft object itself, strip the draft-only `draft_path` from it, and use that as the deploy path. Also persist the app summary, which was dropped entirely: the autosave stores the bare App value (the summary normally lives only in the `app` table column, set on deploy), so a draft never carried it — reopening a draft or deploying it lost the summary. Mirror the summary onto the autosaved App (like `draft_path`), read it back when loading a draft, and on deploy send it as the summary column while stripping it (and `draft_path`) from the deployed value so the value stays clean. Verified end-to-end: a new low-code app with a summary deploys at its pretty path with the summary set, content intact, and no draft_path/summary leaked into the deployed value; the draft is cleaned up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b67c8cf42b |
fix(frontend): render Modal2 dialogs above the AI chat panel (#9636)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f4425fca9f |
feat(ai-chat): self-hosted docs tools via windmill.dev llms.txt + ask benchmark (#9578)
* feat(ai-chat): add self-hosted docs tools fetching from windmill.dev llms.txt Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(ai-evals): add ask benchmark mode comparing inkeep vs llms.txt docs tools Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(ai-chat): fix docs link sanitizer tests to match skip-all-`../` guard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(ai-chat): add hybrid full-text docs search tool and ask variant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(ai-chat): expose docs search tools in the global workspace assistant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(ai-chat): drop inkeep/llmstxt arms, keep only hybrid docs search Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(ai-chat): remove docs-tool benchmark write-up Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(ai-evals): remove ask mode, cover docs search via global mode Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * nits * refactor(ai-chat): swap navigator + api copilots from inkeep to search_docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ai-chat): point read_docs_page empty-path hint at search_docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
51bd8692a4 |
feat: queue messages typed while ai chat is streaming (#9525)
* feat(frontend): queue messages typed while ai chat is streaming * fix(frontend): avoid losing queued chat messages on send early-return * test(frontend): cover queued chat message semantics in AIChatManager * fix(frontend): complete ChatLoopResult mock in queued message tests * feat(frontend): single appendable queued message, send on cancel * fix(frontend): only auto-send queued message on a user cancel, not programmatic * chore(frontend): remove queued-message dev preview page * fix(frontend): clear queued chat message on conversation switch |
||
|
|
2523465009 |
fix(frontend): don't save drafts on leave when auto-save is off, warn instead (#9630)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e6b45c4eee |
chore(main): release 1.728.1 (#9628)
* chore(main): release 1.728.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.728.1 |
||
|
|
86d1d160f0 |
fix(cli): fall back to esbuild-wasm on native host/binary mismatch (#9629)
* fix(cli): fall back to esbuild-wasm on native host/binary mismatch Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(cli): guard tarball extraction, extend esbuild-wasm fallback to script bundling Address CI review: prevent tar-slip in esbuild-wasm package extraction, route codebase/script and inline-rawscript bundling through getEsbuild() too, and move the loader to utils. Add a unit test for the tar-slip guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(cli): make esbuild-wasm fallback concurrency-safe Address CI review (P1): memoize getEsbuild() on an in-flight promise so concurrent first callers (parallel wmill sync push) share one probe/download instead of racing, and give each extraction a unique temp dir so concurrent extractions can't clobber each other. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8a3f69dda8 |
fix(backend): purge workspace_diff cache on workspace delete (#9627)
* fix(backend): purge workspace_diff cache on workspace delete Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(backend): add sqlx cache for workspace_diff regression test queries Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(backend): clear stale fork diff state on fork creation and backfill Purge inherited workspace_diff/skip_workspace_diff_tally rows when a fork is created (reused ids would otherwise leak a prior occupant's cached diff state), and extend the cleanup migration to drop live-pointing stale skip rows that short-circuit compare_workspaces before the has_changes reset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e4bfeb29bc |
fix(frontend): persist session-editor draft path/summary edits + per-line diff tooltips (#9622)
* fix(frontend): persist raw-app draft path edits in the session editor Renaming a raw app's path in the session preview editor never triggered a draft save: the header surfaced the typed path as `pendingDraftPath`, but RawAppEditorView ignored it (it never reached runtime.rawApp.val), and the RawAppDraft codec didn't serialize a path field — so the autosave signature (JSON.stringify(draft)) was unchanged and nothing was written. The rename was lost and the home/review/Drafts lists kept the original `draft_path`. - appDraftCodec: make `draft_path` a real draft + runtime field, serialized by runtimeRawAppToDraft and round-tripped by applyDraftToRuntimeRawApp, so a path change moves the sig and fires a save. - sessionRuntime.loadRawApp (+ inline rawApp.val type): seed `draft_path` from the loaded draft so it survives reloads. - RawAppEditorView: bind the header's `pendingDraftPath`, mirror it into runtime.rawApp.val.draft_path (guarded so the initial undefined can't clobber the seed or fire a spurious save), and seed the path widget from `draft_path ?? path`. Mirrors the full-page /apps_raw/edit route. - appDraftCodec.test: add a draft_path round-trip test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): per-line tooltips in workspace item diff rows The summary line now shows the full summary on hover and the path line the full path, instead of one row-level title surfacing the path everywhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): persist flow/script draft path edits in the session editor The session sync dedups on a per-kind signature that omitted the path, so a rename never moved the signature and never autosaved. Add path/draft_path to the flow signature, and derive draft_path in the script codec (scripts bind the Path widget to script.path directly) so the rename both autosaves and shows the typed name in the home/Drafts lists. Mirrors the raw-app fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): commit editor summary edits live instead of on blur EditableInput only fired onSave on Enter/blur, so the summary in the shared editor header only updated when the field lost focus. Add an opt-in commitOnInput that fires onSave per keystroke and enable it for the header summary, so flow/script/raw-app summaries autosave as you type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): preserve renamed never-deployed script path on session re-seed loadScript seeded a draft-only script's baseline path from the storage key, so re-running it with the draft still in memory (e.g. a script→script switch) reset the path to draft_<uuid> and the next autosave dropped draft_path, clobbering the rename. Seed from the draft's own draft_path/path instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): clear raw-app draft_path when the path rename is reverted The mirror effect only ever set draft_path, so reverting/clearing the path field left a stale friendly name in the draft (persisted by the codec and shown in the home/Drafts lists). Track whether a real typed path was surfaced so a revert clears draft_path while the initial pre-bind undefined still can't clobber the loadRawApp-seeded value. Mirrors the script codec's drop-on-revert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f9cfeb0dba |
chore(main): release 1.728.0 (#9613)
* chore(main): release 1.728.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.728.0 |
||
|
|
a2ce44645f | feat(frontend): dedup user drafts against the deployed baseline (#9618) | ||
|
|
651fa13ee8 |
fix: show folder labels in the folder list table (#9620)
Surface folder labels in the /folders table via a new "Labels" column between Name and Scripts, rendered as blue badges with a +N overflow indicator (first 3 shown), matching the script row pattern. Previously labels were only visible inside the folder editor drawer. Fixes WIN-2056 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
46288b6143 |
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> |
||
|
|
7cb5c6e749 |
fix(frontend): reset deleteWorkspaceForkModal on confirm in SidebarContent (#9619)
The on:confirmed handler for the delete-fork ConfirmationModal never reset deleteWorkspaceForkModal to false. Since SidebarContent persists across workspace switches, the stale true state caused the delete-fork modal to immediately reappear when a new fork workspace was created. Reset the state before calling deleteFork(), matching the on:canceled handler and the pattern in forks/compare/+page.svelte and SessionWrapper.svelte. Fixes WIN-2057 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
46345e9ee7 |
backfill legacy draft emails from usr table (#9616)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
bc0d5bf241 |
feat(frontend): consolidate draft-migration errors into a single toast + modal (#9612)
* Draft migration error modal * nits |
||
|
|
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> |
||
|
|
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 |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
cd098700c2 |
fix(cli): harden legacy flow lock migration ordering and collision guard (#9557)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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 |
||
|
|
9de5708608 |
feat(audit): record workspace archive/unarchive/delete in instance audit log (#9596)
Archiving a workspace sets `deleted = true`, hiding it from the workspace switcher for everyone (the `user_workspaces` query filters `workspace.deleted = false`). The archive/delete actions were audited only inside that same workspace's audit log, which then becomes inaccessible — so there was no durable, discoverable record of who archived or deleted a workspace, or when. Also write these lifecycle events under the instance-level `admins` workspace, the canonical instance-audit scope (a superadmin querying `admins` with `all_workspaces=true` sees entries across all workspaces). The target workspace id is carried in the audit `resource` field and the actor in the author. For delete, the per-workspace rows are removed in the same transaction, so the instance-level entry is the sole durable record. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6a6295921d |
fix(embeddings): retry HuggingFace model downloads with backoff (#9597)
Caching the gte-small embedding model fetched config.json / tokenizer.json /
model.safetensors from HuggingFace with no retry, so a single transient
network error ("error sending request for url ...") failed the whole image
build. Wrap each download in a retry loop (up to 5 attempts, exponential
backoff capped at 8s) that logs each retry and surfaces the error only after
the final attempt. No new dependency.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
5ccaae8ab3 |
fix: resolve release CI failures (pypi bundle, flow serde test, cli windows) (#9595)
Three independent failures on the latest release commit: - pypi (Publish python-client): the `UserDraftOverlay`/`UserDraftItemKind` schema definitions were placed inside the `# -- INLINE START/END --` markers in openapi.yaml. The python-client build replaces that whole block with a wildcard import of `openflow.openapi.yaml`'s schemas, which do not define these two, so every `$ref` to them became unresolvable and the redocly bundle aborted. Move both definitions outside the markers — they are windmill-api schemas, not openflow-mirrored ones. - flows::tests::flowmodule_serde: the expected JSON still carried `"error_message": null` in three `stop_after_if` blocks, but StopAfterIf.error_message is now skipped when None. Drop those keys. - CLI Tests (test-windows): preservePendingScriptLocks mixed the OS path separator (SEP) into map keys that are always forward-slash normalized, so on Windows the multi-module suffix match and the lock-file lookup both failed. Use forward slashes consistently; this also fixes real Windows git-sync deploys, not just the test. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5709a564fb |
feat(frontend): add user-level toggle to disable Windmill AI (#9585)
* feat(frontend): add user-level toggle to disable Windmill AI Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): hide AI sessions sidebar section when AI is disabled Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8643e68891 |
chore(main): release 1.725.1 (#9589)
* chore(main): release 1.725.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>v1.725.1 |
||
|
|
6b916ac688 |
fix(cli): preserve committed script.lock on transient NULL lock during git-sync deploy (#9593)
* fix(cli): preserve committed script.lock on transient NULL lock during git-sync deploy (#9588) A script's `lock` is NULL on the server only while a relock is mid-flight (an importer relock after a relative-import dependency changed, or the script's own first lock job). The git-sync deploy mirror reads the workspace inside that window, sees no lock, and mirrors the transient NULL as a deletion of the committed `.script.lock` plus a strip of the `lock: '!inline …'` line — corrupting the git mirror until the relock writes the identical lock back seconds later. When pulling (remote -> local), carry the local committed lock onto the remote map when the remote lock is NULL, so the diff is a no-op for both the lock file and the metadata line. An empty-string lock ('') — the real "no dependencies" state — is left untouched, so genuine lock removals still propagate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(cli): cover __mod multi-module scripts in pending-lock preservation Address auto-review on #9593: the lock-file key was reconstructed from the metadata path (`.script.yaml` -> `.script.lock`), so a multi-module script whose lock lives at `…__mod/script.lock` fell through unprotected. Derive the key from the committed `!inline` reference instead (covers both the dotted and `__mod` folder layouts) and detect the folder-layout metadata file. The reference is always forward-slash; convert to the OS separator so the local map lookup matches on Windows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e1e2a24b6a |
fix(flows): stop serializing default retry/stop_after_if fields (#9583)
A flow module with a constant-only retry is stored by the frontend as
`{ constant: {...} }`, but round-tripping through the `Retry` struct (e.g.
the dependency/lock job, which re-serialises the flow value) materialised a
full default `exponential` block (`seconds: 0`, `random_factor: null`) and a
`null` `error_message`, because those fields are non-`Option` / `Option`
without `skip_serializing_if`. The defaults then got baked into stored data,
surfaced on `wmill pull`, and were rejected by the linter.
Skip serialising `Retry.constant`/`Retry.exponential` when they equal their
default, and `StopAfterIf.error_message` when it is `None`. Deserialisation is
unchanged (`#[serde(default)]` refills the in-memory structs), so the worker
retry logic and the frontend (which already optional-chains these fields) are
unaffected.
Verified end-to-end against a running backend: a flow created with an explicit
default exponential block + `error_message: null` comes back clean after its
lock job re-serialises it.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
aff0a4ec18 |
fix(security): sanitize dependency names & connection strings against command/SQL injection (#9590)
* fix(security): sanitize dependency names & connection strings against command/SQL injection Follow-up to the PowerShell module-name injection fix (#9587, CWE-78): the same audit surfaced the identical "secondary identifier interpolated into an interpreter/SQL command without escaping" pattern in a few other executors. - R executor (the real twin, HIGH): package name/version parsed from a user-supplied renv.lock were interpolated raw into an `Rscript -e "...renv::install(\"{pkg}@{version}\"...)"` eval string. A double-quote in the name/version broke out → arbitrary R (unsandboxed under DISABLE_NSJAIL / non-Linux). Now validated in parse_renv_lock (charset) and escaped at the sink as defense-in-depth (also escapes the lib path, which holds backslashes on Windows). - DuckDB ATTACH (MED): the connection string built from resource fields (host/db/user/password) is embedded in a single-quoted DuckDB literal; escape quotes so a field value can't break out of the ATTACH statement. - PgDatabase::to_uri: URL-encode host and dbname (user/password already were), so '@'/'/'/'?'/'&' can't reshape the parsed URI (feeds live PG connect and DuckDB ATTACH). - DuckDB CREATE SECRET (FFI): wrap the interpolated S3 key/secret/endpoint in the existing sql_single_quote() helper, consistent with the resource-limits setup right above it. - PowerShell: also escape the configured private repo URL/PAT in the install template (same sink as the module names; the escape landed after #9587 was squash-merged so it was not in the merged change). Adds unit tests for the R validation/escaping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(security): escape ducklake/snowflake/bigquery identifiers; preserve IPv6 host - to_uri: don't percent-encode bracketed IPv6 literal hosts ([::1]) — encoding their brackets/colons would stop them parsing as a host (review fix). - duckdb ducklake ATTACH: the catalog conn string, storage and data_path are embedded in single-quoted DuckDB literals; escape quotes so a resource field can't break out (the ducklake path bypassed the ATTACH escape added earlier). - snowflake: validate account_identifier (it forms the request hostname). - bigquery: validate project_id (it forms a request URL path segment). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |