* refactor(ai): render thinking blocks with the shared tool-call card
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(ai): collapse thinking to a status row with a thought-for duration
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(ai): separate reasoning-timing reset from duration read
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(ai): render expanded thinking in the body font, not mono
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(ai): mark in-progress chat rows with a shimmer sweep
Thinking and tool calls both announced themselves with a spinner, which
carried no more information than the row already did and read as visual
noise once several tools ran in sequence.
A white copy of the label now sits over the coloured one and is revealed
through a travelling band, so a running row is marked by motion across
its own text rather than by a separate glyph. Both spinners and the brain
icon are gone, leaving the card with no icon slot at all, and every header
label settles on text-secondary.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(ai): keep a running row marked under reduced motion
The shimmer is the only thing distinguishing a running tool row from a
settled one, and the reduced-motion rule removed it outright, so the two
became identical for those users. The band now degrades to a flat wash
instead of disappearing.
Also covers the reasoning-duration state machine: that thinking stops at
the first answer token rather than at the end of the turn, and that each
reasoning pass of a tool-using turn is timed from scratch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(ai): restore the clock spy after the reasoning-duration tests
The file-level hook only clears call records, so the Date.now spy stayed
installed and would freeze time for anything appended after this block.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(debugger): return PrepareResult when the service prepared the venv
`prepare_dependencies()` returns `PrepareResult` on every path except the
service-prepared short-circuit, which returned the venv path as a bare `str`.
`handle_launch` reads `prepared.error` on it, so every Python session whose
script has a third-party import raised `AttributeError`, hung, and failed at
180s with `Debugpy command timeout: launch`.
The two consumers of a prepare-deps response also read a `stderr` key the CLI
does not emit; the field is `install_stderr`, and it carries the same text
`error` already wraps in a sentence, so take one rather than joining both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(debugger): keep the failing step in the launch message, drop the dead branch
Preferring the raw `install_stderr` made `_first_line` pick uv's opening
progress line, so a refused launch reported "Using Python 3.12.13 environment
at: venv" — which reads like success. `error` is the same text prefixed with the
step that failed, so it is the better of the two to condense.
The installer-diagnostics pass over a `success: true` response is unreachable:
every `success: true` site in prepare_deps.rs sets `install_stderr: None`, and
its comment claimed the opposite of what that file documents. It existed to work
around a producer that warned and returned success on a failed `uv pip install`;
that producer now returns `success: false`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: stop the homepage edit-in-fork button from wrapping
* fix: show the full edit-in-fork label anywhere on the button
* fix: thread showEditButton through the homepage tree view
* fix: match the edit-in-fork button styling to the normal edit button
* fix: edit in dev workspace dead-ends on items the dev workspace lacks
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: pull the item's folder before copying it into the dev workspace
* fix: speak the compare page's update vocabulary in the dev-workspace prompt
* fix: raw app with no stylesheet was undeployable across workspaces
* fix: drop the raw-app stylesheet workaround now that the backend serves one
The frontend wrapped `getRawAppData` to report a missing `.css` as empty,
because a raw app with no stylesheet stores no css blob and the shared deploy
treats the resulting 404 as fatal. #10364 fixed that at the source: the backend
now serves an empty body for a missing stylesheet, so the wrapper guards a 404
that no longer happens.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop the fork icon from the edit-in-dev-workspace affordances
The row button carried both a pen and a fork, and the menu entries and detail
page buttons carried a fork alone — where the menus already used that same icon
for Duplicate/Fork, so the two entries were indistinguishable. The action is an
edit, so it takes the pen everywhere, matching the ordinary Edit button.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: send edit in dev workspace to the item's editor
The affordance landed on the item's page in the dev workspace and left the user
to open the editor from there. It says "Edit", so it goes to the editor:
`/scripts/edit/...?workspace=<dev>` and the equivalent for flows and both app
kinds. `?workspace=` still does the workspace switch, which the logged layout
applies on any route.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: choose the on-behalf-of user when updating the dev workspace
The prompt deployed the item with no say over the identity it would run under,
so an item that ran on behalf of someone in prod silently became the deploying
user's in the dev workspace. It now offers the same choice the compare page
does, under the same rules: shown only when the source item carries an
on_behalf_of, picking anyone but yourself gated on admin/wm_deployers in the
target, and confirming blocked until a choice is made — including while the
lookup that decides whether one is needed is still in flight.
The prompt also stops offering the compare page inline; the confirm button
still leads there when the user can't deploy into the dev workspace.
Two fixes the reused selector needed to work inside a dialog:
- ConfirmationModal takes `confirmDisabled`, which also blocks the Enter binding.
- The popover's z-index is now overridable, and the user picker is portalled.
A ConfirmationModal renders above the popover layer, and its card is
transformed for the open transition, which makes it the containing block for
the picker's `fixed` positioning — so both opened behind, and the picker was
laid out inside the card instead of the viewport.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: check deploy rights per item before prompting to update the dev workspace
* fix: read the compare page link before closing the dev-workspace prompt
The link is derived from the request the prompt is answering, so closing first
left an empty string to navigate to: refusing users saw the dialog dismiss and
stay put, with no way through to the compare page.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the new-tab promise and speak up when a popup is blocked
Three defects found by successive cold reviews of the click-time resolution
added earlier in this branch, each one only reachable once the previous fix
existed:
- Safari refuses `window.open` from any promise continuation however fast it
resolves, so the tab the editor dropdown opens after its existence probe
never appeared there. `claimTab` takes the tab inside the click's own
transient activation and points it at the answer once it lands, releasing it
when there is nothing to show.
- That left the two halves of the same action disagreeing: the entry promises
never to navigate the editor away, but when the item turned out to be missing
the prompt took over and navigated in place. The request now carries
`openInNewTab`, and every destination the prompt can reach honours it.
- With popups blocked the fallback called `window.open` without checking, so a
successful deploy closed the prompt and did nothing, silently. It now names
what it could not open.
`openEditInFork` also takes the workspace explicitly. The four editor dropdowns
computed their label from `opWorkspace` but resolved the action from the
navigation store, and `prodWorkspaceId` feeds `deployItem({ workspaceFrom })` —
so a session pane would have deployed from the wrong workspace.
`checkPathWritePermission` is exported with an injectable folder probe and
covered by table-driven cases, chiefly to pin its two fail-open branches, which
otherwise read as dead code inviting deletion.
The two unrelated whitespace hunks in ScriptBuilder.svelte are the repo's
format-on-save hook fixing pre-existing violations in a file this touched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: create the dev workspace's missing folder without overwriting it
`ensureFolder` delegated to the shared `deployItem`, which re-probes and
switches to `updateFolder` when the folder turns out to exist. Nobody asked for
that folder to be deployed — it is created only so the item has somewhere to
land — so a folder created between the two probes had its owners, ACL, summary
and labels silently replaced with the source workspace's. Creating is now
create-only, and losing that race counts as success: the folder exists, which is
all the caller needed.
The same delegation dropped `default_permissioned_as` and `labels`, which the
shared folder deploy does not send. A folder copied without its create-time
identity rules applies none, so an item landing inside it with no on_behalf_of
of its own resolves to whoever deployed it rather than to the principal the
source folder would have chosen — the exact substitution the rest of this branch
exists to prevent. Both are now carried across.
Also check `window.open` in the no-dev-workspace branch of `openEditInFork`. The
branch beneath it already reported a blocked popup; this one returned as if it
had opened something.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: translate copied folder identity rules into the target workspace
A `u/<username>` names a workspace-local account, so copying a folder's
`default_permissioned_as` verbatim was wrong in two directions: the same
username in the dev workspace can be a different person, who would then be
granted the item; and a username with no account there at all passes the
folder-create check, which is structural, only to fail every subsequent item
deploy on the existence check, including the retry — the folder now exists, so
`ensureFolder` short-circuits and the deploy fails identically, with no way out
of the prompt.
Rules are now resolved source username -> email -> target username, since email
is the only identifier stable across workspaces, and a rule whose principal has
no account in the target is dropped rather than carried. Dropping one makes the
copied folder less restrictive than its source, which is not something to
discover later from an item running as the wrong user, so it is reported.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: refuse to overwrite a concurrent item, and translate every folder principal
Four findings from CI review, all on the implicit half of this flow — the writes
the user did not explicitly ask for.
The item write is now create-only. The shared `deployItem` re-probes and silently
switches to an update, so the caller that acts on an item being *absent* could
still overwrite whoever landed it between the two probes. Rather than
reimplementing the per-kind deploys, the frontend's own provider refuses exactly
the three writes that branch reaches for — `updateFlow`, `updateApp`/
`updateAppRaw`, and a `createScript` carrying a `parent_hash`, which is what
makes an otherwise identical create an update. A refusal reports `conflict`, and
the prompt opens their version instead of replacing it.
Folder principals are translated rather than copied. `u/<username>` is
workspace-local, so a verbatim copy either names nobody or names a different
account that happens to share the username. Users now resolve source username ->
email -> target username, and the two kinds of unresolvable principal are
separated because they fail differently: an owner or ACL entry is dropped, which
can only narrow the folder and leaves the creator owning it; an identity rule
refuses the copy outright, because dropping it runs the item as the deployer and
keeping it creates a folder the server then rejects every deploy into.
Groups resolve against `listGroups` rather than `listGroupNames`, which unions in
instance groups that folder rules do not resolve against — a same-named instance
group would otherwise let an unusable rule through.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: read every page of workspace groups before judging a folder principal
`listGroups` paginates, and the `perPage: 100` it was called with is narrower
than the server's own default of 1000 — so a group past the first page read as
having no account in the target. Since an unresolvable identity rule now refuses
the whole folder copy, that turned into a refusal naming a group that does
exist, and an owner or ACL entry on a later page was dropped silently. Read
until a page comes back short, with a size check as the backstop for a server
that ignores `page`.
`list_users` is unpaginated, so the user half of the same lookup was never
affected.
Also move `makeProvider`'s doc block back onto `makeProvider`; adding
`DeployConflict` had left it documenting the type instead.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: reattach principalTranslator's doc block to principalTranslator
Adding `workspaceGroupNames` above it left the block documenting the helper,
the same way adding `DeployConflict` had displaced `makeProvider`'s.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(mcp): serve the 2026-07-28 spec alongside the legacy protocol
* fix(mcp): keep oauth discovery strict and preserve request limits
* fix(mcp): allow the protocol's own headers through CORS
* fix(mcp): expose the auth challenge to browser clients
* chore: update ee-repo-ref to c1665a881b61616f96ffe7702b44840905304660
This commit updates the EE repository reference after PR #711 was merged in windmill-ee-private.
Previous ee-repo-ref: bc1c001e3e386342415dfb8ac31c6b97f6629320
New ee-repo-ref: c1665a881b61616f96ffe7702b44840905304660
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(frontend): stop swallowing Ctrl/Cmd+Shift+S in the editors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(frontend): make Ctrl/Cmd+S from a focused Monaco flush the draft
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(frontend): broadcast the Monaco save shortcut after the effect flush
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: report python debugger dependency install failures instead of timing out
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface swallowed installer errors and stream debugger prepare progress
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: reap the python debugger on a failed launch and bound prepare-deps
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: match uv failure output by stripping progress instead of matching errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: treat uv build, download and warning lines as install progress
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: honor python index settings in prepare-deps and report install failures
* fix: forward python registry env to the debugger's prepare-deps
* fix: scope registry credentials to the prepare-deps subprocess
* fix: install python debug dependencies from the service, not the session
* fix: bound the debugger dependency install and keep the proxy bypass default
* docs: name the nsjail config that isolates debug sessions
* feat: responsive modal step panel for the flow editor in sessions
On narrow layouts the flow editor's step-details pane opens as a modal
(double-click a graph node) instead of a split pane, with a dock/float
toggle. Scoped to sessions via allowModalPanel; the full-page editor is
unchanged.
- FlowEditor: modal/docked modes gated by mount width + allowModalPanel,
small header (step-id Badge + subtle dock/close), standing
double-click hint, and a per-step hint in the name tooltip
- selectionManager: onSelectIntent hook so flow-level panels (settings,
input, triggers…) open the modal on single click
- PropPickerWrapper: collapse the prop picker until connect and animate
it in via AnimatedPane (runs-page pattern), no blue connect ring in
modal mode
- StepInputGen: drop the TAB/Wand autocompletion button + spinner
(feature still works via focus + Tab)
- InputTransformForm: decouple the Help dropdown from the AI suggestion
- FlowModuleHeader: move 'Save to workspace' into an ellipsis dropdown
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: loop editor rendering and nested splitpanes splitters in the sessions modal
- Loop iterator/parallelism: keep the picker split pane (forceExpanded) so
the editor fills its box and the picker shows; the collapse-until-connect
mode stays for the step inputs
- Remove the intrusive AI TAB/Wand autocompletion button from IteratorGen
(generation still runs headless via focus + Tab)
- Size the iterator connect plug and restyle the loop header/labels/toggles
- Scope the global `.splitter-hidden` splitter-hiding rule to direct children
so it no longer leaks into nested Splitpanes under the sessions preview
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: redesign flow step advanced settings as a single toggle-first column
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: taller step test pane by default and restyle advanced section titles
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: show flow run-settings params disabled when a setting is toggled off
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: single-column for-loop panel reusing the run-settings accordion
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: single-column while-loop panel reusing the run-settings accordion
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: single-column branch panels reusing the run-settings accordion
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: auto-open modal panel when creating an AI agent tool
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: redesign branch panels with card layout and shared predicate editor
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor: remove per-setting status badges from flow map nodes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: sync package-lock after windmill-utils-internal bump
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* style: polish prop-picker plug button and branch panel layouts
* fix: persist skip-if-stopped toggles in early stop settings
* fix: open the step panel modal on demand and cap its width
* fix: restore graph step setting badges, strip panel header chips instead
* feat: docked panel header with detach action and open-details step menu
* feat: width-based panel mode on every surface with inline detach action
* refactor: single source for flow step settings and their defaults
* docs: pin flow editor vocabulary in CONTEXT.md
* fix: open the trigger panel on double click or a specific trigger
* fix: keep module pickers inside their pane and dismissable
* fix: drop the misleading chevron on the MCP tool entry
* fix: resolve flow approvals against the job's workspace, not the nav one
* refactor: derive the approval workspace from the job, not from callers
* fix: restore S3 snippets and gate params while their setting is off
* fix: restore branch mock controls and address review findings
* chore: drop stray debug log from the flow map item
* feat: pinned output section for loop and branch panels
* fix: open the panel for deliberate navigation from the flow header
* perf: mount branch predicate editors on demand
* fix: skip predicate picker previews the previous step's result
* fix: flow-level graph nodes open their panel on a single click
* fix: open the step panel for AI chat selections, not for undo
* chore: drop dead console.log and duplicated modalPanel doc
* fix: re-sync expression editors and scope error-handler settings
* fix: match the failure module exactly and ignore unselectable nodes
* fix: keep concurrency editable, honour module cache_ttl, tighten panel ids
* fix: open panel from indirect selections, use presence for value-driven toggles
* fix: don't open settings on error-handler delete, flush editors on unmount
* fix: guard editor destroy flush, keep retry kind reachable
* refactor: name the run settings panel after the domain vocabulary
* fix: only write editor flushes to the step they belong to
* fix: bind step panels by id so a delete can't retarget editor writes
* fix: don't let the trigger picker's escape close the drawer beneath it
* docs: condense two comments to the constraint they record
* fix: arbitrate escape through the overlay stack instead of deferring to it
* fix: key nested step blocks by identity so anchored bindings can't go stale
* fix: untrack the overlay-stack push and drop the frozen branch binding
* chore: state the escape rationale once, key branch lists, format
* fix: let the topmost overlay own escape instead of the graph
* fix: keep the dynamic-input help box out of static template fields
* fix: restore the graph connect on the for-loop iterator
* fix: end connect mode with the modal and keep it to docked panels
* fix: never enter graph connect mode from the modal panel
* fix: reveal inserted steps, restore editor pane size, unleak the drawer stack
* fix: keep the enable-AI popover reachable in session panes
* feat: add the connect policy and its single armed slot
* refactor: one picker for every expression input
* refactor: route every connect through one armed slot
* fix: give every connect button the same footprint
* fix: keep the connect ring from showing through the button
* fix: keep flow card actions right-aligned beside the detach button
* fix: give the connect ring an opaque ground to mask against
* feat: dock the panel back without reopening it
* feat: dock the panel from the graph control bar
* style: round the graph control bar and size its glyphs
* style: customize the graph controls through their supported api
* style: build the graph control bar from lucide icons
* fix: use the graph's tooltip component in the zoom controls
* style: pad the graph controls and enlarge their glyphs
* style: pad the graph controls and put dock at the bar's end
* refactor: give settings rows the same popover picker as other expressions
* fix: pass the wrapper's pickable properties to nested inputs
* refactor: stack step settings and render every expression through the step input form
* feat: split loop panels into tabs and rework the approval form
* feat: anchor drawers to their host pane and give them a size floor
* fix: mark the loop iterator expression as required
* refactor: badge ee-only toggles instead of a warning line
* fix: flag an empty loop iterator expression as an error
* refactor: pick the early-stop flow status from one toggle group
* fix: keep parallel loops uncapped unless a limit is opted into
* fix: scope the overlay stack to its host and disarm connect on dismissal
* fix: anchor the trigger picker to its host pane
* feat: move diff into the menu when the top bar is narrow
* fix: gate the result logs toggle to the graph popover
* feat: raise the modal-panel breakpoint to 1280
* fix: anchor flow editor popovers and fullscreen to their host pane
* fix: anchor overlays to their host pane and mute them when hidden
* fix: portal hosted modals and menus into the pane they anchor to
* fix: keep non-listening dialogs off the overlay stack
* fix: drop the topmost gate from confirmation dialogs
* fix: silence overlays in a collapsed preview panel
* feat: rework the branch panels with tabs, reordering and add/delete
* refactor: fold the detached-panel chrome into the card header
* fix: give every flow panel a titled card header
* fix: stop the step panel oscillating on an auto-height editor
* feat: consolidate script panel actions and restore branch predicate AI
* fix: restore the logs toggle on the flow result popover
* fix: collapse the idle property picker in modal step panels
* fix: stop the docked pane scrolling alongside its panel
* fix: space the last settings row off the panel bottom
* revert: always show the property picker pane in step panels
* chore: keep the inline script AI button identical to main
* fix: ask for AI input suggestions on click, not on hover
* fix: keep graph connects armed and remount the parallelism input
* style: reveal the predicate AI button on row hover
* style: give branch cards a handle and delete column
* refactor: arbitrate flow overlay escape through Disposable
* fix: give the popover picker its results and re-narrow the EE badge
* docs: correct loopSubset and guard the modal width measurement
* fix: insert picked properties at the cursor in expression inputs
* fix: give the expanded-subflow panel the shared header chrome
* style: rename the suspend setting to Suspend until approval/resume
* feat: open a step's modal when clicking the step already selected
* feat: add an auto/attached/detached toggle for the step panel
* refactor: pick the step panel's placement from one named menu
* refactor: keep the panel-mode module's exports to what is consumed
* feat: show each configured setting's value on its badge
* fix: carry the suspend rename into the step settings registry
* docs: name both gestures in the step explore hint
* test: pin where the step panel goes for a given width and preference
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: keep flow step picker rows on one line and highlight only one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: restore hover on standalone picker rows and drop phantom ai slots
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop inert picker resize and align hub rows with workspace rows
The step picker popover carried `!resize` but computes `overflow: visible`, so CSS
`resize` never applied and the handle did nothing. Dropping it also pins the inner
height at 464px, keeping `displayPath` off everywhere except the content-sized
trigger picker.
Hub rows there rendered summary and path inside a fixed 28px button; give them the
same `h-auto min-h-7 py-1` the workspace rows got. Guard `hover:bg-transparent` on
`onHover` in both pickers so all three agree, and drop the unconditional `title` on
TopLevelNode, which put a native tooltip on every kind button.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep GenAiQuick's CSS hover when it is not wired into the shared index
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(dbt): reach any dbt adapter through a dbt_profile resource, and constrain the warehouse picker
The workspace dbt warehouse picker listed every resource in the workspace, so a
slack or github resource was an offerable answer to a field that can only be a
warehouse. Constraining it exposed that the set of resource types that actually
work is both smaller than the docs claim and too small to be useful:
- `render_profile` translates only six adapters from a Windmill resource; the
rest (clickhouse, duckdb, salesforce, mssql, oracle) refused one outright.
- `redshift` and `duckdb` name no resource type anywhere, so two of the
adapters the quickstart advertises were unreachable.
- the `databricks` resource carries `workspace_url`, while the renderer demanded
`host`, so that warehouse could never render at all.
So the picker gets a constraint and dbt gets an escape hatch wide enough to make
it honest. `dbt_profile` is a resource whose value IS a `profiles.yml` target —
`{ type, target }` — passed to dbt unchanged, so any adapter and any key it
documents works.
`DbtAdapter` is now open: it carries dbt's own `type:` spelling plus an optional
`KnownAdapter` (the eleven Windmill has facts about — a field mapping, a pip
package, the license gate). Anything else is carried by name and installed as
`dbt-<name>`, the convention every adapter on PyPI follows, so "whatever dbt
supports" no longer means "whatever this enum lists". The license gate is
unaffected: `sqlserver`/`oracle` still resolve to their `KnownAdapter` and are
still gated. The name is confined to `[a-z0-9_-]` starting alphanumeric because
it reaches a pip requirement and a venv path on the host.
Two adjacent fixes fall out: the project's own `profiles.yml` and the
descriptor's `profile.type` now accept any adapter instead of the closed list,
and a databricks resource renders its `host` from `workspace_url`.
The picker is constrained to `dbt_profile` plus the translated types, so nothing
it offers can fail for want of a mapping.
Fixes WIN-2320
* fix: drop the unused DbtAdapter::from_resource_type wrapper
Nothing calls it: a Windmill resource type maps through
KnownAdapter::from_resource_type, and the executor resolves an adapter from
the resource's own dbt spelling or by inference. CI builds with -D warnings,
so the dead wrapper failed every backend check.
* fix(dbt): make dbt_profile the block itself, and address the review findings
**A `dbt_profile`'s value IS a `profiles.yml` output block**, `type` included.
It was `{ type, output }`, which asked the user to restructure their block
before pasting it — a translation step, in the one type that exists to avoid
translation. The schema now declares no properties, so the resource form renders
a single JSON editor over the value.
That means the value's shape can no longer say what it is: a `dbt_profile` and
Windmill's bigquery resource are both objects with a `type` (the latter says
`type: service_account`). So the warehouse carries its resource's type
(`DbtWarehouseConnection.resource_type`), and detection is exact. It also makes
decision 9's "the resource type name is the authority" true at runtime for the
translated path, which until now resolved its adapter by sniffing fields.
Review findings, all three reviewers:
- **[P0] an author-chosen adapter became an unsandboxed PyPI install.** `dbt-` is
not a reserved prefix, and `provision_core_1x` installs through `run_tool`,
outside the nsjail ordinary dependency installation uses — so `dbt-<name>` from
a script author's `type` could run a PEP 517 build backend as the worker. Now
gated on a list of published adapters plus `DBT_EXTRA_ADAPTERS`, so trust stays
the admin's call. The open set survives: the engines that ship their adapters
install nothing and take any type.
- **[P1] `type: fabric` rendered as `sqlserver`.** dbt's `type:` was resolved
through the resource-type table, where `fabric` is a Windmill alias for SQL
Server — so a Fabric profile installed dbt-sqlserver, was enterprise-gated, and
failed on an ODBC driver without ever naming Fabric. dbt types now have their
own table.
- **[P1] two spellings of one adapter compared unequal.** `PartialEq` covers the
carried name, so `postgres` != `postgresql` even resolving to one adapter, and
the descriptor/resource check rejected valid configs with a message naming the
same adapter twice. The name is normalised to the adapter's dbt spelling.
- **[P2] identity keys.** `database_key` is what a Windmill resource spells it,
and only translated adapters have one; the rest read dbt's `database`.
- **[P2] duplicate `sslrootcert`** when a block carried both a PEM and a path.
Verified with three real dbt builds: a flat `dbt_profile` postgres block, the
same with `type: postgresql` under a `profile.type: postgres` descriptor (the
alias case, which failed before), and trino for the unknown-adapter path.
* docs(dbt): say that installing an adapter is gated, not just using one
The open-adapter text promised every future adapter is installed as dbt-<name>,
which ensure_adapter_installable refuses outside PUBLISHED_ADAPTERS and
DBT_EXTRA_ADAPTERS. Separates the two: rendering, licensing and identity are open
to any adapter, and only the dbt-core 1.x PyPI install is gated, because that is
the step that runs outside the sandbox.
* fix(dbt): keep a dbt_profile's own sslrootcert when Windmill writes none
The previous round skipped the block's sslrootcert unconditionally to avoid
emitting the key twice, which drops a path-only CA reference — a certificate
baked into the image or mounted on the worker, which is the block's own trust
source. Skipped now only when a root_certificate_pem is present, which is when
Windmill writes a replacement.
* fix(frontend): let a resource type declare no properties
A schema without `properties` is a JSON-edited resource type, not a broken one -
`dbt_profile` is a profiles.yml block whose keys belong to its adapter, so there
is nothing for Windmill to declare. Both editors assumed properties exist:
- ResourceEditor threw on Object.keys(undefined) while deriving the field order,
which left the drawer on its loading skeleton forever, so the resource could
not be viewed or edited at all.
- ApiConnectForm caught the same throw and reported the type as missing from the
workspace, offering to sync a type it already had.
Both now fall back to the raw JSON editor, which is what usesRawEditor already
intended for a schema with no properties.
* chore: cut the new comments to AGENTS.md's four-line cap
Each still states its constraint once; the long-form rationale belongs in
docs/dbt-runtime.md and the PR, not beside the code.
* fix(dbt): keep a dbt_profile's empty and nested collections intact
A block with no children reads back as null, so `extensions: []` reached the
adapter as a missing value rather than the empty list dbt was handed, and a
nested array went through the scalar path and arrived as a quoted JSON string.
Both are keys dbt passes to the adapter as it finds them, so the type has to
survive: empty collections are emitted inline, and the value half of an entry
recurses instead of bottoming out at a scalar.
The test parses the rendered YAML back rather than string-matching it, since
what matters is what a YAML reader sees.
Also cuts DbtWarehouseConnection.resource_type's comment to the four-line cap.
* fix: reflect custom tag add/remove in the manage-tags drawer immediately
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: do not fail the custom_tags write when the cache refresh errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: show far more in the home tree view and say what is not loaded
* feat: let every folder in the home tree page within its own prefix
* fix: count leaves in nested badges and stop transient subtree mounts
* fix: merge nested pages instead of replacing rows an ancestor loaded
* docs: tighten the tree prefix-loading invariants
* feat: preview and edit expanded subflow steps in the flow editor
* fix: hide subflow edit button when no flow editor drawer is available
* fix: address review findings on expanded subflow step panel
* fix: base-prefix subflow links and bound the expanded subflow module cache
* fix: do not let a pre-deploy response repopulate the invalidated subflow cache
* fix: guard expanded subflow reloads against collapse and encode workspace in link
* fix: commit an expanded subflow reload only onto the expansion it fetched for
* fix: bundle a vector emoji font so emoji scale with flow graph zoom
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: include the upstream copyright notice in the bundled OFL license
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: match the bundled license notice to the shipped font binaries
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: correct the unicode-range gating comment
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: cap ScopeSelector badge container heights
The "Selected Scopes" summary and each domain header rendered their badges
in unconstrained flex-wrap containers. With path-restricted scopes the badge
strings run long, so a handful of them wrapped over many rows and pushed the
scope domain list and the token form's action buttons below the fold.
Cap the summary at 8rem and the per-domain header at 4rem, both scrolling
vertically past that.
Fixes WIN-2318
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: correct scope chip disabled state, summary readability and domain widening
Follow-ups to #10517, all in ScopeSelector:
- The shared scopeChip snippet bound the component-level `disabled` for its remove
button, but a scope card computes `isDisabled = disabled || isScopeDisabled(...)`.
A scope superseded by its `:write` sibling greyed out its checkbox and its path
button while the `x` on its path chips stayed live, so those paths could still be
destroyed. The effective state is now passed in.
- Truncating a chip hides the paths being granted, which is the point of the
Selected Scopes summary. Chips there now wrap instead; the tight per-domain header
and the per-scope path lists keep truncating.
- Ticking a domain checkbox re-added its write and run scopes bare, dropping any
resource paths configured on them: a token restricted to one path silently became
a token for the whole domain, and unticking did not bring the paths back. The
checkbox already reads as checked when those scopes are path-restricted, so it now
carries the paths over. Both branches of the requires_resource_path conditional it
replaces pushed the same bare value, so nothing was reading that flag.
- The path popover tooltip explained that no paths means full access but never that
each path added widens the scope's reach, which is what reads backwards next to
the "Add path" button.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: correct the path tooltip and drop the domain-header height cap
Review nits from #10523.
The tooltip claimed every path added widens the scope's reach, which is only true
from the second path on: the first replaces a bare, full-access scope with a
path-restricted one, narrowing it. Stating what each state means avoids the
direction question entirely.
The domain header no longer caps its height. Truncation holds every chip to one row
and a domain has a handful of scopes, so the row cannot run away, while the cap put
a 64px scroller inside the scrollable domain list that swallowed wheel events
crossing it — and clipped mid-row, since 64px is not a multiple of the row height.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: name the pg login in the job log for token auth modes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor: route remaining pg login defaults through login_name
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: require an explicit user for azure workload identity on postgres
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: let the database manager run its jobs on a custom worker tag
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: ignore a superseded database load, share the tag button between drawers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: share the database worker tag override across mounted drawers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the token scope builder inside its panel when scopes get long
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: label the scope path popover 'Add path' once paths exist
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: show which MCP endpoint tools a token scope will actually expose
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep a wildcard endpoint scope when pruning the MCP endpoint selection
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: drop orphaned matcher comment and name the wildcard remedy in the MCP scope warning
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let admins edit the dev workspace lock ruleset
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: route the empty protections panel through the owning workspace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make protection rule rename actually apply
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: cache the renamed protection rule query for sqlx offline
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep verbatim rule names and scope parent-admin lookup to its workspace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: store renamed protection rule names verbatim
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: point the MCP app tools at full-code apps
* feat: name the full-code app tools createApp and updateApp
* fix: check the path and writer before compiling, let listApps paginate
* fix: ask the app table who may create, not a restated rule
* fix: guard duplicate mcp tool names and document the create body
* fix: allowlist resource_type and escape search highlights
* fix: bound path length and keep marked-label offsets entity-aware
* fix: match postgres word-char semantics and drop double-escaping
* fix: sanitize db constraint and rls errors instead of relying on the regex
* fix: serve getJob in the ai evals benchmark api catalog
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: scope the frontend format hook to the frontend dir
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: answer the run-by-path endpoints and mirror the real getJob entry
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: gate the format hook on a repo-root frontend, not the project dir
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: deploy a raw app from its sources, bundling them on a worker
* refactor: bundle raw app sources with the wmill CLI instead of a second bundler
* fix: address review findings on the raw app source deploy
* fix: bound bundle decompression, drop the npm dependency on slim workers
* fix: stop minting jobs:run for the source deploy, share the decode budget
* feat: let an MCP token grant the scopes its selected tools require
* fix: carry a caller-held extra scope through the MCP proxy
* fix: confine the run scope to the proxied request instead of the token
* fix: mint the run scope only for a token that names the tool
* fix: require write access before compiling, and state the grant where it is granted
* fix: let the database decide write access instead of restating its policies
* fix: answer a write denial with 403, not 401
* fix: surface which auth mode a sql connection used and hint at ms_entraid
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the ms_entraid hint to azure hosts and pin the sentinel trim
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: send prompt_cache_key on the openai responses api
* fix: bound prompt_cache_key to the provider limit and scope it to retryable paths
* fix: keep a digest suffix when bounding long frontend cache keys
* docs: attach the cache-key doc block to the function it describes
* feat: signpost the dbt migration path on the pipelines page
* fix: frame the dbt signpost as a separate runtime, not a pipeline
* fix: claim only graph visibility for dbt models and gate the signpost on operators
* fix: reword the dbt signpost title
* fix: open an AI session from the editor bar's AI button, on the step
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: withhold the session hand-off under disableAi, forward button styling
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: flush the code editor's pending keystrokes before opening the session
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
check-write-access is additive by design: every caller ORs its `authorized`
output with `github.event.comment.author_association`, so a failure should
degrade to the author_association path, not block anything.
It does not. `claude`, `codex` and `pi` all `needs: [parse, check-access, plan]`,
so a failed check-access skips `plan` and with it all three reviewers. Any
disruption to the app credentials — an unset `INTERNAL_APP_ID`, a rotated
`INTERNAL_APP_KEY`, the app uninstalled from the org — turns a redundant
authorization probe into a total /review outage.
Guard the token minting and fall back to the default token, which still resolves
public members and repo collaborators; private members fall through to
author_association exactly as they did before this workflow existed.
Found while porting these workflows to windmill-helm-charts
(windmill-labs/windmill-helm-charts#656), where the app credentials are not
guaranteed to be present.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: locate coursier artifacts by coordinate so private maven registries work
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: match maven coordinates by path component, longest first
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: skip the empty directory a 404 leaves at a maven coordinate
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: ignore coursier's dot-prefixed bookkeeping when claiming a coordinate
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep AI settings editor in sync with the config it just saved
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: skip the post-save reload and record why the saved config is cloned
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: add multi-select and bulk actions to the Home page
* fix: address review findings on home bulk actions
* style: make the home select-items toolbar entry an icon on the left
* fix: address CI review findings on home bulk actions
* fix: address second review round on home bulk actions
* fix: stop app updates from silently converting an app between raw and low-code
* fix: lock the app row for the kind guard and route MCP away from raw apps
* style: condense the restore kind-change comment
* fix: match openrouter model ids by parsed vendor, not raw prefix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: anchor context-window matches so a version entry cannot swallow a longer version
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the context-window digit guard to version-suffixed entries
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: state the thinking-suffix invariant without drafting history
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: load the workspace AI config even when the docked chat is disabled
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: hide the inline-script AI button when no docked chat pane exists
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: wire paged object storage listing module
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: document list_stored_files_paged endpoint in openapi
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: lazily expand s3 explorer folders one level at a time
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: pin ee-repo-ref to the paged listing branch
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: share object_store credential resolution and surface listing errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sqq2LhmWaGwP11Cf3UqWxe
* Chevron is cool
* page size 5000
* feat: make the load more row full-width, secondary and chevron-led
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sqq2LhmWaGwP11Cf3UqWxe
* fix: render newly loaded flat pages inside already-expanded folders
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: address review findings in the lazy s3 explorer
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: address review nits in the lazy s3 explorer
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref after merging main
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: document ambient credential contract and constrain max_keys schema
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: treat an exhausted page token as exhausted, not as a continuation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for canonical prefix validation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for prefix scoping and opaque cursors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: invalidate a folder's in-flight load when deleting from it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: discard a stale folder page after its level is invalidated
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for bounded local listing
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: label folders whose final path segment is empty
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: search files by any part of their path, not just folder prefix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* feat: search files by path prefix instead of a full-bucket scan
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* fix: guard stale search responses and describe prefix search accurately
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the search prefix fallback fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: regenerate the served openapi specs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the search cursor fallback fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqAc8mz6Gu698kBbJJVwcT
* chore: bump ee-repo-ref for the bounded search scan
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface a failed flat listing instead of spinning forever
The flat branch of loadFiles was awaited without a catch, and loadFlatFiles
clears its loading flags only on the success tail. Every caller reaches it
un-awaited, so a rejected listing left the drawer on "Loading content" with
nothing reported. Routing the filter box through this arm made it reachable
per keystroke rather than once per open.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: give back the flat cursor when a page fails to load
"Load more" advanced `page` before requesting it, so a failed page left the
cursor pointing at a `listMarkers` slot that was never filled. The retry sent
no marker at all and silently replayed the first page, and the
`listMarkers.length == page` guard kept it there until the listing was reset.
Only reachable now that a failed page is retryable rather than a permanent
spinner.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the flat cursor rollback to its own listing
The rollback matched on the page number alone, so a page that failed after a
filter or storage change could roll back the *replacement* listing once it had
reached the same number, stranding its cursor. Tie it to the generation the
request was issued under.
The delete replay loop had the mirrored problem: it re-drove `page` by hand and
carried on past a failed page, leaving `page` ahead of `listMarkers` for good.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: skip the delete replay when the fresh listing itself failed
clearAndLoadFiles dropped the result it already computes, so a failed
post-delete listing still ran the replay loop: each page advanced `page` with
an empty `listMarkers`, which never recovers because the marker-length guard
only pushes when the two agree. Every later "Load more" then replayed page one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: stop a superseded lazy load from writing into the search that replaced it
loadFolderPage resolves rather than throwing once its generation is stale, so a
filter change that switches the picker to the flat listing mid-flight left the
lazy branch free to expand a preselected file into the search's results and to
clear the search's loading flags. Guard both on the generation it started under,
as the flat branch already does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: check the listing generation throughout the reveal walk
Revealing a preselected key is a chain of round trips, so checking once at entry
left the rest of the walk free to keep loading after a filter change had already
switched the picker to the search — under the replacement generation, so the
per-level guards inside loadFolderPage saw nothing wrong.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let a late metadata failure clear only its own preview
The handler blanked fileMetadata and filePreview without checking that its
request still owned the pane, so selecting a second file while the first was
still loading meant the first's rejection wiped the second's preview.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: key preview ownership on the request, not the selected key
Comparing the selected key let an older request speak for a newer one when both
targeted the same key, which a storage switch does, and made a request whose
selection had moved to something with no metadata return early with the spinner
still up — the case the handler exists to prevent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: clear the preview when the previewed file is deleted
The lazy branch refetches only the affected level and returns, so it never
reached the reset that the flat refresh gets from clearAndLoadFiles. The pane
renders from fileMetadata rather than from the selection, leaving the deleted
file previewed with working download, move and delete actions.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: retire the in-flight preview load when its file is deleted
Clearing the pane was not enough: a metadata response computed before the DELETE
landed still repopulated it, restoring the deleted file's preview and its
download, move and delete actions. Deleting now retires the owning request, and
the success and preview writes honour that the same way the failure path does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: clear the preview loading flag when the delete retires its request
Retiring the in-flight metadata load left nobody to report its outcome, so in
lazy mode the pane sat on "Loading..." instead of falling back to the empty
state. The delete owns the flag once it has retired the request.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: drop the regenerated openapi deref artifacts
They are generated files that CI only syntax-validates, never checks against
openapi.yaml, and the committed copies already differ from the spec they derive
from by ~9.7k lines. Regenerating here imported that pre-existing drift into a
feature diff, burying ~800 lines of actual change under ~17k lines of other
changes' staleness. Regenerating them is its own chore.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: state the flat cursor invariant once, where the cursor lives
It was spelled out at four sites, which is what AGENTS.md asks not to do. The
rule now sits on the declaration it constrains and the guards reference it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* nit ui
* fix: add the paged listing to the served openapi json
openapi_json() embeds openapi-deref.json via include_str!, and the Docker build
regenerates only the yaml artifact, so the json is served exactly as committed —
leaving the new operation out of the Scalar API reference.
Spliced in the operation and the two schemas it references rather than
regenerating, which would have re-imported ~7k lines of pre-existing drift
between the committed artifact and the spec it derives from.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref for the filesystem symlink boundary
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 0373b4bfdaf8dd51533552e2e4de63ceb3c18b4d
This commit updates the EE repository reference after PR #697 was merged in windmill-ee-private.
Previous ee-repo-ref: eb1a765bb9b29e0c94a6e4942c304934fa15406e
New ee-repo-ref: 0373b4bfdaf8dd51533552e2e4de63ceb3c18b4d
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* fix: handle a non-member superadmin on the dev workspace settings tab
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: only seed the protections panel from a load this call produced
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: refetch rather than seed while a protection-rules fetch is in flight
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: always supersede the in-flight rules fetch instead of seeding by hand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>