Skip to content

Commit ff897e2

Browse files
Merge branch 'develop' into fix/table-row-deletion-480
2 parents 1fa7ff4 + 064e9c6 commit ff897e2

File tree

5 files changed

+101
-8
lines changed

5 files changed

+101
-8
lines changed

frontend/src/components/WikiDocumentList.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,8 @@ async function applyReorder(payload) {
298298
payload.newParent,
299299
siblingKeys,
300300
);
301-
for (const sibling of payload.siblings || []) {
302-
if (sibling && !sibling._changeType) {
303-
sibling._changeType = 'reordered';
304-
}
301+
if (payload?.item && !payload.item._changeType) {
302+
payload.item._changeType = 'reordered';
305303
}
306304
toast.success(__('Documents reordered'));
307305
await loadChanges();

wiki/api/wiki_space.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ def reorder_wiki_documents(
8585
# Direct reorder for users with write permission
8686
parent_changed = doc.parent_wiki_document != new_parent
8787

88-
# Update parent if changed
8988
if parent_changed:
90-
doc.parent_wiki_document = new_parent
91-
doc.save()
89+
frappe.db.set_value("Wiki Document", doc_name, "parent_wiki_document", new_parent)
9290

9391
# Batch update sort_order for all siblings
9492
_batch_update_sort_order(siblings_list)

wiki/frappe_wiki/doctype/wiki_change_request/test_wiki_change_request.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,41 @@ def test_get_change_request_returns_dict(self):
359359
self.assertEqual(data.get("name"), cr.name)
360360
self.assertEqual(data.get("title"), cr.title)
361361

362+
def test_merge_preserves_existing_routes(self):
363+
"""Merging a CR must not regenerate routes for existing documents.
364+
Routes are permalinks — they should remain stable across merges."""
365+
space = create_test_wiki_space()
366+
367+
# Build a small tree with a group and two child pages
368+
group = create_test_wiki_document(space.root_group, title="Introduction", is_group=1)
369+
page_a = create_test_wiki_document(group.name, title="Getting Started")
370+
page_b = create_test_wiki_document(group.name, title="Installation")
371+
372+
# Record routes before CR merge
373+
routes_before = {}
374+
for doc in (group, page_a, page_b):
375+
doc.reload()
376+
self.assertTrue(doc.route, f"{doc.title} should have a route")
377+
routes_before[doc.name] = doc.route
378+
379+
# Create a change request that only edits content (no structural changes)
380+
cr = create_change_request(space.name, "Content update")
381+
page_a_key = frappe.get_value("Wiki Document", page_a.name, "doc_key")
382+
update_cr_page(cr.name, page_a_key, {"content": "Updated content"})
383+
384+
# Merge — this used to set doc.route = None for every document,
385+
# forcing regeneration and triggering duplicate-route errors.
386+
merge_change_request(cr.name)
387+
388+
# Verify routes are unchanged
389+
for doc_name, old_route in routes_before.items():
390+
current_route = frappe.db.get_value("Wiki Document", doc_name, "route")
391+
self.assertEqual(
392+
current_route,
393+
old_route,
394+
f"Route of {doc_name} changed after CR merge: {old_route!r} -> {current_route!r}",
395+
)
396+
362397
def test_archive_change_request_sets_status(self):
363398
space = create_test_wiki_space()
364399
create_test_wiki_document(space.root_group, title="Page A")

wiki/frappe_wiki/doctype/wiki_change_request/wiki_change_request.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,6 @@ def apply_merge_revision(space: Document, revision: Document) -> None:
12151215
content = frappe.get_value("Wiki Content Blob", content_blob, "content")
12161216
doc.content = content
12171217

1218-
doc.route = None
12191218
if doc.is_new():
12201219
doc.insert()
12211220
key_to_name[doc_key] = doc.name

wiki/test_api.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,69 @@ def test_reorder_via_frappe_call(self):
266266
self.assertEqual(sort_orders["Q5"], 0)
267267
self.assertEqual(sort_orders["Q6"], 1)
268268

269+
def test_reorder_preserves_routes(self):
270+
"""Routes must never change during reorder — neither for simple sort-order
271+
changes nor for reparenting. A page's route is its permalink and must
272+
remain stable regardless of where it sits in the tree."""
273+
from wiki.api.wiki_space import reorder_wiki_documents
274+
275+
space = create_test_wiki_space()
276+
277+
# Build a small tree:
278+
# root_group
279+
# ├── group_a (group)
280+
# │ ├── page_1 (leaf)
281+
# │ └── page_2 (leaf)
282+
# └── group_b (group)
283+
group_a = create_wiki_document(space.root_group, "Group A", is_group=True)
284+
page_1 = create_wiki_document(group_a.name, "Page One")
285+
page_2 = create_wiki_document(group_a.name, "Page Two")
286+
group_b = create_wiki_document(space.root_group, "Group B", is_group=True)
287+
288+
# Record every route before any reorder
289+
routes_before = {}
290+
for doc in (group_a, page_1, page_2, group_b):
291+
doc.reload()
292+
routes_before[doc.name] = doc.route
293+
294+
frappe.set_user("Administrator")
295+
296+
# --- Case 1: simple sort-order swap (no parent change) ---
297+
# Swap group_a and group_b among the root's children
298+
siblings = json.dumps([group_b.name, group_a.name])
299+
reorder_wiki_documents(
300+
doc_name=group_b.name,
301+
new_parent=space.root_group,
302+
new_index=0,
303+
siblings=siblings,
304+
)
305+
306+
for doc_name, old_route in routes_before.items():
307+
current_route = frappe.db.get_value("Wiki Document", doc_name, "route")
308+
self.assertEqual(
309+
current_route,
310+
old_route,
311+
f"Route of {doc_name} changed after sort-order reorder: "
312+
f"{old_route!r} -> {current_route!r}",
313+
)
314+
315+
# --- Case 2: reparent page_1 from group_a into group_b ---
316+
siblings_in_b = json.dumps([page_1.name])
317+
reorder_wiki_documents(
318+
doc_name=page_1.name,
319+
new_parent=group_b.name,
320+
new_index=0,
321+
siblings=siblings_in_b,
322+
)
323+
324+
for doc_name, old_route in routes_before.items():
325+
current_route = frappe.db.get_value("Wiki Document", doc_name, "route")
326+
self.assertEqual(
327+
current_route,
328+
old_route,
329+
f"Route of {doc_name} changed after reparent: " f"{old_route!r} -> {current_route!r}",
330+
)
331+
269332
def test_reorder_detailed_debug(self):
270333
"""Detailed test to trace exactly what happens during reorder.
271334

0 commit comments

Comments
 (0)