Commit Graph
14108 Commits
Author SHA1 Message Date
Ruben FiszelandClaude Opus 5 4145e6f162 feat: hide empty owners from the homepage chips and cap them at 20 (#10360)
* feat: hide empty owners from the homepage chips and cap them at 20

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review nits on the homepage owner chips

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:56:00 +02:00
Ruben FiszelandClaude Opus 5 6e56ce11db fix(ai): make the proxy and the AI agent step read a resource the same way (#10359)
The two paths derive the endpoint and the credential header independently, so a
resource could authenticate in one and 401 in the other. A parity test pins them
together across the provider/platform matrix and fails on each divergence below.

- Anthropic base URLs were read differently: the proxy trimmed and re-appended
  `/v1` while the agent step appended `/messages` to the stored value, so a
  `.../anthropic` base worked in workspace settings and 404'd in an agent step.
  `build_anthropic_api_url` accepts both forms for both paths, and the URL no
  longer depends on the client-supplied `X-Anthropic-SDK` header, which is gone.
- A base URL stored with a trailing slash doubled it in an agent step.
- An OpenAI resource pointed at Azure got Azure's URL layout and `api-key`
  header from the proxy but bearer auth and the plain path from the agent step,
  where `OpenAIQueryBuilder` ignored `is_azure`.
- The agent step sent an empty credential when the resource had no api key,
  where the proxy sends none at all. `retain_effective_credentials` gives both
  the same rule, so an endpoint that authenticates another way still works.
- An OAuth resource cannot resolve to a token in a worker: there is no client
  credentials exchange there, so it now fails with that reason unless it carries
  the credential header its provider reads.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:38:13 +02:00
Ruben FiszelandClaude Opus 5 b9960267bb fix(cli): resolve module script metadata on windows path separators (#10358)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:00:08 +02:00
Ruben FiszelandClaude Opus 5 ebf68d7970 fix(ai): support OpenAI/Anthropic-compatible gateways in workspace AI settings (#10356)
* fix(ai): stop breaking OpenAI-compatible gateways in workspace AI settings

The workspace/instance AI proxy sent credentials in a shape that
OpenAI-compatible and Anthropic-compatible gateways reject, while the same
resource worked in an AI agent step:

- `is_azure` treated *any* OpenAI base URL other than api.openai.com as Azure,
  so a gateway got the Azure `api-key` header instead of `Authorization: Bearer`
  and an `/openai/v1/`-rewritten path. Match on the host instead.
- The Anthropic proxy sent both `authorization: Bearer` and `X-API-Key`.
  Gateways reject ambiguous credentials; send only the header the endpoint
  expects, matching `get_auth_headers` and the agent-step path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): match Azure on the endpoint and let resource headers own auth

Review follow-ups:
- Azure OpenAI reached through a custom domain keeps its `/openai/deployments`
  path, which `openai_azure_base_path` documents; match on it so those
  instance-wide settings are not reclassified as plain OpenAI-compatible.
- Cover the sovereign-cloud API Management suffixes and FQDNs with a trailing
  dot.
- A resource that supplies its own `authorization`/`x-api-key` header now
  suppresses the built-in one. Outgoing headers are appended rather than
  replaced, so both credentials used to travel, which is exactly what gateways
  reject; this is the escape hatch for endpoints wanting bearer auth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): give the agent step the same resource-header credential rule

Review round follow-ups:
- `ai_executor` appended the query builder's credential header alongside the
  resource's, so an AI agent step still sent two credentials where the proxy now
  sends one. Both paths share `resource_owns_credentials`/`CREDENTIAL_HEADERS`;
  non-credential headers such as `anthropic-version` are kept.
- Cover the OpenAI-compatible proxy's suppression branch with a test.
- Match the Azure deployments path case-insensitively, like the host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): scope the credential override to the header the provider uses

A resource header now replaces the built-in credential only when it is the same
header the provider authenticates with, or an `authorization` one (which every
endpoint reads as the credential). Matching any credential-shaped header let an
OpenAI-compatible resource's `x-api-key` routing header suppress the bearer
token. Google AI's `x-goog-api-key` joins the list so the override reaches that
provider too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(ai): share credential and trailing header assembly across AI paths

The proxy and the AI agent step each assembled outbound headers themselves, so
this fix had to be applied at three sites and the rules could drift apart
silently. Two pieces move into `proxy`:

- `credential_header` picks the credential to send, applying the resource
  override. `authorization` carries a bearer token and every other credential
  header carries the raw key, which holds for every provider.
- `common_outbound_headers` yields Windmill's own headers then the resource's,
  the tail every outbound request shares.

A resource resolves to an api key or an OAuth token, never both, so selecting
one drops the branch that could emit two `authorization` headers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): keep OAuth tokens on the bearer header

An OAuth resource resolves to an access token, which every provider reads from
`authorization` — Azure OpenAI accepts api keys in `api-key` but Entra ID tokens
only as a bearer. Sending it in the provider's key header left Azure OpenAI and
Foundry Claude OAuth resources unauthenticated.

Also covers the credential-override narrowing: a credential-shaped header the
provider does not authenticate with is an ordinary header and must not suppress
the built-in credential.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 15:23:49 +02:00
Ruben FiszelandClaude Opus 5 50da65c886 feat: show per-owner runnable counts in the homepage tree (WIN-2253) (#10351)
* feat: show per-owner runnable counts in the homepage tree

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: exclude pipeline members from runnable owner counts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: address review findings on runnable owner counts

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: avoid tree reflow while counts load and label pipeline rows

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: drop collapsed owners' cached rows when the tree scope changes

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: untrack tree owners whose node is removed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:57:54 +02:00
Ruben Fiszel f9d5da11b7 feat: allow changing an account email in the superadmin settings (#10355)
* feat: allow changing an account email in the superadmin settings

* fix: cover slack_email and usage rows, and scope job rewrites to the queue

* fix: compare the destination email case-insensitively

* fix: only warn about the consequences once the email is edited

* docs: warn that changing an account email is a last resort

* fix: repoint app policies and raw-email permissioned_as, reject self-change

* fix: repoint folder default rules and guard the varchar(55) job column
2026-07-27 14:54:23 +02:00
Ruben FiszelandClaude Opus 5 cdd8718a93 fix(cli): sync push no longer reports success on a script it never deployed (#10353)
* fix(cli): do not report success when sync push drops a script metadata change

`sync push` skipped every added `.script.yaml` / `.script.json` / `.script.lock`
on the assumption that the sibling content file in the same group carried the
deploy. When the content file was not in the changeset — e.g. filtered out by
`excludes` — nothing was sent to the remote, yet the push still printed
"Done! All N changes pushed" and exited 0, so CI gating on the exit code went
green on a deploy that never happened.

Route those changes through `handleScriptMetadata` (as the "edited" branch
already does), which resolves the content file from disk and deploys it. The
deploy stays idempotent via `alreadySynced`, and a metadata file with no content
file now fails the push instead of being counted as pushed.

Fixes WIN-2254

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): treat only the module entry point as script metadata

`handleScriptMetadata` / `findContentFile` matched any `script.yaml`,
`script.json` or `script.lock` anywhere under a `__mod/` tree, so a module file
nested deeper (e.g. `f/foo__mod/config/script.yaml`) was mistaken for the
script's own metadata. Gate on `isModuleEntryPoint`, which requires the file to
sit directly under `__mod/`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): reject non-metadata paths in findContentFile

Every candidate-path replacement in findContentFile is a no-op on a path that
is neither flat `*.script.{yaml,json,lock}` nor a module entry point, so the
input resolved to itself and the caller got a "more than one candidate found"
list of 25 copies of the same path. Reject those inputs up front.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): report an unpushable script as a failure instead of aborting the push

Throwing out of the apply loop for a metadata file with no script file left the
push partially applied: every change queued behind it was dropped, including
ones with nothing wrong. Collect these into a failed list, log each one, keep
applying the rest, and report `N of M changes pushed; K failed` with a non-zero
exit (`success: false` plus a `failed` array under --json-output).

Only the content-resolution failure is soft, via MissingScriptContentFileError.
A deploy the remote rejected still aborts, since it says nothing about whether
the remaining changes are safe to apply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): let stdout drain before sync push returns a failure exit code

process.exit does not wait for a pending piped stdout write, so a --json-output
push with enough changes was cut off at the 64KiB pipe buffer, handing CI
consumers unparseable JSON. Set process.exitCode instead and return normally,
matching how main.ts already reports failures.

Reproduced with a 1904-change push: process.exit truncated the result at exactly
65536 bytes; process.exitCode emits all 432KiB and still exits 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): treat an ambiguous script file as a recoverable push failure

findContentFile has two ways to fail to pair a metadata file with a script
file, and only the "none found" one threw the class sync push catches. Two
script files for the same name (a .ts and a .py both being in exts) therefore
still aborted the whole push, dropping every change queued behind it — the
failure mode failedChanges exists to prevent, newly reachable now that an added
.script.yaml reaches findContentFile at all.

Both branches now throw the same class, renamed to
UnresolvableScriptContentFileError since it no longer only covers a missing
file, and the ambiguous case gets a message that names the clashing files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 13:21:50 +02:00
Ruben Fiszel a8ef98edff feat: build a React raw app from the script and flow detail pages (#10337)
* feat: build a React raw app from the script and flow detail pages

* fix: keep generated raw-app state and setter names unique

* fix: make the generated app readable on dark and handle labeled enums

* fix: reserve the undefined binding in generated raw apps

* fix: mask password args, keep __proto__ args, and enforce required inputs

* fix: quote non-identifier arg names, preserve JSX entities, support resource args

* fix: JSON-quote generated arg keys and start resource fields empty

* fix: render array enums as multi-selects and let optional enums be omitted

* fix: stop the generated template naming Math/Array and omit untouched optional json

* fix: enforce required on array-enum multiselects
2026-07-27 12:53:43 +02:00
Ruben FiszelandClaude Opus 5 be5e3bbfc4 fix(wac): checkpoint step errors so a caught exception does not hang replay (#10348)
* fix(wac): checkpoint step errors so a caught exception does not hang replay

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): honour a step suspend the workflow body caught and swallowed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): park every suspend, not only those from a failing step

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(wac): keep the generated bun wrapper comment-free

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(wac): park the child task-completion suspend and align error identity

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(wac): pin the TaskError identity of replayed step and task failures

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 12:38:32 +02:00
Ruben Fiszel 78e115bee5 fix: datatable full schema hangs behind a transaction-pooling postgres proxy (#10352)
* fix: datatable full schema hangs behind a transaction-pooling postgres proxy

* test: pause the clock in the pg connection shutdown test
2026-07-27 12:32:44 +02:00
Ruben FiszelandClaude Opus 5 9bbfe12011 fix(frontend): stop spurious asset analysis toasts in the flow editor (#10349)
* fix(frontend): stop spurious asset analysis toasts in the flow editor

The flow editor asks "Assets were detected in this step. Analyze entire
flow for assets?" whenever a raw script step without asset metadata is
selected and its code turns out to declare assets. Nothing recorded that
the question had already been asked, and the selection watcher is
re-created (and fires) on every structural change to the flow, so the
prompt reappeared on every step click and every time a step was added.
Steps created during the session — most visibly the ones an AI agent
inserts one by one — were also treated as legacy steps, so each new step
raised its own prompt even though writing their assets only completes an
edit the user already made.

Ask at most once per editor session, restrict the prompt to the modules
the flow was loaded with, and skip re-analyzing a module whose content
has not changed since its last parse.

Fixes WIN-2251

* fix(frontend): key the asset inference cache on language and replay it

inferAssets depends on the module's language as well as its content, and
the content-only cache also turned a re-derivation into a no-op whenever
the assets field alone was reset (undo/redo, reset to deployed, AI diff
apply). Cache the inference result keyed on both inputs and re-apply it
on a hit, so a cache hit is idempotent rather than a skip; that also
removes the need for analyzeEntireFlow to force a re-parse.

Cached values are copied before reaching the flow store, which would
otherwise proxy them and let a later replay mutate the cache in place.

Accepting "Analyze entire flow" now carries over to modules analyzed
later in the session instead of leaving them for a prompt that will not
be shown again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(frontend): build the asset cache key without a raw NUL byte

The separator was written as a literal U+0000, which makes git treat the
Svelte source as binary: diffs render as +0/-0, blame and log -p stop
working, and ripgrep skips the file. Build the key with JSON.stringify
instead, which is unambiguous and keeps the file ASCII.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 12:20:21 +02:00
Ruben FiszelandClaude Opus 5 4b7ab64a48 fix: enforce per-job authorization on cancel and force_cancel endpoints (#10341)
* fix: enforce per-job authorization on cancel and force_cancel

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: authorize force_cancel on the ancestor it actually kills

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: fail closed when the force_cancel ancestor walk is truncated

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 10:59:50 +02:00
GuilhemandClaude Fable 5 9b55f1d67d fix: name the resource in the delete confirmation modal (#10344)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 10:52:47 +02:00
GuilhemandClaude Fable 5 0f62891d43 fix(ai): stop teaching nonexistent while-loop iter.value state-carrying (#10345)
* fix(ai): stop teaching nonexistent while-loop iter.value state-carrying

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): scope while-loop results guidance to cross-iteration reads only

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): drop unverified wmill state-helper fallback from while-loop guidance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): document supported cross-iteration results state in while loops

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai): rescope while-loop fast-path rule and add results-carrying example

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 10:42:33 +02:00
Ruben Fiszelandrubenfiszel 907141152e chore(main): release 1.771.1 (#10336)
* chore(main): release 1.771.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.771.1
2026-07-27 03:14:35 +02:00
Ruben Fiszel dc5182f86c fix: operators cannot see flows and apps on the homepage (#10340) 2026-07-27 03:05:42 +02:00
Ruben Fiszel 32c018dc85 fix: app stepper no longer runs its validation on subgrid focus (#10338) 2026-07-27 03:04:21 +02:00
Ruben FiszelandClaude Opus 5 023e85bd63 fix: open a pipeline step on its code, not its output (#10335)
* fix: open a pipeline step on its code, not its output

Clicking a script node in a pipeline replay landed on Output. The code is
what the step is, and it is the thing a viewer is usually there to read,
so open on it and put the Code toggle first.

Recordings made before `codes` existed carry no source, and defaulting
them to Code would open an empty pane saying nothing was captured, so the
default falls back to Output when the step has no recorded source. The
reset is keyed on the selected step, so a tab chosen by hand survives
until another step is opened.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor: depend the step-tab reset on the selected path alone

untrack the codes lookup so the effect tracks only which step is selected.
It could not loop either way — it never reads the tab it writes, and the
toggle group's programmatic dispatch settles on an identical value — but
the dependency set should say what the reset means: reset on a new step,
not on a new recording object.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 23:30:59 +02:00
Ruben Fiszel 434c4ac7c8 chore: pin ruff to 0.16.0 and keep the python editor rule set stable (#10331)
* chore: pin ruff to 0.16.0 and keep the python editor rule set stable

* chore: keep the ruff config path rationale at a single site
2026-07-26 14:10:02 +02:00
Ruben FiszelandClaude Opus 5 71575bf941 chore: remove the unreachable hub raw-app embed proxy (#10332)
The raw-app session recorder replaced the live-iframe demo, and removing
`Share as iframe` took the only caller of this proxy with it. Nothing in
the frontend, the CLI or the backend can reach `publish_raw_app_embed`
any more, so it is an authenticated route kept alive for no consumer.

The Hub still stores and renders `external_embed_url` for the raw apps
that already carry one, and still exposes its own editors for it; this
only drops Windmill's write path, which no longer has a producer.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 14:07:55 +02:00
Ruben Fiszelandrubenfiszel 3a08656dad chore(main): release 1.771.0 (#10316)
* chore(main): release 1.771.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.771.0
2026-07-26 11:56:50 +02:00
Ruben Fiszel e80fee86b3 feat: record and replay raw app sessions step by step (#10318)
* feat: record and replay raw app sessions step by step

* fix: address review findings on raw app session recorder

* fix: stamp replay target before pruning the snapshot clone

* fix: redact step metadata, lock down replayed frames, fix control pre-state

* feat: add a checkpoint timeline to the app recording player

* fix: parser-based replay CSP, fold label clicks, drop stale frame indices

* fix: scrub redacted attributes, keep scroll, neutralize replay navigation

* fix: bound replay payloads, strip namespaced nav links, keep control pre-frames

* fix: strip SMIL navigation, redact metadata sources, capture pre-edit on beforeinput

* fix: redact template content, drop shadow templates, make replays inert

* test: pin snapshot redaction and replay sanitization with DOM tests

* fix: allow-list no-record attributes and cover a marked document root

* fix: classify input types positively so pickers get pre-change frames

* fix: one step per control interaction and bound step metadata

* fix: keep button inputs recordable and coalesce only continuous controls

* fix: no frames for coalesced repeats and drop inline styles when redacting

* fix: fold only the label's own click and keep marked stylesheets out

* fix: keep label-forwarded and radio-group pre-frames, fold submitter clicks

* fix: bound key pre-frames to their gesture and clear ancestor pointer frames

* fix: age-bound pre-frames and treat a radio group as one target

* fix: consume pre-frames per interaction and coalesce on the browser repeat flag

* fix: spend only the pre-frame a step actually used

* fix: settle a step from its successor's pre-state and drop stale pointer frames

* fix: bound remote frame payloads and snapshot stylesheets as rendered

* fix: let a control change spend its own frame and dedupe Enter activations

* fix: record Escape on controls and drop disabled stylesheets

* feat: collapse the replay step list by default behind a toggle

* fix: neutralize disabled sheets in place and fold Enter submissions

* fix: withhold redacted control state, fold key repeats, validate remote metadata

* fix: drop noscript markup and fold implicit form submissions

* fix: mask a select whose chosen option is redacted

* fix: mask redacted select choices before the clone diverges

* fix: run clone-paired passes before removals and fold only Enter submissions

* feat: record a raw app demo from the publish flow instead of the viewer

* fix: wait for in-flight runnable jobs before settling a step

* feat: record from the editor menu and replay publicly at /replay

* feat: export the app recording player and its loader for the hub

* feat: publish from folders only, drop iframe sharing

* fix: observe runnable responses where they land and mount the hub recording route

* fix: respect the app's sandbox opt-in when recording a session

* fix: let stop wait for the runnable the last step is still running

* fix: filter redacted class/id to styled tokens and gate publish on admin

* fix: drop marked sheets from the token vocabulary and bound the replay error

* test: pin the remote app-recording validator

* fix: carry in-flight runnables across a reload and fold held keys into one step

* fix: bind runnable responses off the request and honor base in the replay handoff

* fix: close the settling step when a new fill starts and always re-read stylesheets

* fix: empty the no-record marker so it carries nothing of its own

* fix: decode css escapes so utility classes survive redaction

* fix: read keyDriven from the frame the change starts from

* docs: condense recorder comments to the invariant each protects

* fix: rewrite only real url() tokens and accept leading css escapes

* feat: play flow, script and pipeline recordings on the public /replay page (#10327)

* feat: play flow, script and pipeline recordings on the public /replay page

* fix: render a recorded approval result inert while replaying

* fix: bound an asset sample's cell product and validate recording headers

* fix: make a replayed approval step inert and bound nested recording structures

* fix: stop recorded markup from fetching and bound flow/script render trees

* fix: gate recorded markdown at its renderer and close remaining render-budget gaps

* fix: replace per-key render caps with one structural budget per recorded value

* fix: bound component fan-out and text alongside the structural budget

* fix: make component fan-out cumulative and cap the parsed data-test checklist

* fix: bound the whole recording, graph contents, metadata strings and timer bursts

* fix: keep the published loader path, charge object keys, refuse huge serialized fan-out

* fix: cap flat maps a renderer turns into rows (args, schema properties)

* fix: refuse structure hidden past the depth ceiling and bound errored samples

* fix: count array-shaped argument collections against the row cap

* feat: paint canvas pixels into the snapshot

* fix: budget canvas encoding per snapshot and bound the unknown-kind error

* fix: cap flow graph overlay fan-out and condense budget comments

* docs: teach the raw-app prompt about data-wm-no-record
2026-07-26 11:51:59 +02:00
Ruben Fiszel 2bf7746cdd fix: operators cannot archive or delete flows and apps (#10322)
`create_flow`/`update_flow` and `create_app`/`update_app` reject operators, but
`archive_flow_by_path`, `delete_flow_by_path` and `delete_app` did not — so an
operator with folder write could delete a flow or app they were not allowed to
edit. Scripts already get this right (archive is guarded, delete is admin-only).

Verified on a live instance: all three returned 2xx for an operator before, 401
after, and a non-operator member with the same folder write is unaffected.
2026-07-26 11:36:33 +02:00
Diego ImbertandClaude Fable 5 80ad357c06 fix: scope cd in parser wasm dev.nu so cli install path resolves (#10329)
* fix: scope cd in parser wasm dev.nu so cli install path resolves

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xKBCiRBL2NkvpgontuwYf

* Update dev.nu

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 11:36:24 +02:00
Ruben FiszelandClaude Opus 5 4d3ff0299f feat: mark failed jobs as resolved so handled failures stop showing red (#10319)
* feat: mark failed jobs as resolved so handled failures stop showing red

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: constrain auto-resolve to the proven retry chain and honor resolved filter everywhere

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: apply resolved filter to queue-union, concurrency and delete paths, bound note

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: sweep resolutions on workspace delete, verify helper args, enforce UI limits

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: count resolution note in characters on both sides of the API

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: skip the queue lookup for cancel-all under the resolved-only filter

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: converge retry auto-resolution from either commit order, keep notes on re-resolve

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: correct the idempotency claim on the retry auto-resolve sweep

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat: gate resolution notes and attribution behind enterprise, add note popover

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: hide resolution from operators, exclude flow steps, enforce EE licence at runtime

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: add job_resolution.automatic to the summarized schema

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: preserve stored attribution when re-resolving without a valid licence

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: condense the attribution-preservation comment to four lines

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: validate resolution notes by code point instead of a UTF-16 maxlength

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: keep the resolution popover open when a note is rejected

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat: offer to resolve the original failure after a successful re-run

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: verify supersession server-side and stop re-runs overwriting notes

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: apply tag scope to the superseding run

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix: exclude obscured cross-workspace runs from resolution actions

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:36:27 +02:00
Ruben Fiszel a8455acd7d feat: make bigquery and snowflake script languages available in CE (#10324)
* feat: make bigquery and snowflake script languages available in CE

* docs: add snowflake to backend cargo feature map

* fix: stop logging the snowflake bearer token at debug level
2026-07-25 12:07:28 +02:00
Ruben FiszelandClaude Opus 5 9cef724ff2 feat: bind WAC approval urls to a named wait_for_approval step (#10317)
* feat: bind WAC approval urls to a named wait_for_approval step

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject duplicate WAC approval step keys instead of renaming them

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject WAC approval links minted for a step that is not awaiting approval

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: bind WAC approval links to the awaiting step and stop step key aliasing

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject empty approval keys and scope minted-key writes to the workspace

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: enforce WAC approval binding at consumption and reject colliding keys

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: make WAC approval binding and collision checks atomic, harden TS step keys

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: decrement WAC suspend atomically instead of from a pre-lock snapshot

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: add sqlx cache entry for the atomic WAC suspend decrement

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: omit empty approver param from python get_approval_urls

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: pin the suspend-snapshot decrement and the colliding-mint race

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: drop the suspend-snapshot interleave test, it cannot both be stable and discriminate

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject step keys that cannot be minted as a URL path segment

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 11:41:48 +02:00
Ruben FiszelandClaude Opus 5 15a6382c89 remove unused mut breaking backend CI (#10320)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 09:32:01 +02:00
Ruben FiszelandClaude Opus 5 65db58bfda fix(frontend): pin sveltekit version.name so builds are reproducible across architectures (#10315)
* fix(docker): pin frontend build stage to linux/amd64

Rollup selects platform-specific native binaries that can emit different
content-hashed chunk filenames for identical sources. The frontend assets are
embedded into the Rust binary via rust_embed, so building the stage once per
target architecture produced amd64 and arm64 images whose HTML references
`_app/immutable/chunks/<hash>.js` files that only exist in that architecture's
image. In a mixed-architecture cluster, a page served by a pod of one arch 404s
on JS/CSS fetched from a pod of the other.

Pinning the stage makes both image variants embed byte-identical assets. The
stage output is JS/CSS/HTML/WASM only, so the build platform does not leak into
the artifacts.

Fixes WIN-2242

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: tighten frontend platform-pin comment

Vite 8 bundles with rolldown, not rollup; name the right bindings and keep the
constraint to four lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(frontend): make the build reproducible so mixed-arch clusters agree on asset names

SvelteKit defaults `kit.version.name` to `Date.now().toString()`, so every build
of the same commit gets a different version string. It is embedded in the client
chunk (and in the `__sveltekit_<hash>` global derived from it), which changes
that chunk's content hash and cascades into new filenames for roughly a quarter
of `_app/immutable`. The assets are baked into the binary via rust_embed, so the
amd64 and arm64 images of one release ship different `chunks/<hash>.js` names:
in a mixed-architecture cluster, HTML served by a pod of one architecture 404s
on assets requested from a pod of the other.

Measured on the published windmill:1.770.0 images: 224 of 863 asset filenames
differ between the two architecture variants, yet 854 of 855 chunks are
byte-identical once chunk-name references are normalized. The single genuinely
differing chunk is the one carrying the timestamp. The bundler is deterministic
across architectures; the timestamp is the whole divergence.

Pinning the version to the package version (overridable via WM_BUILD_VERSION)
makes repeat builds byte-identical. `version.pollInterval` is 0 and nothing
reads the `updated` store, so this has no runtime behavior change.

This supersedes pinning the Docker frontend stage to linux/amd64, which fixed
the symptom by building the stage under emulation on the arm64 builder — that
cost 32 minutes of QEMU time per build and left the underlying non-determinism
in place.

Fixes WIN-2242

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(frontend): key the sveltekit version on the commit sha

The package version only moves on releases, but `:dev` and RHEL images are
published on every main push. Two such deployments would then advertise the same
SvelteKit version, and SvelteKit only recovers from a chunk that 404s after a
redeploy (client.js: "Referenced node could have been removed due to redeploy")
when the deployed version differs from the baked-in one, so an open tab would
render an error page instead of reloading.

Pass the commit sha through WM_BUILD_VERSION from every workflow that builds the
root Dockerfile, so the value is identical across the per-architecture builds of
one commit and distinct between commits. The package version stays the fallback,
which keeps unwired builds architecture-consistent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(docker): declare WM_BUILD_VERSION in the RHEL frontend stages

The RHEL workflows copy docker/RHEL{8,9}/Dockerfile over the root one before
building, so the build-arg was unconsumed there and those images fell back to
the package version: two RHEL builds between releases would share a SvelteKit
version across different manifests.

Also switch the root declaration to the `ARG name=""` form used by `features`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: keep the version-arg rationale in one place

The root Dockerfile comment restated what frontend/svelte.config.js already
documents; point at it instead, matching the RHEL Dockerfiles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 23:55:47 +02:00
Ruben Fiszel 71b7135cf2 feat: multiple homepage sort orders via an efficient merged runnables endpoint (#10297)
Adds recently-updated / oldest / name A-Z / name Z-A sort orders to the homepage (WIN-2236), produced server-side by a new merged, index-backed, keyset-paginated GET /w/{workspace}/runnables/list so a chosen order is globally correct across scripts + flows + apps and stays efficient on large workspaces.

- Backend: UNION ALL of script/flow/app ordered by index (Merge Append + LIMIT); keyset (sort_key, path, kind, tiebreak) cursor; per-branch LIMIT bounds correlated projections; starred-first pinning; RLS + scope-token filters in SQL. Archived view returns the latest row per path. Migration adds time + lowered-name indexes (built CONCURRENTLY).
- Frontend: server-side sort/kind/owner filters + hybrid search (instant client + on-demand server pagination); file-explorer tree with every folder and your user namespace as lazy-loaded top-level nodes (per-owner "Load more", nested subfolders, bounded "expand all", in-place re-sort without collapse or flicker); the client sorts by the server fetch ordinal to reproduce the endpoint's exact order; empty state distinguishes an empty workspace from too-narrow filters.

Reviewed clean by Claude and Pi (good to merge) and Codex (mergeable).
2026-07-24 23:16:10 +02:00
Ruben Fiszel 1973bc806b migrate to opus 5 2026-07-24 23:05:36 +02:00
Ruben Fiszelandrubenfiszel 113f41bab5 chore(main): release 1.770.0 (#10309)
* chore(main): release 1.770.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.770.0
2026-07-24 19:14:23 +02:00
Ruben Fiszel 03e727777c chore: auto-allow rm in /tmp and git repos, plus read-only gmail (#10307)
* chore: allow /tmp rm and read-only gmail in local permission rules

* fix: gate rm outside /tmp via PreToolUse hook and gate gmail drafts

* fix: reject shell expansion and multi-line commands in rm guard

* fix: make rm guard allow-only with Bash(rm:*) ask as safety net

* fix: reject quotes and backslashes in rm guard to block obscured traversal

* fix: switch rm guard to deny-by-default whitelist of safe /tmp operands

* fix: treat lone dash as rm operand, not an option flag

* fix: defer option tokens containing glob chars in rm guard

* feat: also auto-allow rm strictly inside git working trees under $HOME

* feat: auto-allow deleting linked worktree root folders, still guard primary checkouts

* fix: restrict globs to /tmp and validate post-operand option tokens in rm guard

* docs: correct rm guard rationale to not overclaim git recoverability
2026-07-24 18:55:34 +02:00
Ruben FiszelandClaude Opus 4.8 2143d45815 fix: WAC wait_for_approval reads its own approval result, not the first (#10314)
In prepare_checkpoint_for_resume the resume_job lookup took the oldest row
for the job (ORDER BY created_at ASC LIMIT 1), so a WAC workflow with
multiple sequential wait_for_approval() calls always read the first
approval's result for every step. Consumed rows are never deleted, so the
2nd and 3rd approvals inherited the 1st's result (all showed approved:true
even if the 2nd was cancelled and the 3rd timed out).

Track the resume_job row ids consumed by earlier approval steps in the
checkpoint (consumed_resume_ids) and exclude them, so each step reads its
own row. This is channel-agnostic and needs no clock reasoning:
resume_job.resume_id is only hash(step_key) for the inline resume URL; the
approval page, the in-run approve button, Slack, Teams and resume-as-owner
all store a random resume_id, so filtering by resume_id would drop those
approvals and return approved:false even for a legitimate approval. A
timed-out step matches no row and still falls to the else branch returning
{approved: false}.

Adds a regression test driving three sequential approvals (approved,
cancelled, timed-out) against Postgres.

Fixes WIN-2241

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 18:47:50 +02:00
28a79ced15 feat: add explore button for object storage resources (#10306)
* feat: add explore button for object storage resources in resource list

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA

* fix: make s3 drawer tooltip reflect explored resource

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA

* fix: honor workspace prop in global s3 explorer and add resource connection error state

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA

* fix: use picker's effective workspace in S3FilePreview requests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA

* fix: pass acting workspace to explore button in ResourcePicker

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA

* chore: update ee-repo-ref to f78df23339e3136e8b6e9148a509508633448dd2

This commit updates the EE repository reference after PR #686 was merged in windmill-ee-private.

Previous ee-repo-ref: efb5e014fec34fc580b9dbb1b260494dd76c5462

New ee-repo-ref: f78df23339e3136e8b6e9148a509508633448dd2

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>
2026-07-24 18:41:09 +02:00
Alexander PetricandClaude Fable 5 85008e47b4 fix: pass Windows system env vars to R renv install subprocess (#10313)
Claude-Session: https://claude.ai/code/session_01WTZ5UBBLNh2rkgfNzUmCWs

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 18:33:42 +02:00
48618cff8c feat: Add image when publishing a project (#10310)
* refactor(hub): remove per-item Publish to Hub entry points

Publishing to the Hub now happens exclusively through the folder-level
deploy-to-hub flow (/folders). Remove the standalone entry points:

- script detail page menu item (and the SCRIPT_VIEW_SHOW_PUBLISH_TO_HUB
  const that gated it)
- script list row dropdown item
- raw app editor menu item, its zip-download drawer and publishToHub()
- long-dead commented block in AppEditorHeader

Also drop the now-orphaned URL helpers (scriptToHubUrl, flowToHubUrl,
appToHubUrl, rawAppToHubUrl) from lib/hub.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(hub): upload a custom project logo from the deploy-to-hub drawer

Add a Logo field to the bundle metadata form: a drag-and-drop dropzone
(png/svg, 512KB client-side cap mirrored server-side by the Hub) that
turns into a live replica of the Hub project card once an image is
picked, so the logo can be judged in context before publishing. The
logo is pushed after the draft's items/migrations via the new
POST /projects/{slug}/logo proxy in hub_publish.rs (slug validated by
construction, `logo: null` forwarded to clear). Leaving the field empty
never touches the Hub's existing logo, so re-publishing a bundle keeps it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(hub): logo removal, safer mime inference, explicit clear semantics

Review follow-ups on the project logo upload:

- Removing a published logo is now possible: hubLogo is three-state
  (undefined = leave the Hub's logo alone, null = clear on publish,
  object = upload). Rehydration reads has_logo so the drawer shows a
  "Remove on publish" affordance when the Hub already has one, with an
  undo banner before publishing.
- hub_publish.rs uses a double-Option for the logo field: a missing
  `logo` key is now a 400 instead of being serialized as `logo: null`,
  which the Hub interprets as an explicit clear — POSTing `{}` can no
  longer silently delete a project's logo.
- Client mime inference prefers the browser-reported file.type over the
  filename extension, so a PNG misnamed *.svg no longer produces a
  broken preview and a guaranteed server-side sniff rejection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update frontend/src/lib/components/workspaceSettings/deployToHubSession.svelte.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/workspaceSettings/DeployToHub.svelte

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix(hub): validate logo size/mime/base64 in the proxy, document the endpoint

- Enforce the logo constraints in windmill-api itself instead of relying
  on the browser and remote Hub: a route-level DefaultBodyLimit sized
  for a max logo in base64 (+JSON envelope) overrides the global request
  limit, and the handler validates the mime allowlist, base64 alphabet
  and decoded length (512KB cap) before anything is forwarded.
- Add /w/{workspace}/hub/projects/{slug}/logo to openapi.yaml (with the
  ProjectLogoBody schema) and regenerate the frontend client.
- Drop a narrating comment on the hidden file input.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-07-24 18:19:25 +02:00
Ruben FiszelandClaude Opus 4.8 f00fcb2d1b fix: show scheduled singlestepflow runs in flow history sidebar (#10312)
* fix: show scheduled singlestepflow runs in flow input history

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: only match flow-wrapped singlestepflow rows in flow history

singlestepflow wraps either a script or a flow; a script and flow may share
a runnable_path, so filter flow history to flow-wrapped rows via the wrapped
module type. Extends the regression test to cover the same-path collision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: surface scheduled singlestepflow runs in script history too

Scheduled scripts with a dynamic-skip handler or native retry also run as
singlestepflow. Include that kind for ScriptPath history, filtered to
script-wrapped rows so a same-path flow run does not leak in. ScriptHash is
untouched (these wrappers carry no runnable_id). Test covers both directions.

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-07-24 18:12:09 +02:00
Ruben FiszelandClaude Opus 4.8 992ed01244 fix: do not apply workspace display name on git-sync pull (#10308)
* fix: do not apply workspace display name on git-sync pull

The workspace display name is stored in settings.yaml and was re-applied on
every pull via changeWorkspaceName. Because settings.yaml is shared across the
branches of a repo, a workspace could have its name overwritten by another
workspace that syncs the same repo. Keep name in settings.yaml for reference
(written on push) but stop applying it on pull.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: consolidate workspace-name rationale to one comment (review nit)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: bump git-sync hub scripts to windmill-cli 1.769.1

Repin GIT_SYNC_PULL_SCRIPT_PATH (28795->28808), LATEST_GIT_SYNC_SCRIPT_PATH
(28796->28809) and frontend gitInitRepo to the hub scripts bundling
windmill-cli@1.769.1, so backend automatic git pulls no longer apply the
workspace display name (the CLI fix in this PR only reaches auto-pull via the
pinned hub script bundle).

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-07-24 15:09:57 +00:00
Ruben Fiszelandrubenfiszel a26ea4d43f chore(main): release 1.769.0 (#10302)
* chore(main): release 1.769.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.769.0
2026-07-24 15:46:50 +02:00
3cf7a390a3 fix: pin validated DNS address to close SSRF DNS-rebinding TOCTOU (#10303)
* [ee] fix: pin validated DNS address to close SSRF DNS-rebinding TOCTOU

validate_url_for_ssrf resolved the host, checked every address was
public, then discarded them. Callers re-used the hostname and let stock
reqwest re-resolve at connect time, so a TTL-0 DNS rebinder that answered
a public IP at check-time and an internal one (e.g. 169.254.169.254) at
connect-time slipped straight through the guard.

Return the resolved addresses as a ValidatedTarget and pin them onto the
client that connects, so validate-time and connect-time target the same
address. Covers the AI proxy and worker AI-agent base_url (the primary
readable-SSRF sink), AI OAuth token_url, MCP server + OAuth
registration/discovery/token endpoints, SAML metadata, and the WebSocket
trigger connect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 22abd6d4e229f1206a13ebee8a6a9b808cd82a0d

This commit updates the EE repository reference after PR #684 was merged in windmill-ee-private.

Previous ee-repo-ref: 700feb02ef1b96758ba9425358dbebc83bc02c61

New ee-repo-ref: 22abd6d4e229f1206a13ebee8a6a9b808cd82a0d

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-24 15:04:40 +02:00
Ruben FiszelandClaude Opus 4.8 1478d12eb3 perf: optimize get_datatable_full_schema to avoid timeout on large catalogs (#10304)
pg_get_full_schema built each column row with three per-column correlated
subqueries (default value, primary-key EXISTS on pg_index, pk constraint
name on pg_constraint). On large catalogs those run once per column and the
introspection times out. Replace them with plain joins to pg_attrdef and the
table's single primary-key constraint, so the planner does one hash/merge
join instead of O(columns) index searches. Output is byte-for-byte identical.

Fixes WIN-2239

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 14:37:21 +02:00
Ruben FiszelandClaude Opus 4.8 75acf7207b fix: pin table actions column so it stays visible on narrow screens (#10301)
* fix: pin table actions column so it stays visible on narrow screens

Wide DataTables (folders, variables, resources) scroll horizontally on
small screens, pushing the trailing per-row actions column (the ⋯ menu,
Edit/Delete, and folders' "Publish to Hub") off the right edge where it
was effectively unreachable.

Add an opt-in `stickyEnd` prop to Cell that pins a column to the right of
the scroll container with an opaque background and a left divider, and
apply it to the actions column (header + body) on the folders, variables,
and resources pages.

The background is opaque (bg-surface / bg-surface-secondary) rather than
the row's translucent hover tint, so cells sliding under the pinned column
are occluded instead of bleeding through.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: keep resources actions cell as table-cell so sticky pins correctly

The workspace resources actions cell used class="flex justify-end" on the
Cell, which forces the <td> to display:flex. A flex box inside a table row
is wrapped in an anonymous table-cell, so position:sticky on it is
constrained to that wrapper and no longer pins to the scrollport — the
header stayed pinned while the row actions scrolled away.

Move the flex layout to an inner <div> so the <td> keeps display:table-cell
and the stickyEnd pin works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: address review nits on pinned actions column

- resources Workspace table: add `last` to the body actions cell so its
  right padding (sm:pr-6) matches the header and the other tables.
- variables table: isolate the refresh-error ping indicator's stacking
  context so its z-50 can't paint over a sticky-pinned actions column
  scrolling past it.

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-07-24 13:37:21 +02:00
Ruben FiszelandClaude Opus 4.8 010059a449 feat(hub): surface data pipelines in deploy-to-hub drawer (#10299)
* feat(hub): surface data pipelines in deploy-to-hub drawer

The predeploy step listed a folder's scripts with no indication that some
form a data pipeline. Add a "Data pipeline" summary row (step count +
"View pipeline graph" drawer rendering the asset-graph cascade) and tag
pipeline-member scripts with a Pipeline badge in the item list.

Fixes WIN-2238

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(hub): drop misleading node-inspect hint from pipeline graph drawer

The read-only graph doesn't wire node selection, so the "Click a node to
inspect it" copy promised interaction that doesn't happen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(hub): render pipeline graph inline above the list, collapsed by default

Replace the "View pipeline graph" drawer with an inline collapsible panel
above the deploy item list for pipeline folders. Collapsed by default so
the selection list stays the first thing in view; expanding reveals the
folder's asset-graph cascade in place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(hub): don't let the inline pipeline graph capture the drawer scroll

Add an opt-in scrollZoom prop to AssetGraphCanvas (default true, preserving
the full-height editor/player). The inline deploy-to-hub panel sets it false
so wheel gestures over the 420px graph scroll the surrounding drawer instead
of zooming the canvas and swallowing the scroll.

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-07-24 13:29:36 +02:00
Ruben FiszelandClaude Opus 4.8 1d25d7539e feat(pipeline): collapse secondary top-bar controls into an overflow menu (#10300)
* feat(pipeline): collapse secondary top-bar controls into an overflow menu

The data-pipeline editor top bar crowded primary actions (mode toggle,
Run pipeline, Save) with secondary ones (Record, Download recording,
Macros), which overflowed on small screens. Move the recorder and Macros
into a single overflow (⋮) menu, and surface recording only while armed
as a compact inline "Recording" disarm pill rather than an always-present
Record button.

Fixes WIN-2237

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(pipeline): hoist armed-recorder hint to a shared const

The overflow-menu Record item and the inline armed pill both showed the
same "Recording armed…" tooltip as separate literals, which could drift.
Share one RECORDING_ARMED_HINT const.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(pipeline): keep the overflow-menu rationale at a single site

Address Codex P2: the same crowding/overflow rationale was narrated at
three sites. State it once on the overflowMenuItems derived; the pill and
DropdownV2 mount keep only their local, non-duplicated notes.

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-07-24 13:13:24 +02:00
Ruben Fiszelandrubenfiszel c24d6f9d11 chore(main): release 1.768.0 (#10281)
* chore(main): release 1.768.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.768.0
2026-07-24 11:00:22 +02:00
30d8104edc feat: alert on expired online license key (#10295)
* [ee] feat: alert on expired online license key

Wire alert_on_online_license_expired into the periodic monitor loop
(verify_license_key_f), server-mode gated so only servers report to the
alerts table and critical channels. Add the ee_oss stub so the
enterprise-without-private build still compiles.

Closes the gap where an expired online (renewable) license force-set
externally (env var / CI / k8s) halted all jobs with only a stdout
tracing::error! and no critical alert.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: point ee-repo-ref at license-expired-alert EE branch

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to 9e63619688588fda434dfa06ed585f050e75ee67

This commit updates the EE repository reference after PR #682 was merged in windmill-ee-private.

Previous ee-repo-ref: 7847711567a9c66da6a5c85d176b8cacc5aa7a7f

New ee-repo-ref: 9e63619688588fda434dfa06ed585f050e75ee67

Automated by sync-ee-ref workflow.

* chore: bump ee-repo-ref to license-expiry alert review fixes

Point at the EE follow-up (windmill-ee-private#683): cross-replica dedup via
acquire_lock and no false recovery on malformed key replacement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: update ee-repo-ref to eb8733a36010a7509b438903e95edfa293da079b

This commit updates the EE repository reference after PR #683 was merged in windmill-ee-private.

Previous ee-repo-ref: 562a306d9b66624b28ff90958f8b45d8db5481b9

New ee-repo-ref: eb8733a36010a7509b438903e95edfa293da079b

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-24 10:53:24 +02:00
Ruben FiszelandClaude Opus 4.8 9713e6074d fix: resolve svelte/style export conditions in raw-app CLI bundler (#10294)
The `wmill app dev`/`app bundle` esbuild config never set custom export
conditions, so it only used esbuild's browser-platform defaults
(browser/module/import/default). Packages that gate their entry points
behind other conditions failed to resolve:

- tailwindcss v4 exposes its CSS entry only under `style` (`@import
  "tailwindcss"` -> ./index.css)
- flowbite-svelte exposes its entry only under `svelte` (-> raw .svelte)

Enable the needed conditions, split by scope:

- `style` + `module` are global (DEFAULT_BUILD_OPTIONS): `style` benefits
  any app (Tailwind, CSS libs), and `module` must be re-added because
  esbuild drops its auto-included `module` default once any custom
  condition is set.
- `svelte` is gated per-app via conditionsFor(frameworks.svelte). It
  points at raw .svelte sources that only compile with the Svelte plugin
  (itself loaded only for Svelte apps), so enabling it globally would make
  a Svelte-dual-published import in a plain app hard-fail with no .svelte
  loader.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 10:50:46 +02:00
Ruben FiszelandClaude Opus 4.8 53ad86cd1e docs: fix stale detach_dev_workspace comment on parent_workspace_id (#10296)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 10:43:44 +02:00
Ruben FiszelandClaude Opus 4.8 161c7f4655 test(cli): drain async dependency jobs after sync push to fix flake (#10293)
* test(cli): drain async dependency jobs after sync push to fix flake

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(cli): condense waitForDeploymentJobs comment

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-07-24 10:23:18 +02:00