mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-11 16:09:39 +00:00
fix: keep a staged rename when a move carries the draft
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1bcc051f43
commit
98bce2576c
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE draft AS d\n SET path = $3,\n value = to_json(\n CASE WHEN to_jsonb(d.value) -> $4::text = to_jsonb($2::text)\n THEN jsonb_set(to_jsonb(d.value), ARRAY[$4::text], to_jsonb($3::text), false)\n ELSE to_jsonb(d.value)\n END\n )\n WHERE d.workspace_id = $1\n AND d.path = $2\n AND d.typ::text = ANY($5::text[])\n AND NOT EXISTS (\n SELECT 1 FROM draft o\n WHERE o.workspace_id = d.workspace_id\n AND o.path = $3\n AND o.typ = d.typ\n AND o.email IS NOT DISTINCT FROM d.email\n )\n RETURNING d.id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "381d6ead880f0f0c32e6d87d053bf16fad254b0b070317d9bed4fd97541a0272"
|
||||
}
|
||||
@@ -502,12 +502,27 @@ async fn resolve_moved_to(
|
||||
|
||||
// The client re-points its in-flight draft with this patch rather than
|
||||
// reproducing `typed_path_field` / `base_version_field` on its own side.
|
||||
// Both keys have to be rewritten together: the path alone would leave the
|
||||
// draft claiming the pre-move version, and the editor would greet it with a
|
||||
// stale-draft prompt the moment it landed.
|
||||
// The version is always restamped — it is lineage, not intent, and without
|
||||
// it the draft lands at the new path still claiming the pre-move version and
|
||||
// the editor greets it with a stale-draft prompt. The typed path follows the
|
||||
// same rule as `move_drafts_for_path`: only when it still names the old path,
|
||||
// so a rename the user staged in this very editor survives the relocation.
|
||||
// Present and naming the old path ⇒ repoint. Absent ⇒ omit, so the patch
|
||||
// never manufactures a target the draft did not have. Naming anywhere else
|
||||
// ⇒ omit, so a staged rename is preserved.
|
||||
let repoint_path = serde_json::from_str::<serde_json::Value>(value)
|
||||
.ok()
|
||||
.and_then(|v| {
|
||||
v.get(kind.typed_path_field())
|
||||
.and_then(|p| p.as_str())
|
||||
.map(|p| p == path)
|
||||
})
|
||||
.unwrap_or(false);
|
||||
Ok(moved.map(|(new_path, new_by, head)| {
|
||||
let mut patch = serde_json::Map::new();
|
||||
patch.insert(kind.typed_path_field().to_string(), json!(&new_path));
|
||||
if repoint_path {
|
||||
patch.insert(kind.typed_path_field().to_string(), json!(&new_path));
|
||||
}
|
||||
if let Some(field) = kind.base_version_field() {
|
||||
patch.insert(field.to_string(), head);
|
||||
}
|
||||
@@ -667,7 +682,7 @@ async fn update_draft(
|
||||
current_timestamp: now,
|
||||
moved_to: None,
|
||||
moved_by: None,
|
||||
moved_patch: None,
|
||||
moved_patch: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,13 +603,21 @@ pub async fn move_drafts_for_path(
|
||||
base_version: Option<(&str, String)>,
|
||||
) -> Result<MoveDraftsOutcome> {
|
||||
let typs = kinds.iter().map(|k| k.as_str()).collect::<Vec<_>>();
|
||||
// `create_missing = false` on the typed path: absent means "same as the
|
||||
// row's path", which `SET path` already points at `new_path`.
|
||||
// The typed path is only followed along when it still names the OLD path.
|
||||
// - absent (`create_missing = false`): means "wherever my row sits", which
|
||||
// `SET path` already points at `new_path`.
|
||||
// - equal to `old_path`: no rename staged, so it has to follow or deploying
|
||||
// this draft would send the item back where it came from.
|
||||
// - anything else: a rename the user staged in their editor. Deploying
|
||||
// should still land there, so the move leaves it alone.
|
||||
let moved = sqlx::query_scalar!(
|
||||
r#"UPDATE draft AS d
|
||||
SET path = $3,
|
||||
value = to_json(
|
||||
jsonb_set(to_jsonb(d.value), ARRAY[$4::text], to_jsonb($3::text), false)
|
||||
CASE WHEN to_jsonb(d.value) -> $4::text = to_jsonb($2::text)
|
||||
THEN jsonb_set(to_jsonb(d.value), ARRAY[$4::text], to_jsonb($3::text), false)
|
||||
ELSE to_jsonb(d.value)
|
||||
END
|
||||
)
|
||||
WHERE d.workspace_id = $1
|
||||
AND d.path = $2
|
||||
|
||||
Reference in New Issue
Block a user