mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
dfbc696ddb
commit
de5769fb56
@@ -215,7 +215,23 @@ async fn test_draft_move_refuses_another_users_other_app_kind(
|
||||
"a classic app was moved onto another user's raw app: {body}"
|
||||
);
|
||||
assert!(
|
||||
body.contains("Another user has a raw app draft"),
|
||||
body.contains("holds another user's raw app draft"),
|
||||
"the refusal did not name the occupant: {body}"
|
||||
);
|
||||
|
||||
// And the other direction, where the occupant reads as the classic kind.
|
||||
let (status, body) = move_to(
|
||||
"raw_app",
|
||||
"u/test-user/mvtaken_raw",
|
||||
"u/test-user/mvtaken_app_theirs",
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
status, 400,
|
||||
"a raw app was moved onto another user's classic app: {body}"
|
||||
);
|
||||
assert!(
|
||||
body.contains("holds another user's app draft"),
|
||||
"the refusal did not name the occupant: {body}"
|
||||
);
|
||||
|
||||
|
||||
+3
-1
@@ -32,4 +32,6 @@ INSERT INTO draft (workspace_id, path, typ, value, email) VALUES
|
||||
('test-workspace', 'u/test-user/mvtaken_raw', 'raw_app',
|
||||
'{"summary": "raw", "files": {}}', 'test@windmill.dev'),
|
||||
('test-workspace', 'u/test-user/mvtaken_theirs', 'raw_app',
|
||||
'{"summary": "theirs", "files": {}}', 'test2@windmill.dev');
|
||||
'{"summary": "theirs", "files": {}}', 'test2@windmill.dev'),
|
||||
('test-workspace', 'u/test-user/mvtaken_app_theirs', 'app',
|
||||
'{"summary": "theirs", "value": {}}', 'test2@windmill.dev');
|
||||
|
||||
@@ -859,8 +859,8 @@ async fn move_draft(
|
||||
// The other app kind, owned by someone else: one deployed path cannot hold
|
||||
// both, so this is the other item's path, not a teammate's copy of this one.
|
||||
format!(
|
||||
"Another user has a {occupant} draft at '{new_path}', and an app and a \
|
||||
raw app cannot share a path."
|
||||
"'{new_path}' holds another user's {occupant} draft, and an app and a raw \
|
||||
app cannot share a path."
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -593,8 +593,9 @@ function createRuntime(session: Session): SessionRuntime {
|
||||
// when the path has never been deployed.
|
||||
const aiDraft = UserDraft.get<Flow>('flow', path, { workspace })
|
||||
|
||||
// getDraft=true omits version_id (the plain getFlowByPath has it) —
|
||||
// stamp it on so the flow doesn't always diff. Best-effort.
|
||||
// Fallback for the head: the payload fetches below carry `version_id`, and
|
||||
// this one covers a response that does not. Best-effort, and a request of
|
||||
// its own, so the same response wins wherever both are available.
|
||||
let deployedVersionId: number | undefined
|
||||
try {
|
||||
deployedVersionId = (await FlowService.getFlowByPath({ workspace, path }))?.version_id
|
||||
@@ -608,9 +609,12 @@ function createRuntime(session: Session): SessionRuntime {
|
||||
// yet on the backend — draft-only flows are a valid state.
|
||||
try {
|
||||
const result = await FlowService.getFlowByPath({ workspace, path, getDraft: true })
|
||||
// `getDraft` omits `version_id`; the editor's deploy guard compares
|
||||
// against it, so put the head fetched above back on the baseline.
|
||||
saved.val = { ...(result as SavedFlow), version_id: deployedVersionId }
|
||||
// The editor's deploy guard compares against the head, so keep this
|
||||
// response's own and fall back to the one fetched above.
|
||||
saved.val = {
|
||||
...(result as SavedFlow),
|
||||
version_id: (result as SavedFlow).version_id ?? deployedVersionId
|
||||
}
|
||||
} catch {
|
||||
saved.val = undefined
|
||||
}
|
||||
@@ -622,7 +626,10 @@ function createRuntime(session: Session): SessionRuntime {
|
||||
|
||||
// No local draft yet — seed from `result.draft ?? result`.
|
||||
const result = await FlowService.getFlowByPath({ workspace, path, getDraft: true })
|
||||
saved.val = { ...(result as SavedFlow), version_id: deployedVersionId }
|
||||
saved.val = {
|
||||
...(result as SavedFlow),
|
||||
version_id: (result as SavedFlow).version_id ?? deployedVersionId
|
||||
}
|
||||
const serverDraft = (result as SavedFlow).draft as Flow | undefined
|
||||
const flow: Flow = (serverDraft ?? (result as Flow)) as Flow
|
||||
// Seed the per-tab last_sync from the server draft's timestamp so the
|
||||
|
||||
Reference in New Issue
Block a user