mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-17 16:03:06 +00:00
0caf054295fccaf3d8993e562f7bca3049d9e4d9
92
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0caf054295 |
fix: check pinned versions and app kind before keeping an item page on switch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f00b2fcb1e |
feat: drafts follow their item through a move; behind means base ≠ head (#10577)
* refactor: give home multi-select a reserved gutter and a menu entry Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep checkbox theming and reserve the gutter on non-selectable rows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: carry every draft with an item when it moves Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: move draft-only items and warn editors when an item moves Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: put the home selection checkbox back in the kind icon slot Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FaEacdxR6M6VDej6C9r39 * feat: animate the home bulk bar and exit selection at zero Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FaEacdxR6M6VDej6C9r39 * fix: keep dialog icon badges round and the panel inside narrow viewports Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FaEacdxR6M6VDej6C9r39 * fix: address review findings on the draft-carry path Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FaEacdxR6M6VDej6C9r39 * fix: keep a staged rename when a move carries the draft Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: restamp only the deployer's own carried draft Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: scope the moved-save restamp to the mover as well Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: read the app move's author from the head version, not the draft's base Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: carry a flow draft's baseline path so deploying it cannot un-move the flow Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: reject unsupported kinds in move_draft, survive NUL-poisoned draft rows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: skip NUL-poisoned rows in every draft-value rewrite, not just the first Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: report a NUL-poisoned draft on move instead of 500ing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name the attempted operation in the NUL rejection message Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: drop dead selection code and comments that outlived their state Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: describe script staleness as head-pinned, which is what the loader does Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: correct the third staleness comment left claiming a stable fork base Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address CI review — auth order, save race, carry failure, path validation Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: gate operators earlier, skip the write tx without lineage, unblock a chained move Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: run the post-write moved re-assert under RLS, not the raw pool Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin the moved answer to what the saver can see The post-write re-assert names a path and a username, and nothing at any layer stopped it reading them off a raw pool connection. Swapping the transaction back to `db.begin()` compiles and passes everything else, so the guard has to be a test: a non-admin saving at a path whose item moved into a folder they cannot see gets `saved`, while the admin gets `moved`. Also drops two doc comments still arguing that clearing the write gate at the old path removes the need for an RLS envelope. It does not — the gate resolves the old path and the re-assert asks about the new one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: name the real deploy path and stop restating the RLS constraint `update_path` is not a symbol in this repo; a script move goes through `create_script`. The re-assert's comment re-derived the disclosure argument that already sits on `resolve_moved_to_in`, where a caller would break it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: state the RLS and restamp constraints once each The RLS envelope was argued at three sites in drafts.rs; it now sits only on `resolve_moved_to_in`, whose signature is what a caller would break. The restamp scoping was copy-pasted at all three deploy call sites while already documented in full on `move_drafts_for_path`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: carry both path keys on a move, and grant the draft sequence The upsert now runs as `windmill_user`, so it calls nextval on `draft_id_seq` as that role. The only thing granting that is the ALTER DEFAULT PRIVILEGES in 20250205131523, whose DO block swallows failures — so an instance where it errored would fail every autosave with `permission denied for sequence`. A draft value carries two path keys: the typed one and a mirror the editors keep in step with it while it differs from the row's path. Rewriting only the typed one left the mirror naming the old location, and the loaders prefer the mirror — reopening a moved session script restored the old path and the next save un-did the move. Both keys now follow, in the move endpoint and in the passive carry, under the same tri-state rule. `typed_path_field` answered `draft_path` for every non-script kind, including resources, variables and triggers, which have no such key. It returns `None` for them now, and `move_draft` reads its guard off that mapping so the movable set and the field mapping cannot drift apart. Also documents that `move_drafts_for_path` mutates every owner's row and enforces nothing itself, and parses the draft payload once per save instead of three times. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin the two-key move, and stop the down migration breaking instances Revoking the sequence grant would strip a privilege a healthy instance had before this migration ran — the grant it adds is indistinguishable in the catalog from the one ALTER DEFAULT PRIVILEGES gives at creation time — so the down is a comment, matching the other grant-only migrations. The mirror rewrite is spread over three sites that have to agree and fails silently when they don't, so it gets a test: a draft carrying both path keys has both moved, and one carrying neither mirror does not gain one. It reads the value back over HTTP rather than with `sqlx::query!`, which would need an offline cache entry of its own. Also drops twelve `.sqlx` entries this branch added and then superseded, and corrects the doc and openapi text that still described only the typed path being rewritten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: point the empty down at the grant it is declining to revoke Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: drop the restamp and tri-state; a move relocates the draft row only A deploy that renames an item is a deploy like any other: every draft on the item goes stale, and the stale prompt with its diff is the single mechanism to catch up. move_drafts_for_path now touches only the row's path column, so the value keeps the base version the draft actually forked from, and the "moved" patch carries no version restamp. DraftBaseVersion shrinks to the three per-kind lineage fields. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: stale prompt links to a diff that names and lets you pick the deployed version The stale-draft prompt gains "See what changed", which opens the diff drawer. The drawer resolves the deployed side by the draft row's own path (not the typed path, which after a rename still names the archived row), labels which version the left pane is, and offers a picker over the item's deployed history for scripts, flows and raw apps. The history endpoints return created_by (and created_at for apps) so each entry can name its deployer. "Restore to deployed" moves to the header actions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: move_to asserts the response status Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: keep a script draft's base at the version it forked from The script editor seeded the draft's parent_hash from the deployed head on every load, and the next autosave persisted it, so a draft behind the deploy read as up to date after being opened once. The base now comes from the draft when one exists; the head is only used for a fresh checkout or an explicit topHash. Deploy already fetches the live head and confirms on mismatch, so the base is what makes that check meaningful. The webhook "run this version" URL uses the deployed hash rather than the draft's base. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: store the version a draft forked from in one draft.base column Every kind kept its fork base under a different name and type inside the value: parent_hash (hex) for scripts, version_id for flows, parent_version for apps. draft.base holds it as one text id, derived on save from the value so every writer fills it the same way, backfilled by the migration (rows holding a NUL are skipped, since ->> raises on them). The get-by-path overlay exposes it as draft_base and the drafts list as base; the editors and the compare page read that one field and compare it to the head as text. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: raw-app drafts carry a fork base, so behind means base != head for them too The raw-app bundle never carried the version it forked from, which left raw apps on the timestamp check that self-heals as you type, and the header's deploy guard read a version prop nothing set, so deploying over a newer version never asked. The route now stamps parent_version into the bundle (the draft's own base when it has one, else the head), the server derives draft.base from it, the stale prompt compares it to the head and links to the diff, and the editor threads it to the header so the deploy guard confirms. A deploy re-pins the base to the version it wrote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: refuse a rename onto a path that already holds a draft A draft occupies its path the way a deployed item does: a never-deployed item, or a draft left on an archived script. Renaming onto it would either merge two items or leave the losing row stranded at a path its item has left. The move now refuses with a BadRequest inside the deploy's transaction, so the rename itself fails and the source stays deployed. Every draft on the item then moves; there is no longer a left-behind count to report. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: save drafts by row id, so an open editor follows its draft through a move A rename carries every draft on the item to the new path. An editor left open across it was still saving by the path it opened on, which the server had to refuse and answer with where the item went (the "moved" handshake and its modal). The draft row has an id: the get-by-path overlay now returns it as draft_id, every later save sends it, and the server writes the row wherever it is and answers with that path. The editor then follows: it flushes what it holds, tells the user, and navigates to the item's new path, where the stale prompt says what changed. The lineage-based move resolvers, the moved status and the moved modal are gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: the out-of-date prompt names both versions and can take the latest as the new base The prompt now says which version the draft forked from and which is deployed (and by whom), instead of two timestamps, and gains "Take latest, keep my edits": the draft's base moves to the head and its content stays, so the user can acknowledge a newer version without discarding their work. Each route sets its kind's base field on the draft value and persists it; the raw-app bundle carries it already, so setting the state is enough there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: two-action out-of-date prompt; taking the latest moves into the diff drawer Four buttons made the prompt hard to read. It keeps "See what changed" and a red "Use latest" (it replaces the draft); closing it is keeping the draft. "Take latest, keep my edits" moves to the diff drawer's header, offered only while the draft is behind, so the user takes the latest with the diff in front of them. Scripts, flows and raw apps pass the action through their diff drawer; the classic app editor has no drawer wired to the prompt and loses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore: drop the draft_id_seq grant; the draft upsert runs on the raw pool Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a moved draft's path keys follow it, and a refused rename names the draft's owner Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: follow a moved draft on tab close, and deploy a followed flow at its new path Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: write a followed draft by id against the row's own path keys; keep base on assign and clone Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: look up a script's head at its row path, and show flow and app version ids bare Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: session editors save by draft id; raw apps keep a legacy draft's base unknown Also advance the raw-app base on deploy, relocate once per move, drop the hoisted operator check and the unread base on drafts/list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: guard a base-unknown raw-app deploy against the head at load; keep the base in session hydration Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: the server follows a moved draft through a move record, not client-sent row ids A move writes old path -> new path (per workspace and kind, per owner for a draft-only move) in its transaction; a draft save or discard addressed to a path the caller has no draft at resolves through it and keeps the moved draft's path keys. Creating an item at a path drops the records leaving it. Every writer (edit routes, sessions, chat, CLI, the tab-close flush) follows without passing an id, so the id plumbing is gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: session loaders keep a draft's base, and a failed relocation flush stays put Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a draft-only app move refuses the other app kind; a session keeps an unknown base unknown Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin a teammate's carried draft; name the kind that refuses a draft move Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an unknown base stays unknown in every loader, and an owner move extends an item move Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a clone keeps only a base it can resolve; a base-unknown script deploys without a false guard Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a workspace clone sanitizes a NUL-bearing draft instead of copying it unstripped Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: move records follow an account rename and deletion; a legacy draft says why it cannot move Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an owner move extends only the item's own route, not another user's Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a redeploy ends a route off its path, take-latest persists on raw apps, stale picker loads are dropped Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a poisoned draft's path keys follow a move, legacy only bypasses routing on a delete, picker loads are generation-guarded Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count picker load generations, and report a skipped legacy upsert as a conflict Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a legacy discard follows the item's move record too Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a failed version load keeps the picker on what the diff shows; one spelling for a legacy delete Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the picker marks the version on display as head, restore compares the head, relocation follows the last move Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: say so when a version fails to load in the diff picker Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: take latest re-reads the head at click time; type the kept head as prepared diff data Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: taking the latest moves the head each editor knows, not just the base Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: take latest adopts the head the diff shows, and is offered while the drawer sees the draft behind Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a head nobody could name is not behind, so take latest is not offered without one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the flow drawer's head is the version its payload came from, and its callback type says so Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a NUL in a move's summary is dropped, and take latest simply adopts the head it was handed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a loaded raw-app draft keeps its own fork base, and an unknown head is refused Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a routed discard names where it landed, a superseded drawer opening is dropped, and a loaded draft keeps its base in every editor Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a legacy draft occupies its destination, a superseded opening writes nothing, and a loaded flow draft keeps no base it lacks Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the drawer owns its opening, a loaded script draft keeps no base it lacks, and a legacy occupant says who can clear it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: taking the diff drawer without a token claims it, and the classic app editor takes one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a retried routed discard still names the destination, and filling the drawer takes the opening too Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a no-op routed discard names the destination only to someone who could write there Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the no-op routed discard gates its answer on reading the destination, and a session draft keeps its unknown base Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: abandoning an opening clears the drawer it still owns Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an app deploy pins only a version it wrote as the next draft's base Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the deploy-override diff takes an opening its editor can hand back Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: pin the version this deploy wrote even when one landed on top, and tighten three comment blocks Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a deploy claims only the version it appended to the head it read, and names the head separately Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a deploy always names the head it left behind, and pins a base only when it can claim one Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the derived base is read after the sanitizer, and a deploy that claims nothing leaves no base to compare Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the route's lineage follows an in-place deploy, and the raw-app editor's event type carries the head Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: the raw-app deploy comment says what that editor actually does with version Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a group member can be told where their item went, and a deploy names the head's author Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an emptied selection is no shift anchor, and a deploy leaves no draft for the prompt to compare Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: session tabs compare the same base pair, and a consumed draft is not out of date Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a failed anchor read is not a raced deploy, and take latest closes only its own drawer Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an unclaimed deploy always confirms, and the prompt keeps warning a loaded teammate draft Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: the base-unknown confirmation says what it knows, and two comments match the guard Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the other app kind collides whoever owns it, and session tabs get a head to compare Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the cross-kind refusal reads properly, and a session flow keeps its own response's head Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a fresh session checkout takes the head its payload came from, and a deploy keeps the base it pinned Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the move endpoint validates its source path, and two comments say what their branch does Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an unanswered head read confirms rather than assuming the app editor is current Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a deploy is not blocked by the draft a move carried to its destination Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an unread head confirms with the copy for caution, not for an observed deploy Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the move record alone excuses a carried draft at the destination, whoever owns it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: an app deploy answers with the version it wrote, so the editor stops inferring it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: the rename assertion reads the deploy's json answer Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the unread-head warning reads as caution in the deploy drawer too, and the cross-kind refusal names a remedy Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a reused destination retires the routes pointing at it, and draft_base stays out of diffs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the app head is the tail of app.versions, not the newest timestamp Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: app history lists in deployed order, so the picker numbers it right Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: the ordering test's setup sql compiles offline, and the head join names its app Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: kinds that cannot move skip the move lookup, and the move wording needs read Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: a deploy history comes a page at a time, so the diff drawer opens at once Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a history stays whole unless asked to page, and pages inside the version array Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an asked-for history page is bounded, and a failed one is not the end of the list Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: an unasked history is whole again, and an absurd page is empty not an error Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: naming only a page still asks for one, and a stray version stays reachable Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a fork's nul-poisoned draft arrives clean, so its dangling identity repoints too Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: a raw app names its deployed version even when the history will not load Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
864e5f02ec |
fix: bring back Publish to Hub for scripts (#11097)
* fix: bring back Publish to Hub for scripts Publishing to the Hub moved to the folder-level flow, which publishes a whole project and needs a workspace admin. That left no way to share a single script, which is what private hubs mostly use the Hub for. Restore the "Publish to Hub" item on the script detail page and in the script list row menu. Both open the Hub's script submission form prefilled with the script, on whichever Hub the instance is configured to use, and are hidden when the instance disables the Hub. Flows and apps still reach the Hub only inside a project. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: open the Hub tab before fetching, and hide Publish to Hub from operators The script list row has to fetch the script before it can build the Hub URL, and Safari refuses window.open after an await, so the tab never opened there. Claim it inside the click with claimTab(), point it at the Hub once the script loads, and close it with a toast if the fetch fails. A blocked popup falls back to a late window.open, and says so if that is blocked too. Operators can't write scripts, so the row menu now hides the item from them, as the script page's menu already does. The script page opens the Hub with noopener, and scriptToHubUrl takes the script instead of eight positional arguments. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
716ce2ece0 |
feat: free AI tokens + home search/filter revamp (#10020)
* feat: add free Claude Opus tier with per-user token limit Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * nit move alert * Home AI Chat * wire home ai chat * auto send prompt * refactor: remove keyboard arrow-navigation from home list Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: replace home search bar with unified FilterSearchbar Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: replace home quick tags with FilterSearchbar presets Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: add content filter to home FilterSearchbar with EE-gated content view - Clear the kind filter by deleting the key (was showing a 'kind: null' tag on All) - Remove the standalone Content button - Add a 'content' filter; when set, render the Ctrl-K content-search view (ContentSearchInner) which shows text-match snippets and its own EE warning Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: disable home AI chat and prompt to configure AI when no model Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * track cost instead of tokens * nit * fix: load copilot config on home so AI chat isn't wrongly gated Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Home page update * nits * example prompts * nit * feat: switch free AI tier to DeepSeek with daily cost budgets Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * nit * Move bottom buttons to HomeAIChat * [ee] feat: surface free AI tier state and make its metering abort-proof Makes the free Windmill AI tier legible to the user and closes an abuse hole. Backend: - AIConfig gains a response-only free_tier marker (skip_deserializing so a client can't store a forged one via edit_copilot_config). get_copilot_info keeps returning it once the grant is spent, so the client knows AI is off because the grant ran out, not because nothing was configured. - Per-user grant becomes one-time (migration drops the day key from ai_free_token_usage); the daily table stays as the instance kill-switch. - Reserve-then-reconcile metering (see EE commit) so a mid-stream disconnect can no longer dodge the usage report and get metered zero. Frontend: - copilotInfo carries freeTier; model settings show a "Free" pill and a usage meter that warns past 80%. - The home chat and the session chat show a dedicated "you've used your free Windmill AI, add your own API key" state instead of the generic "no provider configured" one. - A failed send re-fetches copilot_info so the exhausted state (and its banner) appears live, without a page reload. Bumps ee-repo-ref.txt to the matching EE commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: free AI usage meter reusing the context-usage gauge Show free-tier spend with the same gauge as context usage instead of a bespoke block: - Extract the meter+tooltip into a shared UsageMeter; ContextUsageIndicator uses it, and a new FreeTierUsageIndicator renders it from copilotInfo.freeTier. Placed in the session-chat toolbar and next to the home-chat model settings; the old meter block in the model-settings dropdown is removed (the "Free" pill stays). - Hide the context-usage bar while on the free tier so the free meter takes that slot. - Refresh copilotInfo after every free-tier turn (AIChatManager finally) so the meter advances live and the turn that exhausts the grant flips to the exhausted state, instead of both only updating on reload. Gated to active free-tier users, so it costs nothing for configured-key users. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: fix stale free-tier comments after DeepSeek/cost rework Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: always show context bar, replace free-tier meter with usage banner Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * nit * fix: atomic free-tier budget reservation (ee ref + sqlx) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: keep CLI/MCP and Hub buttons unblurred on AI chat hover Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add back arrow nav * nit * nit * fix: three review P1s in the home AI chat & search - AIChatManager: refreshFreeTierUsage now bails unless the global copilot state still belongs to the completing manager's workspace, so a warm session finishing after a workspace switch can't reload its (background) workspace over the active one's models/client/copilotWorkspace. - HomeAIChat: block submission until the copilot config is loaded AND enabled (new `canSend`), so a prompt submitted during the unknown-config window isn't handed to a session that never sends it and silently lost. The disabled overlay still gates on config-loaded to avoid a flash. - ItemsList: the content-search reload effect now depends on $workspaceStore so content results follow the active workspace instead of showing the previous one's. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [ee] fix: harden the three home-AI-chat/search P1s after deeper review Follow-up to the previous P1 commit; sharper review found the earlier guards insufficient: - refreshFreeTierUsage now compares against the most-recently-*requested* workspace (new copilotWorkspaceRequested in aiStore, set synchronously in loadCopilot), not the last-*resolved* one — otherwise a warm session finishing while a newer workspace's load is still in flight could win the monotonic token and restore its stale workspace over the one being loaded. - The content-search view is keyed by workspace ({#key $workspaceStore}) so a switch remounts ContentSearchInner; late in-flight responses from the previous workspace can no longer land in the new one's component. Backend (EE, via ee-repo-ref bump to 03ef0eb): the free-tier reservation now also prices the worst-case input cap (at the cache-miss rate), and enforce_free_tier_body rejects oversized prompts and pins n=1 — so an aborted large-prompt request can no longer dodge the input bill that reconciliation would otherwise charge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: exclude service accounts from the free AI tier Free-tier eligibility was keyed solely on authed.email. Workspace admins can create and impersonate arbitrary service accounts (synthetic *.sa.wm.dev identities), each of which would receive its own one-time grant — letting one tenant mint many grants and drain the instance-wide daily allowance. Skip the free-tier fallback for *.sa.wm.dev identities. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: activate free AI tier when clearing a workspace provider edit_copilot_config returned AIConfig::default() when the saved workspace config had no providers and no instance config existed; the frontend applies that response immediately, disabling AI even though the free-tier key is available. A later get_copilot_info (on reload) returns the synthetic free-tier config, so clearing a provider behaved inconsistently until reload. Give this response path the same free-tier fallback as get_copilot_info. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: gate the home AI composer behind the global-AI dev flag The "Build with AI" composer starts a session and navigates to /sessions, which lives behind the same wm_dev_global_ai dev gate as the global AI chat. With the gate off (the default), /sessions renders only its gate message, SessionWrapper never mounts, and the queued prompt is silently dropped. Hide the home entry point behind isGlobalAiEnabled() so it isn't exposed before the sessions gate opens. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [ee] chore: bump ee-repo-ref for deepseek-v4-flash price/model fix Points at the EE commit that pins deepseek-v4-flash and its real prices (pico-precision accounting). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [ee] fix: provable byte bound for the free-tier input cap (ee-repo-ref) Bumps ee-repo-ref to the EE commit that caps the raw request body byte length directly (token_count <= byte_count is provable), replacing the unsafe body.len()/2 token estimate that high-entropy prompts could beat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * nit isGlobalAiEnabled * empty commit * fix(frontend): address Codex review on free-tier / home filters - P1: home filters now sync from the URL reactively, so browser Back/Forward updates the chips, kind toggle and results (and clears keys dropped from the URL) instead of leaving them stale until the next filter edit. - Free-tier banner buttons drop deprecated Button props (size/color/border variant) for unifiedSize + a supported variant. - Condense refreshFreeTierUsage comments to a single race-condition constraint beside the guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): hide empty kind badge on draft-only scripts A draft-only script can carry an empty `kind`, which still isn't 'script' so the row rendered a blue badge whose only content was capitalize('') — an empty pill left of the "Draft only" badge. Guard the badge on a non-empty kind. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(frontend): animate home tree-view group expand/collapse Wrap each owner group's children in ResizeTransitionWrapper so height changes animate. A slide transition only animates the initial mount, but a freshly-opened owner fetches its rows and passes through a transient empty state before they land — the ResizeObserver animates that second growth too. Nested TreeViews inherit the wrapper's context and skip their own, so one observer per top-level owner animates the whole subtree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(frontend): FilterSearchbar boolean auto-set and string-filter presets - A default-false boolean filter has only one useful value, so selecting it sets true immediately instead of opening a true/false picker. A default-true boolean (e.g. "Include library scripts") still shows the picker, where false is the meaningful choice — expressed via a new optional `default` on the schema. - A plain string filter now surfaces any presets targeting it (`<tag>:<value>`) as suggestions once selected, integrated into menuItems so keyboard nav works — previously selecting e.g. "Owner" showed nothing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(frontend): home page toolbar and content-filter revamp - "New" create-menu button (scripts/flows/apps/…) replaces the old Content button; the search bar moves to the right of the toggle group. - Restore the content filter dropped in a merge: a `content` searchbar filter swaps the list for the full-text ContentSearchInner view (EE), aligned flush with -mx-2. - Move the owner/group and label chips off the page into FilterSearchbar presets; ownerFilter/labelFilter now derive from the searchbar keys (data layer unchanged). - Move the list controls (select / tree view / expand-all / sort) inline into the top row between the toggle group and search bar; add margin above the list. - Beta tag on the home AI chat; a bit more bottom margin under it; tighten the gap between the admin/tutorial banners and the list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ai): pass the request body to the free-tier reservation Thread the prompt body into resolve_free_tier_credentials so the free tier can size its upfront reservation from the actual request length instead of a fixed worst case (EE c2e248b), fixing normal chats being rejected as "too large". Updates the OSS stub signature and bumps ee-repo-ref. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): gate home Create/Import menu on edit permissions The relocated CreateActionsMenu rendered unconditionally, so operators and users in workspaces protected from direct deployment saw create/import actions they can't use. Restore the original gate (!operator && showEditButtons, the latter from NoDirectDeployAlert). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): address Codex review on filter searchbar - P1: the boolean shortcut now goes through the same tag-insertion path as the normal branch, so it removes the typed search segment instead of leaving it as a stray free-text (_default_) term. - Mark the Runs `show_future_jobs` filter default: true so selecting it opens the picker (false is the meaningful choice) rather than being a no-op. - Home owner/label presets now emit the canonical `key:\ value` form so the applied-preset check matches after a reparse and can't re-offer a duplicate; update the suggestion extraction to strip the leading separator. - Replace deprecated Button props (size/spacingSize/color) on the relocated list controls with unifiedSize. - Fix stale comments: UsageMeter no longer claims a free-tier consumer; the home filter schema comment describes presets, not the removed ListFilters/label badges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): boolean filter shortcut sets value canonically The round-1 shortcut baked `true` into the tag text, which merged into a following tag (e.g. `archived:\ truekind:\ flow`). Instead remove the typed segment, set the value, and reparse so the text is rebuilt canonically — no lingering free-text and no merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(ai): restate free-tier caller identity contract in the OSS stub; bump ee-repo-ref Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): keep flanking tags separate when boolean shortcut drops a segment Joining `before`/`after` directly fused the tags a removed mid-segment sat between (e.g. `kind:\ flowsummary:\ bar`). Join with a space; reparse then canonicalizes. Also trims the comment to the essential constraint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(ai): update sqlx cache for free-tier daily-day queries; bump ee-repo-ref The reserve/reconcile daily-usage queries now bind the reservation day (EE change); refresh their offline query cache and point ee-repo-ref at the EE commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ai): activate free tier when instance ai_config has no provider An instance ai_config row won precedence just by existing, so an empty {} (valid via global settings / declarative config) suppressed the free-tier fallback and left AI disabled — even though build_copilot_settings_state already treats it as unconfigured. Apply the same has_providers() check to the instance config in the proxy and edit_copilot_config paths. Also refresh the sqlx cache for the reservation ceiling change and bump ee-repo-ref. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(frontend): migrate legacy Home filter URLs to the searchbar keys The old Home UI stored free-text in `search`, owner scope in `filter`, and could write `kind=all`; the generic searchbar sync uses `_default_`, `owner`, and a kind enum without `all`. Rewrite those params once before the sync reads the URL so shared/bookmarked links restore, and drop `kind=all` which would otherwise wedge later filter edits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ai): empty instance config in get_copilot_info; label user-disabled Home AI - get_copilot_info returned any existing instance ai_config row before the free-tier fallback, so an empty {} disabled AI in the copilot-info UI even though the proxy now serves the free tier. Apply the same has_providers() gate here. - The Home chat overlay said "No AI provider is configured" when the user had disabled AI in account settings (providers still present). Distinguish that state ("Windmill AI is disabled in your account settings") as the docked chat does, and drop the misleading workspace-config button in that case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(ai): drop redundant proxy service-account check; trim TreeView comment The service-account exclusion now lives in the free-tier helper, so the proxy calls it directly. Also condense the tree-view resize-transition comment to the essential reason. Bumps ee-repo-ref. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(frontend): the Home content filter is not EE-gated ContentSearchInner loads the workspace's scripts/flows/apps/resources and matches their contents client-side, so it works on any instance. Drop the misleading "(EE)" from the filter label and the "EE indexer / off-EE fallback" comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(ee): bump ee-repo-ref for free-tier pricing + exhaustion fixes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): show disabled Home AI overlay statically, not on hover The disabled-state overlay (reason + configure/add-key action) was opacity-0 and pointer-events-none until group-hover, so keyboard and touch users saw an inert composer with no visible remedy. Render it and the composer blur statically when disabled instead. Also bumps ee-repo-ref for the trimmed free-tier comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): give account-disabled Home AI overlay a recovery action The account-disabled branch showed a reason but hid every action, on the mistaken premise that account settings has no linkable route. It opens from the #user-settings hash (the same one the sidebar Account menu uses), so link there. Bumps ee-repo-ref for the free-tier fixes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): gate Home AI composer for operators; a11y and filter-sync fixes - Home composer now uses prefersSessionHandoff($userStore?.operator) instead of isGlobalAiEnabled(): operators reached this route and could submit a prompt into a /sessions page that refuses them, silently dropping it. Also drops the leftover empty header spacer div above the chat. - HomeAIChat: mark the blurred/disabled subtrees inert so keyboard users can't tab into the unreadable textarea (pointer-events-none didn't stop Tab). - ItemsList: keep the role-dependent searchbar keys (include_library, only_user_folders) in the schema unconditionally and toggle `hidden` instead, so useUrlSyncedFilterInstance (which snapshots the key set once) still URL-syncs a key that first appears after a workspace switch. - Bumps ee-repo-ref for the indexer non-parquet build fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): keep CLI/MCP connect row for operators; trim filter comment The previous commit gated all of HomeAIChat behind the operator/session check, which also removed the AI-independent CLI/MCP "Connect workspace" drawer that operators (and the sessions-beta opt-out) had on main. Render HomeAIChat for the same audience as before (isGlobalAiEnabled) and gate only the composer (title, input, examples, overlay) on operator status inside the component; the connect row always shows. Also trims the role-dependent filter-schema comment to the <=4 line rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): reconnect Home keyboard navigation to the unified searchbar The searchbar migration replaced the <input id="home-search-input"> the ItemsList keyboard handler keys off, so Arrow/Enter no longer drove the results list. Thread an `id` down to the searchbar's contenteditable (via TaggedTextInput/FilterSearchbar `inputId`) so the handler and the workspace-switch focus restoration find it again; read the caret through the Selection API instead of an <input>'s selectionStart/End; and stand the list's arrows down while the searchbar's suggestion dropdown is open (tracked via onDropdownVisibleChange). In free-text mode the searchbar no longer opens its dropdown on a bare arrow key, so an empty box passes Arrow/Enter to the list as before. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * fix(frontend): stop searchbar Enter inserting a newline; idle typewriter for operators - TaggedTextInput is a single-line filter input, so Enter now preventDefaults the contenteditable's newline insertion (surrounding suggestion-select / list-open handlers still run on bubble). Previously Enter with no row highlighted dropped a literal \n into the query. - HomeAIChat's placeholder typewriter effect now runs only while the composer is shown, so it no longer loops forever driving an unrendered input for operators. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSqa1iRxn9GUE9fegT7bDS * chore: update ee-repo-ref to f2a31156ac08ecb02d89dbc66d72be58e9c877ff This commit updates the EE repository reference after PR #652 was merged in windmill-ee-private. Previous ee-repo-ref: e59b96a2eea5d1110b40c842f17b337ab051bdd3 New ee-repo-ref: f2a31156ac08ecb02d89dbc66d72be58e9c877ff 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> |
||
|
|
616d4fe167 |
fix: edit-in-dev-workspace dead-ends, wraps, and misses the tree view (#10354)
* 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> |
||
|
|
c57045dbb3 |
feat: add multi-select and bulk actions to the Home page (#10499)
* 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 |
||
|
|
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> |
||
|
|
b4b0c6a93e |
feat: add dev workspaces paired with a lockable prod workspace (#9793)
* feat: add dev workspaces paired with a lockable prod workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: gate dev-workspace prod-lock on admin and prevent attach cycles Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: redirect locked-prod edits into the dev workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: make dev-workspace settings tab available on CE (was EE-gated) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: lock prod against forking too and funnel edits to the dev workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: open dev item page on edit and tailor dev-workspace lock messages Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: prevent nested dev workspaces and hide dev option when one exists Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: drop the redundant already-has-dev hint on the fork form Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: badge dev workspaces and sort them ahead of forks in the tree/switcher Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: label dev workspaces as 'Dev workspace of X' instead of 'Fork of X' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: label edit as 'Edit in <dev>', cover editor headers, auto-expand dev in tree Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: split prod lock into separate block-deploy and prevent-forking toggles Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: make resources/variables workspace-specific from compare page Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: steer AI-chat sessions to the dev workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: refine session fork options and lock guidance for dev/prod Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: session picker reads prod's real rules, default to current ws Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: copy members into forks and clarify dev-workspace root labeling Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: place the workspace id field under the fork name Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: address dev-workspace review findings and harden fork detection Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: regenerate sqlx offline cache Restores entries dropped during the origin/main merge and adds the dev-workspace queries (is_dev_workspace, ws_specific, has_parent). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: address second-round dev-workspace review findings Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: address Pi and Codex review findings on dev-workspace endpoints Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: gate locked-dev git-branch fork on admin and validate ws_specific path Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: clear prod dev-lock when deleting an attached dev workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor: consolidate dev-workspace migration and scope all-group join to attach Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: restore dev-workspace CHECK into consolidated migration and scope all-group join Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor: drop copy_members from the dev-workspace attach path Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: dev-workspace lifecycle/auth fixes from Codex review round Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: explicit create-in-other for workspace-specific items Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: make create-in-other strictly create-only (never overwrite target) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: return 403 (not 401) for dev-workspace permission denials Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat: allow attaching a same-family fork as a dev workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: emphasize the go-to-dev action in the no-direct-deploy alert Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: seed a resource's linked variables when creating it in the other workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: judge workspace deploy/fork locks against the user's identity in that workspace Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: clarify create-in help text in workspace-specific panel Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: admin-gate dev-workspace creation and harden lock/seed edges Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: preserve a staged fork's source on picker create-mode re-entry Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: clear dev flag on archive and check dev existence server-side Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: make create-in-other atomically create-only via direct create Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: create-only resource insert, ws-specific list scopes, archive lock guard Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: reserve the dev_workspace_lock protection-rule name from the public API Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: reattach create_protection_rule doc comment to its function Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor: make dev-archive pairing teardown atomic with the archive Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: follow deploy_to on root rename; show dev pairing to non-member prod admins Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: copy creator metadata on fork; invalidate fork routing cache on rename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: accept g/ paths in set_ws_specific; gate copy_members to dev workspaces Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6833a554ae |
fix: allow users to always discard their own drafts without write permission (#9659)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
5508f1da9c |
feat(frontend): View Diff and in-place Load for other users' drafts (#9621)
* feat(frontend): replace other-user draft "View JSON" with "View Diff" Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(frontend): replace other-user draft "Fork" with in-place "Load" Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(frontend): detect first overlay edit by value divergence, not a timer Replaces the 700ms arming timer (which leaked across sessions and silently swallowed sub-window edits) with a deterministic check: a blocked save opens the overwrite prompt only once the cell value diverges from the loaded value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): overlay leak on revisit, diff z-index, home-popover edit affordances - Clear a stale "editing another user's draft" overlay when its editor is reloaded without a fresh Load, so returning to the item edits our own draft. - Open View Diff above the others-drafts modal (close it first) instead of rendering the drawer behind it. - Add an Edit button to our own row in the home draft popover; use a pencil icon (not a download) for Load. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: admin "Migrate" action for legacy drafts (delete / assign to self) Adds an admin-gated `POST /drafts/migrate_legacy/{kind}/{path}` endpoint to resolve pre-migration workspace-level drafts (email NULL): delete the row, or move its value onto the admin's own row. Surfaces a "Migrate" button on legacy rows in the home-page draft popover and the in-editor others-drafts modal (workspace admins / superadmins only), opening a modal with Delete and Assign to self. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): close home draft popover before opening View Diff / Migrate The hover popover sits above the diff drawer and migrate modal (z-index), so it covered them. Close it first so they render on top. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): remount the flow builder on "Reset to draft" from an overlay FlowBuilder captures the flow at mount, so reloading the value alone left the foreign graph on screen — reset appeared to do nothing. Force a remount (renderEditor=false → loadFlow) like navigation does. Scripts (imperative setCode) and apps (redraw++) already remount, so only flows needed this. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): refresh the home row after migrating a legacy draft invalidateAll() didn't refetch the home list (it loads items client-side), so the legacy badge entry lingered after delete / assign-to-self. Bubble an onMigrated callback up to the row's `change` event, reusing the same reload chain (Item → ItemsList loadScripts/Flows/Apps) as delete/archive. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * nit * nit * fix(frontend): match app overlay baseline to the migrated value AppEditor migrateApp()s the app on mount, so the draft cell settles to the migrated value. The overlay used the raw loaded value as the divergence baseline, so a post-mount mirror write could trip "Overwrite your current draft?" before any edit. Migrate the baseline too (like the deployed-baseline and raw_app bundle do) so it matches the settled cell. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): address review on legacy-draft migrate + overlay - Legacy "Assign to self" now confirms before replacing an existing own draft (MigrateLegacyDraftModal gains an `ownDraftExists` step, threaded from the home badge and the in-editor others-drafts modal). - Gate overlay mode on a per-response `hasOwnDraft` instead of the sticky `loadedFromDraft`, so navigating to a no-own-draft item in the same editor route can't wrongly enter overlay. Fixed in all 4 editor routes. - Raw-app "View Diff" now projects the deployed app into the flat draft-bundle shape (via a shared `extractDataConfig`) instead of diffing `.value` against the bundle, so the drawer shows a real diff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1fc355709c |
feat: Db-backed user drafts (#9351)
* Db draft removal * refactor: drop unsaved-changes confirmation modal from editors * fix: remove nodraft from flow row edit link * fix: remove nodraft from app and raw app edit buttons * fix: remove nodraft from all edit links * fix: merge backend defaults into legacy autosaves to avoid spurious restore toast on raw apps * feat: add username column to draft table for user-scoped drafts * feat: add sync_drafts and list_users_with_draft_on_path endpoints * feat: add UserDraftDbSyncer service for bi-directional draft sync * feat: wire UserDraft.save through DbSyncer + conflict modal * refactor: gate useLocalStorageValue nested-update effect behind opt-in flag * refactor: move sync force flag from request-level to per-entry * feat: sync all userdraft kinds, switch draft owner to email FK, add id PK, scope draft list to readable paths * refactor: route draft permission check through authed.folders + RLS, drop client-supplied email * feat: support draft deletion via sync (value: null) with same conflict semantics * feat: surface other users' drafts in editors with diff+fork action * refactor: unify draft schema migrations and type kinds via DRAFT_KIND enum * perf: add (workspace_id, email, created_at) partial index for sync hot path * chore: update ee-repo-ref to a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd This commit updates the EE repository reference after PR #597 was merged in windmill-ee-private. Previous ee-repo-ref: 55c19293232be379a3044eb78f677b545882ffd6 New ee-repo-ref: a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd Automated by sync-ee-ref workflow. * fix(userdraft): trigger sync on deep mutations via readFieldsRecursively * Rollback UserDraft * remove queuing logic * pushDrafts * refactor: remove draft sync layer and conflict modal * feat: add save_draft, list_drafts, get_draft routes * feat: add get_draft overlay to getScriptByPath * feat: extend get_draft overlay to flow, app, resource, variable, schedule, triggers * feat: support null value in save_draft for deletes * readLastSyncMap * feat: redirect /add pages to /edit/draft_uuid with new_draft flag * fix: inline get_draft query field instead of flattening * fix: drop dangling nobackenddraft assignment in flows edit * feat: include user drafts in list endpoints with is_draft flag * fix: prefix draft paths with u/{user} and seed editor state on new_draft * fix: route draft-only deletes through UserDraftDbSyncer on home page * feat: delete user drafts when their underlying item is deleted * fix: empty path seed on new_draft so friendly auto-name fires * feat: re-add Draft and Draft only badges on home page rows * fix: synthesize value wrapper on draft-only raw_app response * fix: tolerate missing latest-version on draft-only flow reload * fix: skip first observable change in DB sync effect to match LS persist * fix: remove URL-hash sync from script editor (already marked TEMP) * refactor: drop localStorage layer from UserDraft * refactor: drop vestigial LS-era code from UserDraft * feat: migrate localStorage drafts to DB on layout mount * fix: migrate session runtime + script view to per-user draft API * feat: add 'Reset to deployed' action on draft-loaded toast * feat: hide 'Reset to deployed' action when no deployed version exists * createCoalescingKeyedRunner * example ts doc * createDebouncerByKey * refactor: drop await on draft-delete in reset flows, refetch deployed directly * fix: bridge saved-draft shape to wire shape in apps/resources/variables loaders * feat: route UserDraftDbSyncer.save through debouncer + coalescing runner * feat: add immediate-save bypass that cancels pending debouncer + runner tasks * fix: seed UserDraft cell from spec defaultValue on acquire * fix: redirect /add routes at load phase to eliminate white flash * fix: drop +page.js files in /add routes that conflicted with +page.ts * refactor: send draft as separate .draft field instead of deep-merging onto deployed * feat: surface draft path in home list when user typed one different from URL * feat: add UserDraft.stopSync/restartSync, wire on script + low-code app /add init * fix: thread URL path into ScriptBuilder.stopSync (was using empty initialPath) * fix: also stopSync in route's new_draft branch + queue pre-acquire suspensions * feat: add AutosaveIndicator backed by reactive UserDraftDbSyncer.getState * refactor: drop draft-loaded toast in non-route editors, banner now compares draft vs deployed * fix: gate per-user draft-only rows in listings on include_draft_only flag * feat: flush pending draft saves via keepalive fetch on tab hide / pagehide * autosave indicator nits * fix: route create-vs-update on /add deploys; seed policy.execution_mode; sync script template * chore: add [draft-sync] console logs to trace script bootstrap autosave * fix: seed auto-generated path in script new-draft route to suppress Path widget's autosave-triggering mutation * fix: defer script restartSync until script.path lands (Path widget gated on $userStore + $workspaceStore) * fix: poll script.path via tick() until Path widget settles before restartSync * chore: log inferArgs underlying error on deploy to diagnose 'Could not parse code' toast * fix: wait for script.path to stabilize across two ticks before restartSync * revert: drop unsuccessful path-stabilization heuristics + leftover [draft-sync] logs * fix: seed new-draft script schema as emptySchema() so inferArgs doesn't trip on undefined properties * fix: heal legacy drafts with schema={} (no .properties) on deploy * autosave indicator * refactor(editors): drop UnsavedConfirmationModal mount + Show diff button * feat(drafts): collaboration banner, cross-tab conflict detection, raw app template picker - Other-users-drafts banner (Modal2): the deployed-overlay response now carries `other_drafts_users` (workspace usernames only, never emails); each row offers View JSON + Fork. Drops the standalone `listUsersWithDraftOnPath` endpoint; `getDraftForUser` now takes a workspace `username` query param (resolved to email server-side). - Cross-tab/browser save conflict detection: the syncer attaches `last_sync` to every save (defaults to non-force); on a `conflict` response it parks a snapshot in a reactive map. Each route mounts a `DraftSyncConflictModal` and seeds the per-tab `last_sync` via `recordRemoteSync(query, draft_saved_at)` on every `get_draft` load. Keepalive flush also respects optimistic concurrency. - Raw app template picker re-added after the /add ⇒ /edit refactor: framework (React 19 / 18 / Svelte 5), data table + schema config, and optional AI prompt — extracted into `RawAppTemplatePicker.svelte` and driven by `new_draft=true` on the edit route. * fix(drafts): suppress autosave during /add template seeding on script + raw app editors - ScriptBuilder: delay `restartSync` 500ms past `initContent` + stores- ready so the Path widget's `$workspaceStore && $userStore`-gated `initPath → reset → onMetaChange → bind:path` cascade lands inside the suspension window. Two `tick()` waits weren't enough — the bind:path mutation fired ~100ms after the prior `restartSync` and posted as a "user edit". - apps_raw route: suspend autosave on `new_draft=true` and resume only after the framework picker closes (via `onStart` or X dismissal), with a two-tick settle so the picker's seeded `files/runnables/data/policy` mirror to `draftHandle.draft` observably advances `lastSerialized` before sync re-arms. * fix(drafts): land /add redirects on the real workspace username, not "me" The `/add` → `/edit/u/{username}/draft_{uuid}` redirects ran during SvelteKit's load phase, BEFORE the (logged) layout's async `getUserExt` populated `userStore`. `get(userStore)?.username` returned undefined and fell back to the `'me'` placeholder on every fresh nav, producing `u/me/draft_{uuid}` paths instead of the user's real namespace — broke ownership checks against `authed.username` and silently scoped autosaves under the wrong path. Layout now persists `username` to localStorage on every successful `getUserExt`, and `getUsernameForNamespace` (new shared helper, used by all four `/add/+page.ts` files) reads the live store first, falls back to the cached value, and only then to `'me'` for true first-ever loads. * fix(drafts): key low-code app autosave on the URL path, not the empty string `AppEditor` keyed its `UserDraft.use` handle on `newApp ? '' : path` — a legacy leftover from when `/apps/add` was its own URL (no path). With the `/add` ⇒ `/edit/u/{user}/draft_{uuid}` redirect, `newApp=true` made autosaves land on the `('app', '')` row instead of the URL path: - The `apps/list?include_draft_only=true` query joins drafts onto `app.path`, surfacing drafts at the URL path. The empty-path row didn't match the user's URL so the draft never appeared in the home list. - Refreshing `/apps/edit/u/{user}/draft_{uuid}` re-fetches at the URL path with `?get_draft=true`, finds nothing, and 404s. Drop the ternary so the handle always uses `path` — the same as scripts/flows/raw_apps. The route's `?new_draft=true` branch already seeds the empty-template baseline, so there's no longer a "the draft sits under '' until first save" race to worry about. * fix(raw_app): propagate template picker X / Esc dismissal so autosave resumes The picker mounted `<Modal kind="X" open ...>` (one-way prop, not `bind:open`). When the user dismissed via X / Esc / click-outside, the inner Modal flipped its own local `open` to false (hiding the UI) but never wrote back to the picker's `open` $bindable. The route's `templatePicker → false` watcher — the one that calls `restartSync` two ticks after the picker closes — never fired, so autosave stayed suspended and the user's edits after dismissal were silently dropped. Switch the inner Modal to `bind:open` so the dismissal bubbles all the way up to the route's state. "Start without AI" already worked because its `onStart` handler explicitly sets the picker's `open = false`. * nit unused * fix(drafts): make the home-page View/Edit JSON action work on draft-only apps The "View/Edit JSON" entry on the home page called `AppService.getAppByPath` without `get_draft=true`, so for draft-only items at `u/{user}/draft_{uuid}` the backend 404'd with "App not found at path …". Pass `get_draft=true` and render the synthesized stand-in's editable shape: - App drafts come back as `{summary, value, path, policy, ...}` — `value` is the App definition the editor was working on; show that. - Raw-app drafts come back as the flattened `{files, runnables, data, summary, policy, ...}` with no nested `value`; show the whole shape. On save, draft-only items can't go through `updateApp` (no deployed row). Route the edit through `UserDraftDbSyncer.save` (with `immediate: true` so `await` resolves after the POST lands) and relabel the button "Save draft" + Save icon. Deployed items keep the existing "Deploy" flow unchanged. * fix(drafts): render the right shape in View/Edit JSON for draft-only items The previous fix landed `fapp.value` into the editor, but the deployed-overlay flattens the bare editable shape into `inner`/the top-level response — drafts have no nested `.value`. So: - App drafts (`{grid, breakpoints, hiddenInlineScripts, …}`) rendered as empty (`fapp.value` was undefined). - Raw-app drafts 404'd outright: `get_draft=true` with no `rawApp` flag can't tell which draft kind to look up, defaults to `app`, doesn't find one. Thread the row's `raw_app` flag from AppRow → `appExport.open(path, rawApp)` → `getAppByPath({..., rawApp})` so raw-app drafts resolve to the right `UserDraftItemKind`. Read `fapp.draft` (the bare editable shape from `fetch_draft_only`) into the JSON editor for draft-only items — clean payload, no `is_draft` / `no_deployed` / overlay noise. Save the same bare shape back through the syncer so the regular editor reads it unchanged on the next mount. * fix(drafts): skip public-secret-URL fetch in the Deploy drawer for draft-only apps Opening the Deploy drawer on a `/edit/u/{user}/draft_{uuid}` app fired `AppService.getPublicSecretOfApp` immediately because the gating effect only checked `appPath != ''` + `savedApp`. The `/secret_of/{path}` route plain-SELECTs `app.id`, so a draft-only path 404'd with "App not found at name …" and the public-URL ClipboardPanel spun forever waiting on `secretUrl`. Thread the existing `newApp` signal (already on `AppEditorHeader` / `RawAppEditorHeader`) into `AppEditorHeaderDeploy`, gate the fetch behind `!newApp`, and render the existing "Deploy this app once to get the public secret URL" placeholder instead of the spinner for draft-only items. * fix(drafts): disable Diff button on draft-only items across the 4 editors Diff has no baseline to compare against on draft-only items — the button used to be gated by the pre-PR `/add` route's own state, but the `/add → /edit` redirect landed everything under the regular `/edit` page where the gate was missing. - ScriptBuilder: gate the topbar Diff on `savedScript.no_deployed`; seed `no_deployed: true` on the route's `new_draft` empty NewScript so the gate fires before the first deploy. - FlowBuilder: gate the topbar Diff on `newFlow` (route already sets it from `backendFlow.no_deployed` and the new-draft branch). - AppEditorHeader: gate both the "Diff" dropdown action and the Deploy-drawer's "Diff" button on `newApp`. - RawAppEditorHeader: gate the topbar Diff + the Deploy-drawer's "Diff" button on `newApp`. Each gate also rewrites the tooltip ("Deploy this … once to compare against the deployed version") so the hover state explains why. * fix(drafts): disable the "No login required" toggle on draft-only apps Flipping the toggle called `setPublishState`, which POSTs the new `policy` through `AppService.updateApp` — that handler's `UPDATE app ... RETURNING path` finds nothing on a draft-only path and `not_found_if_none` 404s with "App not found at name …" (apps.rs:1975). Gate the Toggle on `!newApp` too so the user has to deploy once before configuring the publish state. * refactor(drafts): drop dead draft_path field from list responses The draft-only listing branches in scripts/flows/apps computed a `draft_path` from the draft JSON (when the user-typed path differed from the URL's autogenerated `u/{user}/draft_{uuid}`), and `{Script,Flow,App} Row.svelte` preferred it over `path` for the row title. In practice that path is never written: the app, raw-app and flow editors all warn "Deploy the X to make the path change effective" — the rename only lands on deploy, never in the draft. So the field is always None and the home rows always show the autogenerated slot anyway. Drop the field from the three `Listable*` structs, the three draft-only push sites, the three OpenAPI response schemas, and the three frontend row components. Client regenerated. * fix(drafts): seed a friendly name on /flows/add The flow route passed `initialPath={page.params.path ?? ''}` to FlowBuilder, so on the `/flows/add → /flows/edit/u/{user}/draft_{uuid}` redirect the Path widget's `initPath` saw a non-empty `initialPath` and skipped the `reset()` branch that auto-generates the friendly `<random_adj>_flow` name. The other three editors all clear `initialPath` in their `new_draft` branch for exactly this reason. Track `initialPath` as route-owned state (defaults to the URL path) and clear it to '' inside the `new_draft` branch, then bind it through to FlowBuilder so any post-deploy update from the editor still propagates. * feat(drafts): render friendly user-typed path on home list for all 4 kinds Reinstate `draft_path` on `Listable{Script,Flow,App}` so the home rows prefer the user-typed name over the autogenerated `u/{user}/draft_{uuid}` URL slot, with two source rules — one per how each editor wires the Path widget: - Scripts already work: `ScriptBuilder` binds the Path widget directly to `script.path`, so the typed path round-trips through the draft JSON's own `path` field. Backend extracts `v["path"]` when it differs from `row.path`. - Flows / apps / raw apps don't write the typed path into the autosaved value (`Flow.path` is one-way-bound to `$pathStore`; the bare `App` / raw-app value has no `path` field at all). Introduce an explicit `draft_path` field on the draft JSON, written by the editor ONLY when the typed path differs from the deployed/seeded `savedX.path`: - FlowBuilder: $effect on `$pathStore` mutates `flow.draft_path`. - AppEditorHeader: $effect on `newEditedPath` mutates `$app.draft_path`. - RawAppEditorHeader: $effect surfaces `pendingDraftPath` up via the bind chain (RawAppEditor → route); the route's draftHandle.draft spread includes `draft_path` when set. Backend extracts `v["draft_path"]` and `None` when unchanged or after deploy (deploy clears the whole draft, so the field naturally disappears post-deploy without bookkeeping). Flow route's `new_draft` branch now stops sync around the Path widget cascade, with a 700ms scheduled `restartSync` (mirrors the existing scripts/apps/raw_apps stoppers) — the new draft_path mutation lands inside that window so `/flows/add` no longer fires an autosave before the user's first edit. openapi/sqlx regenerated. * fix(drafts): preserve the user-typed draft_path on reload of draft-only items The flow / app / raw-app editors all dropped the saved `draft_path` back to the URL's `u/{user}/draft_{uuid}` slot the moment the user reloaded a draft-only edit page: the route sourced the Path widget's initial path from `page.params.path` instead of the previously-saved `draft_path`, and the first user edit then mirrored that URL path back into the autosaved draft — silently overwriting the friendly name in both the row and the editor. - Flow route: after computing `effectiveFlow`, override `flowInitialPath` with `effectiveFlow.draft_path` when set. - App route: pass `newPath={(app.value as any)?.draft_path ?? app.path}` through to `AppEditor`; AppEditorHeader's `newEditedPath` default now prefers a non-empty `newPath` over the random `<adj>_app` seed (the `newApp && !newPath` branch keeps the `/apps/add` friendly auto-name). - Raw-app route: surface `savedRawAppDraft.draft_path` onto `backendApp` so the `extractRawApp` path seeds `newPath` with the friendly name. Reload + a subsequent edit now leaves `draft_path` intact for all three kinds; verified end-to-end via the `/drafts/get_draft/...` endpoint. * fix(ui): default Modal2 target to 'body' so omitting the prop doesn't throw Modal2 defaulted `target = ''` and forwarded it to `Portal`, which calls `document.querySelector(target)` — an empty selector throws "Failed to execute 'querySelector' on 'Document': The provided selector is empty" and the modal silently fails to mount. That's why `OtherUsersDraftsModal` (and `DraftSyncConflictModal`) never appeared on editors where another user had a draft — both omit the `target` prop. Other Modal2 callers (StorageSettings, CriticalAlert, CustomInstanceDbWizardModal, …) pass an explicit `target="#content"` and were unaffected. Match Portal's own default of `'body'` so omitting the prop is now a no-op rather than a runtime throw. * fix(drafts): Reset to deployed no longer resurrects the draft The toast's "Reset to deployed" callback POSTed `value: null` to the syncer, then handed control to the route's `onResetToDeployed` (which wipes the in-memory handle and reloads the deployed payload via `getDraft: false`). Both writes flowed through the reactive sync effect: the wipe scheduled a delete, the reload scheduled a re-save of the deployed value as the new draft. Coalescing collapsed them and the draft came back — making the "discard" action effectively a no-op. Wrap the whole callback in `UserDraft.stopSync` / `restartSync`. The explicit `value: null` POST still goes through (it's a direct `UserDraftDbSyncer.save` that doesn't depend on the reactive effect), the route's wipe-then-reload mutations advance `lastSerialized` silently under suspension, and the next user edit (after two ticks past the deployed-seed write) is the first real save again. * ui nit * feat(drafts): autosave-indicator popover with Reset-to-deployed action Click the cloud icon → popover with "All changes are saved as a draft on the server. The draft is per-user — your teammates' editors keep their own." When the editor isn't on a draft-only path AND the user has a draft (UserDraft.has returns true), a "Reset to deployed" button mirrors the load-time toast action — stops sync, POSTs `value: null`, runs the route's reload-without-draft callback, restarts sync past two ticks so the deployed-seed write doesn't resurrect the draft. Threaded `onResetToDeployed` from each route down to its builder (ScriptBuilder / FlowBuilder / AppEditorHeader / RawAppEditorHeader) and into the indicator. `draftOnly` is wired from `savedScript.no_deployed` / `newFlow` / `newApp` so the action hides where there's nothing to fall back to. The indicator's trigger now has a hover affordance + matches Portal's default target ('body') via Modal2's earlier fix. * fix(drafts): wait for the fork POST to land before navigating OtherUsersDraftsModal's Fork action called UserDraft.save, which routes through the autosave debouncer (1500ms). The subsequent goto fired within the same tick, so the destination editor's get_draft=true read ran before the POST landed and 404'd — refreshing worked because by then the debounced save had fired. Call UserDraftDbSyncer.save with immediate: true and await it. The syncer cancels any queued debouncer task for the key and resolves the promise only after the POST completes, so the route load can find the forked draft on the first try. * fix(drafts): conflict detection — keep last_sync map tab-local instead of in localStorage Two tabs editing the same draft both load with last_sync = T0. Tab-1 saves; the server accepts, returns T1, and the syncer wrote T1 into localStorage. Tab-2 then tries to save: it reads the SHARED localStorage map, sees T1 instead of its own baseline T0, sends last_sync = T1, and the backend's WHERE clause (`created_at <= last_sync`) is true → tab-2 clobbers tab-1's edit without ever seeing a conflict. Move the map to tab-local memory (`new Map<string, …>`). Reload of the tab now starts with an empty map; that's fine because the editor's load path calls `recordRemoteSync(query, draft_saved_at)` right after `get_draft=true` returns, reseeding from the authoritative server timestamp before any user edit could fire a save. * fix(drafts): OtherUsersDraftsModal — close on Fork, don't leak clicks through nested JSON Two bugs in the per-editor "another user has a draft" banner: - Fork landed the immediate save but didn't close the banner before navigating. Svelte hadn't torn down the previous route's components by the time goto returned, so the banner lingered on top of the destination editor. Comment the explicit isOpen=false on the happy path so it's clear it MUST run before goto. - Clicking anywhere on the screen while the View JSON drilldown was open closed the underlying banner too. Modal2's clickOutside action fired on every Modal2 instance — both the JSON modal and the underlying banner — because both attach their own listener at the document level. Add `closeOnOutsideClick` opt-out on Modal2 and pass `closeOnOutsideClick={!jsonOpen}` to the outer modal so clicks outside the JSON drilldown only close the drilldown. Drive-by: Modal2's keydown handler now ignores Escape when its own isOpen is false (was a no-op closer that would still preventDefault on every key press, swallowing key events for any siblings). * fix(drafts): conflict modal wording — drafts are user-scoped, not teammate-scoped * fix(drafts): defer reset-to-deployed restart until first user interaction Two-tick `restartSync` was too aggressive: editor remounts emit a tail of cascading writes (Monaco setValue acks, schema re-infer, UI Builder iframe handshakes, schedule-config recomputes, …) that land well after two ticks and would clobber the just-deleted draft with an upsert of the deployed value — making "Reset to deployed" a no-op in practice, the user kept seeing the draft come back. Centralise the suspension lifecycle in a new `runResetToDeployed` helper. It stopSyncs around the reset, POSTs the explicit delete, runs the route's wipe-and-reload, and then arms a one-shot listener on document keydown / input / pointerdown that restartSyncs on the user's next real interaction. A 5-second fallback re-arms sync if the user walks away without touching the editor, so suspensions don't leak. Use it from both the load-time toast (`notifyDraftLoaded`) and the autosave-indicator popover so the two stay in sync — fixes both entry points. * indicator ui nits * fix(drafts): split tab-switch and unload flushes — kill self-conflict on visibility change The single keepalive flush bound to both `visibilitychange → hidden` and `pagehide` self-conflicted on tab switch: visibilitychange fires on every tab/app switch with the page still alive, the keepalive POST advanced the server's `created_at` to a fresh `now()`, the client discarded the response (no listener), the local `lastSync` stayed at the old value, and the next foreground autosave sent that stale timestamp → server saw `created_at > last_sync` → conflict modal for the user's own background-tab write. A still-pending debouncer task made it worse: it fired a second runner POST after the keepalive with the same stale `last_sync`, the second self-conflicted too. Split into two paths: - `visibilitychange → hidden` → `flushOnVisibilityHidden`: route through the normal runner pipeline. The page is alive, so the response can land and `setLastSync` keeps the baseline current. Call `debouncer.cancel(key)` first so a queued keystroke can't double-fire with the same stale `last_sync`. - `pagehide` → `flushOnPageHide`: keep the `keepalive: true` raw fetch for the genuinely-going-away case (the JS context is torn down, the response is necessarily discarded). Same `debouncer.cancel(key)` guard. On the next mount, the route's `recordRemoteSync(query, draft_saved_at)` reseeds `lastSync` from authoritative server state before any user edit can fire a save. * fix(drafts): drop the visibilitychange flush — debouncer keeps running on hidden tabs Tab switching just hides the page; the JS context survives and the debouncer's `setTimeout` keeps counting down. When it fires, the runner POSTs normally and the server's response updates `lastSync`. There's nothing left for a visibilitychange-driven flush to do that the ordinary pipeline doesn't already handle, and adding one only creates extra POSTs to reason about. `pagehide` remains the single trigger for the keepalive flush — that's the case where the JS context is actually being torn down and the runner's pending fetch would otherwise be killed mid-flight. * nit * refactor(drafts): drop LS-era pipeline; backend is canonical on load The PR's iteration left behind a meta/staleness pipeline carried over from the localStorage era — per-rev tracking, a LocalDraftStaleModal, a 'Restored from local storage' toast, and a localDraft-vs-backend comparison branch in every editor loader. With drafts now living in the DB and the optimistic-concurrency lastSync check handling divergence, that whole stack is dead weight. Worse, the comparison branch caused 'Load from server' in the conflict modal to do nothing: the loader preferred the in-memory cell over the backend, so the user-clicked 'load from server' just re-displayed the local edits AND fired two confusing toasts (Restored from local storage + Loaded your saved draft). The rip: * userDraft.svelte.ts: drop UserDraftMeta, StoredDraft.meta, checkStaleness, UserDraftStalenessCause, normalizeForCompare, localDraftDiffers, saveMeta, getMeta, setDraftAndMeta, setMeta, handle.meta/setDraftAndMeta/setMeta, force option. Handle is now just { draft }. * userDraftToast.ts: drop notifyRestoredFromLocal + RestoreFromLocalActions. Update copy. * LocalDraftStaleModal.svelte: deleted. * AppEditor.svelte: drop initialRevs prop and the firstMirror wipe-then-restore dance (it existed only to consume the meta-mismatch skip slot). * All 4 editor routes: backend is canonical on load — the in-memory cell is overwritten with the deployed+draft overlay, the syncer's seed guard swallows the first write so we don't POST it back. * VariableEditor / ResourceEditor: drop the staleness pipeline + rev bookkeeping; backend wins on open. * useTriggerDraftSync.svelte.ts: inline the JSON-normalize + deepEqual utility as a private cfgDiffers helper (kept for the form-vs-deployed dirty check, which is a genuine semantic compare, not LS legacy). * copilot core.ts / userDraftAdapter.ts: drop meta argument from saveAppDraft, loadAppDraftValue, write*Draft. Test assertions on getMeta dropped. Net: -22 typecheck errors, fewer moving parts, conflict modal works. EOF ) * refactor(drafts): remove dead endpoints + UserDraftDbSyncer.getLastSync The list_drafts and get_draft (own) routes were added during PR iteration and never wired up to any frontend caller — the editor overlay path uses the per-kind get-by-path getDraft query parameter, and the home page lists drafts via the per-kind list endpoints, not via /drafts. Drop both routes (+ sqlx caches + OpenAPI entries). UserDraftDbSyncer.getLastSync was a peep-hole for callers that never materialised — the per-tab lastSync map is only ever read by postSave internally, where the bookkeeping already lives inline. * refactor(drafts): extract DraftEditorModals trailer block The four editor routes (scripts/flows/apps/apps_raw) mounted an identical pair of trailer modals — DraftSyncConflictModal + OtherUsersDraftsModal — wrapped in the same guard chain and {#key path} remount. Lift the markup into one component; routes thread their itemKind, path, editPathFor, and loader callback. Pure markup extraction, no state ownership change. Drops the unused userStore import where the trailer was the only consumer. * refactor(drafts): UserDraft.useReactive — kill array-of-one boilerplate The script + flow routes both wanted a handle that re-keys when the URL path changes. UserDraft.use() can't do that (its opts getter is untracked), so each route hand-rolled the same useMany-array-of-one + proxy idiom: const handles = useMany(() => [{ kind, path: reactive }]) const handle = { get draft() { return handles[0]?.draft }, ... } Add UserDraft.useReactive(getSpec) that internally wraps useMany with a single spec and returns the stable proxy. Callers collapse to one line. * refactor(drafts): unify bootstrap suspension via armRestartOnFirstInteraction The flow and raw-app routes each rolled their own end-of-bootstrap resume: a 700ms setTimeout for flows and a templatePicker watcher with double-tick gating for raw-apps. Both are timing-fragile (the comments admit it) and drift from each other. armRestartOnFirstInteraction already existed in userDraftToast.ts for reset-to-deployed: keydown/input/pointerdown listeners (capture phase) that fire restartSync on the first real user touch, with a 5s belt-and-braces fallback. Export it and use it everywhere we'd previously have picked a magic number. For raw-apps this is a tiny behavioural change: the user's template choice now POSTs immediately (the pointerdown that picks the template also resumes sync, so the picker's onStart write rides the wake-up). Previously the choice only persisted on the user's NEXT edit. That's strictly better — navigating away preserves the choice now. * refactor(drafts): type App.draft_path; drop the as-any cast The audit asked for the three editors to converge on one draft_path injection pattern. For App and Flow, the in-builder $effect-mutates- the-store idiom is wedged into a shape that doesn't natively own the field — App's editor type genuinely has no draft_path so the writer had to cast through `as any`, and consumers downstream did the same. The minimum viable fix: declare draft_path on the local App type (it's already a field on the autosaved JSON). Lifting the writes upward into a route-side merger would mean restructuring the AppEditor mirror $effect and the FlowBuilder pathStore plumbing — larger change for the same shape, deferred to a follow-up. Flow already has the typed cast localised at one site. Will get the OpenAPI-level draft_path field as part of task 47 (drop as-any casts on backend overlay reads). * refactor(drafts): extract makeDraftAddLoad helper Four identical /add/+page.ts files differing only by the edit-route prefix. Lift the redirect into a factory, slim each entry point to two lines. * refactor(drafts): type UserDraftOverlay.other_drafts_users in the OpenAPI The backend response carried other_drafts_users on every get-by-path that supports the draft overlay, but the OpenAPI schema didn't declare the field. Each route had to cast the typed response to `any` to read it (and the sibling draft_saved_at), which obscured the real shape from the type system and rotted the discoverability of the draft surface. Add it to UserDraftOverlay. Frontend casts collapse to plain property reads in the three editor routes. * feat(drafts): list & open draft-only items for variables, resources, schedules, triggers For scripts/flows/apps the list and get-by-path endpoints already surface per-user drafts that have no deployed counterpart — that's what gates the home page from 404'ing on an AI-agent-created draft. Extend the same support to the other UserDraftItemKinds: Backend (list endpoints): - Add include_draft_only to ListVariableQuery, ListResourceQuery, ListScheduleQuery, StandardTriggerQuery (the latter covers the 11 trigger kinds via the generic TriggerCrud). - Append per-user draft rows whose path has no deployed row. Same gate as scripts/flows/apps: non-operators, page 0, no narrowing filters. Synthesis is per-kind: ListableVariable/Resource get field-for-field synthesis; ScheduleLight reads NewSchedule shape; Trigger<T> uses a best-effort JSON merge + serde_json::from_value (rows skipped on deserialize failure rather than failing the list). - Add draft_only: Option<bool> with sqlx(default) to each row type so it serializes as the column is opt-in. Backend (get-by-path endpoints): - get_variable, get_resource, get_schedule, get_trigger<T> fall back to fetch_draft_only when the deployed row is missing and the caller passed get_draft=true. Mirrors scripts/flows/apps. OpenAPI: - Shared IncludeDraftOnly parameter under components/parameters, wired into the 11 trigger list endpoints + listRawApps. Inline declarations on listVariable / listResource / listSchedules / listAzureTriggers. - draft_only field on ListableVariable, ListableResource, Schedule, TriggerExtraProperty. Frontend: - variables, resources, schedules, and the 10 trigger list pages (routes + 9 *_triggers) pass includeDraftOnly: true on the initial fetch and render <DraftBadge draft_only> on synthesized rows. Trigger pages got a sed/perl bulk update — pattern is the same across kinds. * fix(drafts): swap crypto.randomUUID() for the project's randomUUID helper crypto.randomUUID() is gated on a secure origin (HTTPS or localhost). Self-hosted Windmill instances often run on a bare HTTP origin or a LAN IP where the WebCrypto API is unavailable, so the /add redirect would throw before issuing the 307. Use the existing RFC4122 v4 helper in FlowChatManager that the rest of the codebase already imports for this exact reason. * fix(editor): leading-edge fire + max-wait cap on Monaco debounce The Editor debounced `onDidChangeModelContent` purely on the trailing edge — every keystroke rescheduled a 500ms timer, and uninterrupted typing held the bindable `code` prop stale until a pause. Stacked behind our 1.5s autosave debouncer that meant our clock didn't even start ticking until 500ms after the user paused, and the `code` binding never updated mid-burst for downstream consumers (lint, live preview, change listeners). Switch to leading + trailing + max-wait: * First keystroke of a burst fires `updateCode` synchronously, then stamps a wall-clock chain start. * Each subsequent keystroke (re)arms a trailing timer at `min(now + changeTimeout, chainStart + maxChangeTimeout)` — the cap is what makes continuous typing materialize at least once per maxChangeTimeout window instead of indefinitely. * When the trailing fires it resets the chain so the next keystroke after a pause is a fresh leading fire. New prop `maxChangeTimeout` (default 1000ms) sits next to the existing `changeTimeout` (default 500ms). Dispose path clears the chain stamp alongside the timer. * feat(drafts): wire Ctrl/Cmd+S to flush the pending autosave immediately Each builder already had a Ctrl/Cmd+S keybinding routed through a saveDraft() no-op left over from the LS-era — the comment said "persistence happens via the page-level UserDraft autosave" but the shortcut was the user's only way to actually force a save without waiting for the 1.5s debounce. Restore the intent. * UserDraftDbSyncer.flush({ workspace, itemKind, path }) — new method that re-submits whatever's queued in pendingSaveOpts with immediate: true. No-op when nothing's pending. * Editor.svelte.flushPendingChanges() — exposes a synchronous updateCode() with chain reset, so callers can drain Monaco's own trailing debounce before asking the syncer to flush. Without this step a Ctrl+S within ~500ms of typing would POST the pre-burst content. * ScriptBuilder.saveDraft() — editor?.flushPendingChanges() → await tick() → UserDraftDbSyncer.flush(). Toast on result. * FlowBuilder.saveDraft() — no direct Monaco ref (flows have many per-module editors); just flushes the syncer. Editor.svelte's new 1s max-wait cap means at most the last <1s of typing in a module Monaco won't be in this POST; it follows in the next autosave round. * RawAppEditor.handleKeydown — adds a 's' case that flushes before the focus guard, so the shortcut fires regardless of where focus is in the editor pane. * fix(drafts): low-code apps — drop spurious autosave on /edit + remount on Load from server Two bugs in low-code app editor (raw apps use a separate code path): 1. Every /edit visit looked like an autosave because loadApp() called UserDraft.discard('app', path, undefined). The comment claimed "this load doesn't POST" but discard always POSTs value: null server-side — that surfaced as a DELETE-my-draft on every page load AND a flash in the AutosaveIndicator. The discard was originally intended to wipe the in-memory cell so AppEditor remounts "fresh". But the path-change $effect upstream already sets app = undefined before each loadApp, which unmounts AppEditor and releases the handle's entry — so a remount via app = backendApp naturally starts with an empty handle. Drop the discard. 2. The conflict modal's "Load from server" called loadApp() but didn't remount AppEditor. Since AppEditor's stateApp is captured once at mount and doesn't react to prop changes, the editor kept showing the conflicting local edits even after a successful reload. Wrap the onLoadFromServer to await loadApp() then bump redraw to force a fresh mount. * feat(drafts): home-page Draft badge — show user-initial circles, drop the '+' The home-page Draft badge previously showed '+Draft' as a flat label. Add per-user awareness: up to 3 user-initial circles render to the left of the label, ordered alphabetically; with 4+ users we collapse to the first 2 + a '+N' overflow circle so rows stay compact. Backend: * New `DraftUserRef { username: Option<String> }` in windmill-types::user_drafts, re-exported from windmill-common so the list endpoints in scripts/flows/apps crates share one import path (windmill-types/windmill-common can't be reordered without a cycle). * ListableScript / ListableFlow / ListableApp gain a `draft_users: Option<sqlx::types::Json<Vec<DraftUserRef>>>` field. The list SQL adds a per-row subquery `SELECT json_agg(...) FROM draft d LEFT JOIN usr u ...` that aggregates the workspace users with a per-user draft at this path. NULL (no drafts) decodes to None; LEFT JOIN against `usr` lets orphaned drafts (user removed from workspace) still surface with username = None. * Synthesized draft-only rows set draft_users to a single-element vector with the authed user (those rows come from `email = $2`). OpenAPI: `draft_users` added to listScripts / listFlows / ListableApp response shapes as an array of `{ username }` with nullable username. Frontend DraftBadge: * Accepts `draft_users: { username?: string | null }[]`. Renders up to MAX_CIRCLES (3) initial circles; at 4+ users renders first 2 + a gray '+N' overflow circle. * Initials: 'john.doe'/'john_doe' → 'JD', 'alice' → 'AL', the legacy NULL-email row → '?'. * Color picked deterministically from a 6-entry palette so the same user gets the same circle color across rows. * Label is now just 'Draft' (dropped the '+'). 'Draft only' is unchanged. * Tooltip lists every user in full. ScriptRow / FlowRow / AppRow thread `draft_users` through their prop types and pass it to DraftBadge. * fix(drafts): suppress 'You have unsaved changes' banner when deployed baseline is null A brand-new variable/resource/trigger (no deployed row yet) has `getDeployed() == null`, but the caller's `show` prop is computed off `current != deployed` which is trivially true while the user types. Result: the banner appeared with 'Show diff' (no-op — the drawer early-returns on null deployed) and a 'Discard' that's semantically backwards (there's nothing to revert to). Gate `show` internally on `getDeployed() != null`. The check sits in the banner rather than each caller because every caller would otherwise need the same boilerplate guard. * fix(drafts): hide LocalDraftBanner when deployed and current match the DiffDrawer's compare Earlier I gated the banner on `getDeployed() != null`, but the user still saw it fire on entries where 'Show diff' opens to 'No changes detected'. That means `show` (the caller's coarse dirty check) flagged a difference the DiffDrawer treats as a no-op — typically toggle defaults (`false ↔ undefined`), removed empty arrays, or key-ordering noise that `cleanValueProperties + orderedYamlStringify` collapses. Replicate the drawer's comparison inside the banner: stringify both sides through the same pipeline and only render when the keys differ. A single `diffKey()` helper keeps the logic local; the catch-and-empty fallback survives a non-serializable side rather than throwing. * ui(drafts): nest user-initial circles inside the Draft badge Previously the circles sat alongside the Badge in a parent flex container; the result read as two separate UI elements. The Badge component already exposes its children as a snippet rendered inside its own flex row, so moving the circles into it makes them feel like part of the same chip. Knock-on tweaks: shrunk the circles from h-4/w-4 to h-3.5/w-3.5 so the badge stays compact, and tinted each circle's ring with the badge's indigo palette (instead of plain white) so the overlap reads as a deliberate stack rather than dots floating on top of the chip. * feat(drafts): drop the authed user's circle, mark own drafts with a '*' suffix Three tweaks to the home-page Draft badge: 1. Filter the authed user out of `draft_users` before rendering circles. The row already signals 'this user has a draft' via the asterisk (below), so a circle for them would be redundant noise. New `currentUsername` prop on DraftBadge — pass `$userStore?.username` from each row. The tooltip still lists every user (with `(you)` next to the authed one) so the full picture is one hover away. 2. The badge already showed whenever `is_draft || draft_users.length > 0` (per-user OR any-user). Spelled the rationale out in a comment — no logic change. 3. Append '*' to the displayed summary when `is_draft` is true. Falls back to `draft_path`/`path` when summary is empty so the marker never decorates an empty string. Threaded the same expression into ScriptRow / FlowRow / AppRow. Slice/overflow math now keys on the post-filter `otherUsers` list, so dropping the authed user doesn't silently shrink the visible count (e.g. 3 users incl. self → 2 circles, not 1 circle + a '+1' bubble). * feat(drafts): clone per-user drafts when forking a workspace `clone_workspace_data` clones every other workspace-scoped table on fork creation (resources, variables, scripts, flows, apps, raw apps, triggers, schedules) but quietly dropped the `draft` table. With per-user drafts that meant any open editor in the parent lost its pending edits the moment a fork was created — surprising and inconsistent with how forks treat the deployed surface. New `clone_drafts` mirrors the existing clone helpers: a single INSERT...SELECT into the target workspace, preserving `path`, `typ`, `value`, `created_at`, and `email`. The `email` FK targets `password.email` which is instance-scoped so it carries across workspaces without remap. `created_at` is preserved on purpose so the per-tab `last_sync` baseline lines up with the parent's timeline — otherwise the fork's next autosave would race a stale `last_sync` and trip the conflict modal on every cloned draft. Plain INSERT (not UPSERT) is safe because the fork target is empty at create time; no conflict against the partial unique indexes (`draft_pkey_with_user` / `draft_pkey_legacy`). The synthetic BIGSERIAL `id` PK is regenerated by the default so it stays out of the column list. * ui(drafts): pin the authed user to the first circle instead of hiding them Previously the authed user was filtered out of the circle row entirely on the theory that the row's '*' suffix already signalled 'this user has a draft'. New requirement: they should always lead the circle row when they have a draft so the visual half of the signal lines up across rows (consistent leading-slot identity, easy scan). Switch from a filter to a sort: `orderedUsers` finds the authed user in `draft_users` and splices them to index 0; everyone else keeps the backend's alphabetical order behind. Slice/overflow math now keys on `orderedUsers`, which guarantees the authed user never falls into the '+N' bubble — they're at position 0 and the slice keeps the head. The popover's '(you)' annotation moves to the circle's title attr too, so hovering the leading circle confirms the identity. * feat(drafts): drop draft_only column from script/flow/app Drafts now live in the `draft` table exclusively — `draft_only` stubs in script/flow/app are redundant. Migration `INSERT INTO draft ... ON CONFLICT (workspace_id, path, typ) WHERE email IS NULL DO NOTHING` so real per-user drafts already at the same path are preserved; only rare stubs that lost their draft get a synthesised workspace-level row. Stubs are then deleted (FKs cascade to *_version) and the column is dropped. List endpoints keep a synthesised `draft_only: true` on rows sourced from the draft table itself (sqlx default on the struct field). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ui(drafts): surface draft state in AutosaveIndicator instead of toast+auto-modal The "Loaded your saved draft" toast and the auto-opening OtherUsersDraftsModal both surprised users on every editor mount. Move both signals into the AutosaveIndicator label: "Loaded from draft" or "Others are working on this {kind}" (priority) sits where Saving/Saved do, with a one-shot light-green flash behind the indicator that fades to transparent. Saving/Saved still win when they fire. The popover gains a "See others' drafts" button that flips the modal open on demand; the modal itself is now externally controlled via a bindable \`isOpen\` threaded through DraftEditorModals. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ui(drafts): per-user View JSON / Fork actions in DraftBadge popover Hover popover used to be a plain text list of usernames. Now each row gets a colored circle icon + name + "(you)" for the authed user, and every OTHER user's row carries View JSON / Fork buttons mirroring the OtherUsersDraftsModal. For draft-only entries owned solely by the authed user, the popover ends with "Only you can see this {kind}" so the row's privacy is obvious. ScriptRow / FlowRow / AppRow thread workspace + itemKind + path + editPathFor through; AppRow switches between app / raw_app on app.raw_app. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * nit * fix(drafts): clone only the forker's per-user drafts on workspace fork clone_drafts copied every user's drafts, but only the forker gets added to the fork's usr table. Drafts owned by absent users LEFT-JOIN to NULL in the home page's draft_users aggregate, surfacing as multiple legacy-style rows at one path and crashing the popover with each_key_duplicate. Filter the clone to email = forker OR email IS NULL, and key the popover's #each by index defensively so future legacy collisions can't crash the page either. Also re-adds `draft_only: None` to NewScript/CreateFlowBody literals in tests — the auto-generated windmill-api-client still carries the field and the previous commit dropped them too aggressively. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): always populate other_drafts_users in maybe_overlay_draft Reset-to-deployed reloads the deployed payload with get_draft=false, which made the backend return other_drafts_users=[]. The route then reassigned otherDraftsUsers to the empty list, dropping the count to 0 and hiding "See others' drafts" in the AutosaveIndicator popover — but the other users' drafts hadn't actually gone anywhere. Fetch the list independently of get_draft so the popover stays accurate across reset reloads. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(drafts): alert user when their draft is older than the latest deploy Open a modal on editor mount when the per-user draft was saved before the latest deploy at the same path — i.e. a teammate deployed a new version while this user's draft was sitting. Two choices: discard the stale draft and pick up the deploy, or keep editing the older draft. DraftEditorModals computes the staleness from the timestamps each route threads in (script.created_at, flow.edited_at, app_version.created_at) and the "Load latest deploy" callback reuses the route's existing reset-to-deployed logic. Wired for script / flow / app / raw_app editors; trigger / resource / variable drawer editors follow a different pattern and aren't covered here. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): deploy only wipes the deployer's draft, not everyone else's Script / flow / app deploys ran an unconditional DELETE on every draft at the path, so a teammate's deploy silently destroyed any other user's pending draft. After the wipe, the other user's tab kept auto-saving — re-creating the row at a NOW timestamp newer than the deploy — and StaleDraftModal never fired because draft_saved_at had been bumped past the deploy. Filter the DELETE to email = deployer (plus the legacy NULL row), so other users' drafts persist and the stale-draft prompt actually fires on their next reload. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): surface save failures in AutosaveIndicator instead of pretending Saved postSave caught network errors with `console.error` and let the runner finish normally. The indicator read the saving → none transition as a successful save and flashed "Saved" even when the request had thrown. Track failed keys in a SvelteMap, expose `'failed'` as a new UserDraftSyncState, render "Save failed" in red with a CloudOff icon. Failure clears on the next successful save for the same key, or when recordRemoteSync seeds a fresh authoritative timestamp. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): surface 'Save failed' inside the AutosaveIndicator popover too The popover used to repeat the cheerful "All changes are saved as a draft on the server..." copy even when the inline label said "Save failed", which read as contradictory. Add a red, text-xs warning at the top of the popover body when the sync state is `failed`, explaining that the latest edits didn't reach the server and that editing again retries the save. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): surface the actual error message in the AutosaveIndicator popover Replace the generic "your latest changes did not reach the server" copy with the real failure detail. The syncer now stores the extracted message in the failures map (formatSaveError walks body / message / statusText) and exposes it via the state handle's `failureMessage` getter. Popover renders it in red, monospaced, scrollable so a long server traceback doesn't blow out the popover. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(drafts): suppress Saving/Saved indicator during a reset-to-deployed discard A `value: null` POST is a discard, not a save, but it ran through the same runner the indicator watched — so resetting to deployed flashed "Saving..." → "Saved", reading as "your draft just landed" while we were actually wiping it. Track in-flight discards in a SvelteSet, expose a distinct `'discarding'` UserDraftSyncState, and the indicator stays quiet for it: no spinner, no label change, and the `discarding → none` transition deliberately skips the "Saved" flash. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Revert "fix(drafts): suppress Saving/Saved indicator during a reset-to-deployed discard" This reverts commit |
||
|
|
765f50c474 |
feat: folder-level label inheritance for scripts, flows and jobs (#9524)
* feat: folder-level label inheritance for scripts, flows and jobs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: use SECURITY DEFINER folder_labels() for RLS-consistent inheritance Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: extend folder label inheritance to apps, resources, variables, schedules Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c1e52eab09 |
fix: navigate home arrows (#9024)
* Navigate with arrows * Jumps to other side item + load 30 more * No workspace selector * Recommendations Claude check * Navigation horizontal * Same --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
91064ce857 |
feat(frontend): improve permissions drawer UX and auto-share resource variables (#8824)
* feat: improve permissions drawer UX and auto-share resource variables
- When sharing a resource, automatically detect linked variables ($var: refs)
and offer to apply the same permission changes via a toggle (on by default)
- Rename "Share" to "Permissions" across all dropdown menus (resources, variables,
scripts, flows, apps, schedules, triggers)
- Replace Share icon with Shield icon for consistency
- Show default permissions (folder/user/group) as a separate section in the drawer
- Move item path into drawer title ("Permissions for {path}")
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: guard async results against stale drawer state and null-safe extra_perms
- Add path staleness check in loadLinkedVarPaths and loadDefaultPerms
to prevent late async responses from overwriting state when the drawer
was reopened for a different item
- Use ?? {} fallback for folder.extra_perms which can be undefined
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
c57c769dea |
feat: add CI test scripts with auto-trigger on deploy (#8736)
* feat: add CI test scripts with auto-trigger on deploy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: fix annotation parser early return and handle renames correctly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: move CI test results to top of script/flow detail pages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: improve CI test results spacing, icon, and remove pass label Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: support one-line annotation and use script/path format Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: move CI test trigger logic to EE Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: move CI badge next to New badge and add deduplicated CI summary Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add CI test e2e tests and fix nullable column annotations Add integration tests for CI test annotation parsing (creates/removes ci_test_reference rows) and the CI test results API (single + batch endpoints). Add backend test for auto-trigger on deploy (private+python). Fix sqlx LEFT JOIN LATERAL nullable column annotations in get_ci_test_results and get_ci_test_results_batch queries — sqlx cannot infer nullability from LATERAL subqueries, causing runtime decode errors when no matching job exists. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix build/sqlx * fix * feat: CI test improvements and templates - Fix windmill-dep-map/private feature propagation in worker, api-scripts, and api-flows Cargo.toml so CI test triggers actually fire in EE mode - Clone ci_test_reference rows during workspace fork - Add polling to CiTestResults component (refetch every 3s while running) - Add running state and auto-refresh to ForkWorkspaceBanner CI summary - Add yellow "CI test" badge on script list rows and detail page - Fix Library badge border color (remove indigo border override) - Add CI Test TypeScript and CI Test Python templates in ScriptBuilder - Update sqlx offline cache - Add debug tracing for CI test trigger in worker_lockfiles Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add missing children prop to WorkspaceDeployLayout Fixes svelte-fast-check type error when passing named snippets as children content inside the component tag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review feedback - Remove empty wrapper divs around CiTestResults, move mb-4 into component - Add batch endpoint size cap (max 200 items) - Add ON DELETE CASCADE to ci_test_reference workspace FK (new migration) - Downgrade CI test trigger logs from info to debug - Fix false-positive polling: only treat status='running' as running, not null status (CiTestResults, CompareWorkspaces, ForkWorkspaceBanner) - Fix test numbering in integration tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to latest EE commit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to d9d68c2406df0b59f413ea0b2cb24780a9817d04 This commit updates the EE repository reference after PR #516 was merged in windmill-ee-private. Previous ee-repo-ref: d7ccd9b86da99ec056a0e8708e3637d64290387a New ee-repo-ref: d9d68c2406df0b59f413ea0b2cb24780a9817d04 Automated by sync-ee-ref workflow. * fix: treat queued jobs (job_id set, null status) as running Jobs that have been pushed but not yet picked up by a worker have a job_id but null status. Treat these as 'running' to avoid showing misleading 'pass' badges or '0 passing'. Tests that were never triggered (no job_id, null status) remain neutral/hidden. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: hugocasa <hugo@casademont.ch> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
c4c9ef5fd7 |
feat: add optional labels to scripts, flows, apps, schedules, triggers (#8609)
* feat: add optional labels to scripts, flows, apps, raw apps, schedules, and triggers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update sqlx cache, make labels optional in openapi, regenerate system prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add minimal labels input UI to script, flow, and schedule editors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reduce gap between summary and labels input
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to script/flow detail pages and summary/path popover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move labels inside SummaryPathDisplay trigger for clickable area, reduce gap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: display labels inline to the right of summary, not below
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase gap between summary and labels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to resources/variables, make labels nullable, add home page label filter badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels to workspace export/import, resources, variables + test coverage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make migration idempotent, regenerate sqlx cache after merge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pass labels in script create and flow create/update API calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add labels input UI to resource and variable editors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove negative margin from LabelsInput to prevent overlap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add top and left margin to LabelsInput for better spacing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reduce left margin on LabelsInput
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: widen label input to w-32
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use inline-flex so LabelsInput doesn't stretch full width
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove flex-wrap so label input stays on same line as badges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add label filter presets to resources, variables, and schedules search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use max-w-32 on label input to prevent stretching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pull labels closer to summary with negative top margin
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase negative margin to pull labels even closer to summary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pass labels in schedule create/update API calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use COALESCE to preserve existing labels when not provided in schedule/flow update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add labels to CreateResource, EditResource, CreateVariable, EditVariable in OpenAPI spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label badges on resource and variable list pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label badges on schedule and all trigger list pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add folder and label presets to schedules search filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: apply user_folders_only filter on all workspaces including admins
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add label presets to resources and variables search filters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: derive folder presets from loaded items, not all workspace folders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add label query parameter to resource and variable list endpoints in OpenAPI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display label filter badges inline with folder filters on home page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "feat: display label filter badges inline with folder filters on home page"
This reverts commit
|
||
|
|
31d6660d56 |
feat: script module mode with CLI sync, preview, and WAC UI improvements (#8380)
* feat: add script module mode with folder model for Bun and Python Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add missing modules field to RawCode in bun_executor Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * sqlx * feat: enrich WAC templates with checkpoint and replay semantics Add prominent comments explaining that all computation must happen inside task/step/taskScript or it will be replayed on resume/retry. Clarify that waitForApproval does not hold a worker and that approve/reject URLs are available in the timeline step details. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cli): script module sync idempotency, per-module hash tracking, and preview support - Fix pull→push idempotency: use `??` instead of `||` for module lock field so empty strings are preserved (matches API's `lock: ""`) - Add per-module hash tracking in wmill-lock.yaml following the flow inline script pattern (SCRIPT_TOP_HASH + per-module subpath hashes) - Selective module lock regeneration: only regenerate locks for modules whose content actually changed, not all modules - Use unfiltered rawWorkspaceDependencies for module hashes to match what updateModuleLocks passes to fetchScriptLock - Show changed module names in stale script output for clarity - Add module support to `script preview` command: read modules from __mod/ folder and pass them in the preview API request - Add preview tests for taskScript pattern (flat and folder layout) - Update test assertion for module stale detection output Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(frontend): WAC UI improvements — reorder templates, module tab rename, import consolidation - Reorder WAC template buttons: TypeScript before Python in ScriptBuilder, CreateActionsScript, and CreateActionsFlow - Remove dropdown items from +Script button (simplify to direct link) - Move "Import Workflow-as-Code" to +Flow dropdown with dedicated drawer - Add module tab rename: pencil icon on hover opens popover with validation, fixed-width icon container prevents layout shift Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: remaining module-mode changes from working branch - Backend parser updates for WAC detection - CLI sync/types updates for raw app path and module support - Frontend UI polish (Dev.svelte, ScriptRow, script hash page) - Test fixture updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(cli): add test for module modification detection in generate-metadata Verifies that modifying a single module file re-triggers stale detection and only the changed module is listed, not all modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): critical fixes from PR review - Fix hardcoded dev path in bun_executor.rs WAC v2 wrapper — use "windmill-client" import instead of absolute filesystem path - Fix missed no_main_func → auto_kind rename in parser TS test - Add modules column to clone_script SQL (windmill-common and windmill-api-workspaces) so cloned scripts retain their modules - Add modules: None to RawCode structs in worker tests - Restore complete sqlx cache (merge main's cache + our new queries) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix clone warning treated as error in CI Change `.clone()` on double reference to `*k` dereference in scripts.rs hash implementation. Update sqlx cache with new query hashes from modified clone_script SQL. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): use published parser wasm versions for CI build The local file:// paths for windmill-parser-wasm-py and windmill-parser-wasm-ts don't exist in the Cloudflare Pages build environment. Revert to published npm versions (1.655.0). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): update parser wasm packages to 1.657.2 Use newly published windmill-parser-wasm-ts and windmill-parser-wasm-py v1.657.2 which include auto_kind/WAC detection changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): regenerate package-lock.json for npm ci compatibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): use main's lockfile as base, update only parser wasm packages Regenerating package-lock.json from scratch pulled different dependency versions causing svelte-check type errors. Instead, start from main's lockfile and only update the two changed packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): add modules column to fetch_script_for_update query The Script<SR> struct has a modules field (FromRow), but fetch_script_for_update didn't SELECT modules, causing a runtime error "no column found for name: modules" when the worker processed dependency jobs. This was the root cause of the relock_skip test timeout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix script module execution for Python and Bun - Fix modules not passed through job queue: inject _MODULES into PushArgs.extra when pushing Code jobs so worker can extract them - Fix Python module imports: use relative imports (from .helper) and add sys.path.insert for module directory in wrapper - Fix Python tests: use relative imports and empty lock to prevent pip from resolving module names as packages - Add local file check in Bun loader for module resolution - Ignore Bun module test (bundle mode loader integration tracked separately) - Add missing modules column to fetch_script_for_update query Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): remove unnecessary empty lock in Python module tests Relative imports (from .helper) are not parsed as pip packages, so the empty lock workaround is not needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(backend): fix module execution for Python and Bun — all tests pass Python modules: - Use relative imports (from .helper import greet) since scripts run as packages - Add sys.path.insert for module directory in wrapper to ensure local modules take precedence over pip packages with same name Bun modules: - Use bundled output (./out/main.js) as wrapper import when modules are present — the bundled output has module content inlined by Bun.build, avoiding runtime loader resolution issues - Add local file check in loader.bun.js onResolve to short-circuit API URL resolution for module files on disk Job queue: - Inject _MODULES into PushArgs.extra when pushing Code jobs so the worker can extract them at execution time Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address PR review — simplify, fix correctness, remove dead code Critical fixes: - Replace all CLI `no_main_func` references with `auto_kind` (string) to match the backend migration and API changes - Remove duplicated `compute_python_module_dir` in worker.rs, use the canonical version from python_executor.rs High priority: - Auto-create `__init__.py` in intermediate directories for nested Python modules so imports like `from .utils.math import add` work without users manually creating __init__.py files - Remove redundant `sys_path_insert` — relative imports use Python's package system, not sys.path Medium: - Fix lock file base name extraction: use regex to strip only the final extension (`.replace(/\.[^.]+$/, '')`) instead of `indexOf(".")` which breaks for files like `helper.test.ts` Simplification: - Remove dead `{#if false}` Popover block in ScriptEditor.svelte - Guard loader.bun.js local file check to only run for relative paths (matching the Windows loader pattern) - Add clarifying comment on Bun dual mechanism (build + run phases) - Add maintenance comment on manual Hash impl for NewScript Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: final review fixes — stale cleanup, baseName, auto_kind export - Fix sync.ts baseName extraction using indexOf(".") → regex (same fix as script.ts/metadata.ts, missed this instance) - Add stale module file cleanup in writeModulesToDisk: removes files from __mod/ that are no longer in the modules map before writing, fixing the pull→push cycle that couldn't delete modules - Log warning when _MODULES serialization fails in job push instead of silently dropping modules - Use strict equality (===) for auto_kind comparison - Exclude auto_kind from workspace export — it is auto-detected by the parser at deploy time from script content Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): remove auto_kind from push, comparison, and metadata auto_kind is auto-detected by the parser at deploy time, so the CLI should not send it, compare it, or write it to script.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove erroneously added backend/backend/.sqlx directory Duplicate .sqlx cache was committed at the wrong nested path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review feedback + fix CI dead_code warning Frontend (ScriptEditor.svelte): - Fix switchToMain() missing lastSyncedCode update — prevents stale code sync on external changes while editing a module tab - Fix formatAction saving module code to main script's localStorage draft — now saves main code when on a module tab - Fix non-null assertion on inferModuleLang in renameModule — fall back to original language instead of force unwrap - Remove redundant activeModuleTab truthy check in runTest CLI (script.ts): - Clean up empty directories after removing stale module files in writeModulesToDisk Backend: - Add path traversal guard in write_module_files — reject module paths containing ".." - Fix dead_code warning on auto_kind field in workspace export struct Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(frontend): improve auto_kind UX + address review findings - Rename "Include without main function" toggle to "Include library scripts" in script list (ItemsList.svelte) - Update NoMainFuncBadge: "No main" → "Library" with clearer tooltip - Filter module file extensions by main script language — Python scripts only allow .py modules, TypeScript only .ts, etc. - Split flushModuleState into flushModuleContent (no UI side-effect) and flushModuleState (flush + reset tab), reducing duplication - Dynamic placeholder and hint text in add module popover based on main script language Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
f6ceb2e366 |
Remove edit in fork button for app.windmill.dev (#8213)
* Remove edit in fork button for app.windmill.dev * remove duplicate import |
||
|
|
cf7f704a91 |
add button to edit in workspace fork (#8119)
* Add button to edit in workspace fork * Remove old fork from script row * Remove fork button from approw * fix frontend check |
||
|
|
2851b6b7ca | feat: restriction rulesets for workspaces (#7879) | ||
|
|
309de58134 |
Revert "feat: restriction rulesets for workspaces (#7791)" (#7820)
This reverts commit
|
||
|
|
a1cd02d7f8 |
feat: restriction rulesets for workspaces (#7791)
* Add frontend for the workspace proctection rules * api to add and update workspace protection rules * Fix bypasser selection * Fix Select bug on refocus * Change rulesets to use bitflags * Messages for protection rules errors * claude remove ui for rules * Hide edit buttons when rule * No edit refactor pt1 * Update edit buttons to be disabled when rule is active * Merge deploy ui and rulsets in one tab * Remove not cleaned line in migration * multiple fixes * Remove old protection rule logic * Add prrotection rule for deploying through Merge UI * Add Alert on legacy Deploy UI * Add backend enforcing of workspace rules * Finish backend blocking on rulsets * Last changes to api ruleset blocks * Prepare sqlx * Remove unused import and argument * Update SQLx metadata * fix npm run check * Re trigger CI --------- Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> |
||
|
|
a3d75ba10a |
feat: favorite datatable and ducklake tables + asset page nits (#7795)
* update cf worker hostname
* set remote_url cookie from param
* ephemeral backends v1
* nit
* Run queue server
* ntis
* timeout
* better db process management
* commit hash and worktree
* nit use map
* nit
* err handling
* Revert "err handling"
This reverts commit
|
||
|
|
9d2785bece | fix npm check | ||
|
|
dccee1dba0 |
fix(frontend): forking UI issues (#7215)
* fix(frontend): forking UI issues * fix dark mode |
||
|
|
6d403da05a |
fix(cli): resource type sync with protected private hub (#6933)
* fix(cli): resource type sync with protected private hub * nits |
||
|
|
032f0c1f8c | feat: UX/UI full overhaul to meet new design system | ||
|
|
39b2f54779 | feat(frontend): allow publishing script to hub from list view (#6634) | ||
|
|
328ef605ad |
feat: triggers error handler and retry (#6138)
* feat: http triggers error handling and retries * feat: handle sync http triggers * feat: triggers retry and error handling * feat: frontend and preprocessor * fix build * minimum allow dead code * check workspace tags in schedules * fix flow preprocesor + hub urls * update ee ref * nit * nit * final nits * schedule UI nits * migrate workspace settings to svelte 5 |
||
|
|
e6a9f2d593 | nits svelte 5 migration | ||
|
|
b4a6a7e724 |
feat: fill runnable inputs with AI chat (#5887)
* feat: integrate TriggerableByAI with SchemaForm components - Add currentValue and schema props to TriggerableByAI component - Wrap all ArgInput fields with TriggerableByAI for AI chat integration - Each input field now registers with AI chat manager including: - Current field value - Schema details (type, description, format, etc.) - Proper triggering mechanism for AI-driven value updates This enables AI chat to interact with any input type generated by SchemaForm, allowing intelligent form field modifications based on context and user intent. Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> * add schema to description * draft * draft * just use json inputs component * good starting point * add triggerable to scriptrow + shortcut * fixes * save prompt for ai in schema * fix * change visibility * simplify * cleaning * fixes * add tool to fetch resources * fixes * add try catch * fix prompt * cleaning * use ask ai button * fix * no animation on form + fix empty summary * add inputselectedbadge * better action description + fix rows border --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> Co-authored-by: centdix <farhadg110@gmail.com> |
||
|
|
cbba8297cd |
feat: add navigator mode to AIChat and unify UI (#5859)
* feat: ai flow chat * youpi * feat: preprocessor and error handler support * fix: reactivity * Add GlobalChat component with drawer functionality - Create GlobalChat.svelte with placeholder chat functionality - Create GlobalChatDrawer.svelte as drawer wrapper - Add global chat button to sidebar menu (both mobile and desktop) - Integrate global chat state management in main layout - Include message history, loading states, and error handling - Implement responsive design and proper drawer behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> * draft * use triggerable by ai compoennt * make drawer triggerable * implement logic * add inkeep tool * cleaner code * make more things available * more integrations + better system prompt * fix docs fetching * small fix * cleaning * add ask in search bar + right top icon on homepage + suggestions * fix button * disable chat if no ai providers * add inkeep endpoint * draft working stuff * cleaner code * better chat * fix * send license and uid * better anim * move logic * parse links in chat * add missing integration * add reset button * fix * rm file * integrate navigator mode * integrate all changes * add hide button * adjust drawer size * add script ai chat integration * fix drawer * small fixes * small fixes * draft * merge script ai chat with global one * cleaning * fixes * working draft * add aichat service * cleaning more * remove left over from store * more descriptive states * better icon * fix * use pending prompt * cleaning * cleaning * small fix * add inkeep file * clean * add route * Update backend/windmill-api/src/lib.rs Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * cleaning * fix drawer * save open state in local storage * small fix * fixes * small fixes * move chat request to manager * renaming * move flow effects in manager * move chat effects in manager * remove log * Update frontend/src/lib/components/copilot/CronGen.svelte Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Update frontend/src/lib/components/copilot/chat/flow/core.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * change askaibutton folder * define button * ifelse * no any + no default size * use tailwind * use splitpanes * move effects * remove deprecated file * wording * add back disable ai * add error message * modify system prompt * handle confirmation modal * fix * fix * close script settings * fix icon color * fix * fix history manager * fix test panel * save size * remove floating button * fix delete chat * fix * better fix --------- Co-authored-by: HugoCasa <hugo@casademont.ch> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> |
||
|
|
70b7c8c998 |
refactor(frontend): capture refactor UI (#5591)
* migrate postgresEditorInner to svelte 5 syntaxe
* Add postgress
* add postgres capture section
* migrate kafka trigger config to svelte 5
* use snippets in kafka config
* feat: Update KafkaTriggerEditorInner with editMode, hideTarget and other props from WebsocketTriggerEditorInner
* feat: Create KafkaTriggerPanelV2 following WebsocketTriggersPanelV2 model
* feat: Integrate KafkaTriggerPanelV2 into TriggersEditorV2
* feat: add kafka capture panel
* use svelte 5 syntaxe for nats config
* use snippet in nats config
* feat: add editMode for nats trigger config
* fix import
* create NatsTriggerPanelV2.svelte for NATS trigger
* integrate NatsTriggerPanelV2 into TriggersEditorV2.svelte
* Create NatsCapture.svelte and update CaptureWrapperV2.svelte to use it
* migrate MqttTriggerEditorInner to svelte 5
* add mqtt trigger to new trigger panel
* migrate SqsTriggerEditorInner to svelte 5 syntaxe
* feat: add sqs triggers panel
* Add badge to MQTT config section
* remove unnecessary binding
* add gcp to the trigger list
* add prop size to GCP icon
* add gcp trigger utils
* migrate GcpTriggerEditorInner to svelte5 syntaxe
* add gcp trigger panel
* Revert "add gcp trigger utils"
This reverts commit
|
||
|
|
30edcdfe0e |
fix: workspace preprocessor improvements (#5784)
* add tracing to get of authed client * internal: Trigger claude when commenting with /aider (#5783) * add claude instructions files * call claude too when using aider * fix * add draft for linear claude integration * fix: workspace preprocessor fixes * tmp ee ref * fix build * update ee ref * fix: hub script preprocessor handling * fix build * good ref --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: centdix <40307056+centdix@users.noreply.github.com> |
||
|
|
dfb947ff37 |
feat: add run now directly on schedule drawer and duplicate schedule option (#5674)
* add run now on schedule drawer * add duplicate option for schedules * fix * add missing await keywork |
||
|
|
9095ca7b5b | add standalone bundle support on CE | ||
|
|
ea40331ab7 |
Deploy UI warning update (#4601)
* Deploy UI warning update * Harmonization icons --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> |
||
|
|
6693c88353 | deploy ui homepage call optimization | ||
|
|
f300f4cf2e | nits whitelabel | ||
|
|
af0e901954 |
feat: deployment UI filter deployable items (#4183)
* Add column to workspace settings table * Add endpoint to change the deploy UI settings * Make frontend page to edit UI settings * Prepare sqlx * Add deployment restrictions to frontend * Fix function name * Change dependency to minimatch, CE compatibility * Remove default include_path * Remove picomatch types (old dep) * Use empty list instead of globstar as default * All deployable if config is null |
||
|
|
c9300bce2b | fix sveltekit conf | ||
|
|
7b1798f9ef | fix: fix BASE_URL build conf | ||
|
|
0bb2ef34e8 | nit fix | ||
|
|
b1a3244032 | fix: fix BASE_URL build conf | ||
|
|
d7b5796fd8 | small nit BASE_URL | ||
|
|
e21a814712 |
fix: Allow deploying frontend in a sub directory (#3867)
* fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow depolying frontend in a sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Expose base path from $lib/navigation Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow deploying frontend in sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow deploying frontend in sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow deploying frontend in sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow deploying frontend in sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * fix: Allow deploying frontend in sub directory Signed-off-by: Marcel Klehr <mklehr@gmx.net> * update * update --------- Signed-off-by: Marcel Klehr <mklehr@gmx.net> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com> |
||
|
|
45b8f8dab7 | fix: fix edit button on script row | ||
|
|
1f64715043 |
feat: local typescript codebase as bundle (#3694)
* codebases * codebases * foo * foo * foo * foo * fix(frontend): Disable the insert button when required fields are empty strings (#3659) * fix(frontend): use normal password mask for the sensitive fields of the resource editor * handle super admins in password arg input * chore(main): release 1.323.2 (#3660) * chore(main): release 1.323.2 * Apply automatic changes --------- Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> * foo * all * s3_helpers move * progress * all * progress * progress * progress * progress * codebase final * update without ee * sqlx * all * all * all * all * all * all * all * all * all * all * all * all * all * all * all * update * all * all * all --------- Co-authored-by: Faton Ramadani <faton.ramadani14@gmail.com> Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> |
||
|
|
9e36ae066c |
feat: hide scripts with on function main from operators + badge/filter for devs (#3584)
* feat: save in DB whether script has not main function * fix: if cannot parse script args, clear schema * feat: no main function badge and filter * fix: sqlx * fix: no main |
||
|
|
1ea5a68132 |
fix(frontend): add script history in the script menu on the homepage … (#3388)
* fix(frontend): add script history in the script menu on the homepage + move test an iteration * fix(frontend): fix Test an iteration position |