feat: commit UI#5268
Merged
Merged
Conversation
|
👋 Commands for maintainers:
|
05abd0a to
4232f7f
Compare
Introduce the DB-native uncommitted edit layer keyed by draft workflow_versions.id. Each row stores staged YAML for a path on a draft; rows cascade away when the draft version is deleted. Add InTransaction CRUD: upsert path content, mark path deleted (keeps the row so effective read can tell unstaged from staged removal), list, discard (hard-delete to revert staging), and has-staging checks. Document why staged deletion is soft while discard is hard. Includes migration, regenerated structure.sql, model tests for upsert/ discard/isolation, and cascade-on-draft-delete. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Replace direct spec publish with a git-like stage → commit → publish flow for canvas, console, and repository files. Backend adds CommitCanvasStaging and DiscardCanvasStaging (spec into the version row, arbitrary paths into git), wires authorization, and removes CommitCanvasRepositoryFiles. Frontend adds instant local staging indicators (orange uncommitted, blue committed vs live), draft branch status badges, and tab/header dots. Files edits route through staging with Reset/Commit; fix first-keystroke loss in FileMonacoEditor. Publishable state diffs committed YAML baselines against live so ready-to-publish badges and blue dots stay accurate after commit. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Add canvas_staging_commit_publish_test for the stage→commit→publish loop and per-draft staging isolation. Extend shared canvas steps with staging, publish, and draft assertion helpers. Fix agent preamble expectations in service_test for operator-mode session context. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Rewire the superplane_canvas custom tool's update_draft action to stage spec-file edits onto the agent's private draft (then auto-layout the staged canvas) rather than committing them directly. This mirrors the human --stage-only CLI flow and respects the agent permission boundary, where commit and publish stay user-driven. Usage limits are now enforced at commit time, so update_draft no longer fails on node limits at stage time; the tool test is updated to assert successful staging accordingly. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Draft staging changes flashed orange then reverted to blue on refresh, and the "UNCOMMITTED CHANGES" badge stuck after committing console edits. Both came from the frontend cache treating staged and committed content as interchangeable. - Separate staged reads from committed reads with dedicated query keys (versionStagedDetail, consoleStaged) so a committed (stage=false) fetch can no longer overwrite the editor's pending edits. Fixes the orange-flash-on-refresh for the Canvas and Console tabs. - Only switch the Files tab to local staging detection once an in-session edit is actually observed, so a fresh mount no longer hides persisted server-side staging. - Compare console panels through a key-order-insensitive snapshot. The backend serializes panel content with alphabetical map keys while the editor keeps insertion order; a plain JSON.stringify reported these identical consoles as different, leaving the badge orange after commit until a full refresh. - Guard async console save callbacks with a mutation generation so a stale in-flight autosave can't write staged data back into the cache after a commit/reset. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
The console tab's diff surfaces only reflected committed changes, and a draft whose only change was the console lost its "READY TO PUBLISH" badge once it was no longer the active draft. - Drive the console X-ray, diff summary, and "Show diff" modal from the effective draft console (committed + uncommitted staged edits) instead of the committed-only console, matching the canvas tab. Publishable indicators still diff the committed console against live, so publish semantics are unchanged. - Factor per-draft console changes into the draft branch publishable status: diff each inactive draft's committed console against live in addition to the existing graph diff, so console-only drafts keep their "READY TO PUBLISH" badge when inactive. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
While a commit is in flight the button no longer swaps to "Committing…" (which changed its width). The progress spinner now renders to the left of the Reset button, and both Reset and Commit are disabled until the commit response returns. The Reset button label is shortened to "Reset", with "Reset to last commit" moved into a hover tooltip (2s delay). Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
dcd4eae to
000513e
Compare
This branch's Canvas model has no IsTemplate field (templates were removed from the database), so the staging precondition check no longer compiles. Remove the guard to keep StageRepositorySpecFileOperations building. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl>
Restore the CommitCanvasRepositoryFiles RPC alongside the staging flow so the CLI (`canvas update`, `console set`) writes the draft version row directly instead of going through stage -> commit. The direct commit now discards any existing workflow_staging rows for the target version in the same transaction as the version-row write, so a CLI/API commit always supersedes pending staging atomically. - proto: re-add CommitCanvasRepositoryFiles RPC + request/response messages - backend: restore handler, service method, and authorization entry; thread autoLayout + discardStaging through ApplyRepositorySpecFileOperations into UpdateCanvasVersionWithUsage and UpdateConsole - cli: restore CommitRepositoryFiles/CommitRepositorySpecFile and point `canvas update` / `console set` back at the direct-commit path - tests: restore commit_canvas_repository_files_test.go and cover in-tx staging discard Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Canvas edits now stage to workflow_staging before commit, so tests that publish draft changes must call CommitAndPublish explicitly. Add shared helpers to read effective draft spec from staged YAML and update autosave assertions that previously read only the committed version row. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Clarify that canvas edits stage to workflow_staging, agents stage only, and E2E tests must commit before publish when promoting draft changes. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Extract draft staging indicators, graph diff, and commit/reset actions from AppPage into dedicated hooks, fix files editor exhaustive-deps, and keep index.tsx within eslint line/complexity budgets. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Propose Change stays disabled until the committed draft differs from live; canvas edits only stage until Commit, so change-request tests must commit before waiting for the propose action. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Move echo-release guards and draft staging composition out of AppPage so Prettier formatting no longer pushes index.tsx over the max-lines budget. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
mchalapuk
commented
Jun 11, 2026
…ions Extract helpers in useDraftStagingIndicators and the loop mapper so check.lint.ui stays within the ESLint complexity budget. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Agents commit draft edits directly (like the CLI), not via workflow_staging. Map staging, discard, commit-staging, and auto-layout RPCs to update_version so authorization matches the draft-version permission model. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Clarify the UI stage→commit loop vs CLI/agent direct commits, and note that uncommitted staging must be committed before change requests. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Document access/read_runtime actions and note that update_draft uses CommitCanvasRepositoryFiles instead of workflow_staging. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
… budget Split committed-content state and staging sync effects out of useEditor so the hook stays within the max-statements lint cap after the draft staging work. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl>
The Files tab Diff was unreliable. This addresses four issues: - Empty diffs: the diff used loadedContentByPath (staged content, since draft reads use stage=true) as the baseline, so after autosave the baseline equaled the edit. Use committedContentByPath (stage=false) as the baseline instead. - Stale Diff button: reverting a file to its original left a phantom pending change because pending detection preferred the staged loadedContentByPath over the committed baseline. Prefer committed. - Missing spec and post-refresh changes: canvas.yaml/console.yaml edits autosave into the staging layer (not pendingChanges), and repository staging outlives a page refresh while in-memory pendingChanges do not. Surface all server-staged paths not covered by a pending change via a committed-vs-effective (stage=false vs stage=true) read. - Noisy spec diffs: committed YAML is server-serialized and staged YAML is client-serialized, so canvas.yaml showed spurious key-ordering, quote-style, and isCollapsed:false differences. Normalize both sides to a canonical form before diffing so only real edits appear. Add tests for the spec YAML normalization. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
forestileao
reviewed
Jun 12, 2026
Route the Files tab diff, committed-baseline lookups, and committed file selection reads through React Query so already-fetched content is reused instead of refetched. - Add a cached `repositoryFileContent` query (prefix-extending `repositoryFile`, so existing invalidations clear it) and a `fetchRepositoryFileContentCached` helper. Committed (stage=false) content is cached; staged (stage=true) content always refetches so the diff stays correct. - Have `useStagedFileDiffs` and `useEditorLifecycle` read through the cached helper, deduping the committed read and reusing diff content across re-opens. - Make committed baselines reuse the canonical `versionDetail`/`console` caches, collapsing the duplicate committed `console.yaml` read shared with the draft console query into a single request. Signed-off-by: <Your Name> <your@email> Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # web_src/src/pages/app/index.tsx # web_src/src/ui/CanvasPage/components/CanvasModeToggle.spec.tsx # web_src/src/ui/CanvasPage/components/CanvasModeToggle.tsx
mchalapuk
commented
Jun 12, 2026
Merging main shifted three per-rule lint counts one over budget. Resolve without raising the baseline, via behavior-preserving refactors: - usePageTitle: derive the title with useMemo and depend on the stable string, removing the exhaustive-deps eslint-disable-next-line. - TextFieldRenderer: hoist the static editor options to a module-level CODE_EDITOR_OPTIONS const so CodeTextFieldRenderer drops under the max-lines-per-function limit. - parseDefaultValues: collapse the number case into a single ternary to stay under max-statements. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
The agent no longer shells out to the CLI, so its tools now read and write through the same staging layer as the UI editor instead of committing directly to the draft version row. - read: serve effective staged draft content (staged edits when present, otherwise the committed draft) and derive the summary from that YAML - update_draft: validate up front, then save edits as pending staged changes and run auto-layout via the staging path instead of committing - add ParseAndValidateCanvasYAML / ValidateConsoleYAML helpers and a staged-canvas summary, since staging never materializes the version row - DraftActionsWidget: commit staged edits before publishing so the agent's staged changes are included (publish ignores uncommitted staging) - update agent preamble and contributing docs to match the staging flow Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Gate staged reads behind the draft owner, revert git on failed spec commits, flush file staging before Commit, and add debounce generation guards. Rename workflow_staging to workflow_staged_files and StagingState to StagingSummary. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Pick up the workflow_staging -> workflow_staged_files constraint renames (primary key, unique, and foreign keys) after recreating the dev/test databases. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl>
Merge the near-identical TYPE_ACTION and TYPE_TRIGGER branches in getNodeEditData (src/pages/app/index.tsx), which differed only in the metadata map they read from. This drops the function below the max-statements limit (taking the over-budget count from 73 back to 72) and trims the file from 4970 to 4966 lines (under the 4968 max-lines maximum), resolving both budget regressions flagged by make check.lint.ui. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
Apply gofmt struct-field alignment in describe_canvas_version.go and Prettier formatting in src/pages/app/index.tsx so make check.format.go and make check.format.js pass. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
The original 20260610003157 migration already creates the table as workflow_staged_files, so the later rename migration's guarded DO block was always a no-op. The workflow_staging table was never deployed, so drop the rename migration and point structure.sql at the new latest migration version. Signed-off-by: Maciej Chałapuk <maciej@chalapuk.pl> Co-authored-by: Cursor <cursoragent@cursor.com>
shiroyasha
approved these changes
Jun 12, 2026
forestileao
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces server-side draft staging (
workflow_staging) and a stage → Commit → Publish editing loop for multi-draft apps.workflow_staging; Commit (orange) materializes the draft version row; Publish (blue) promotes to live. Orange/blue indicators show uncommitted vs ready-to-publish state.Closes #5328
Resolves #5355
Changes
Backend
workflow_stagingtable and model.StageCanvasRepositoryFile,DiscardCanvasStaging,CommitCanvasStaging.GETwith?stage=true(staging overlay → committed draft row).update_version(agent-allowed).UI
canvas.yaml/console.yamlinstead of writing the version row directly.DescribeCanvaskept for metadata/runtime status; draft spec from effective YAML.CLI
superplane apps canvas get --draft-idreads only committed changes.superplane apps canvas update --draft-idalways commits.Agents
update_draftcommits directly to the UI staging area of the agent's private draft version row viaStageCanvasRepositoryFiles. Agent never commits or publishes.Test Plan
UI — staging loop
canvas.yaml/console.yamlmatch export modal; edit → stage → commitCLI
superplane apps canvas get <app> --draft-id <id>-o yaml → committed draft onlysuperplane apps canvas update --draft-id <id>-f canvas.yaml → commitsAgents