From 9770dd34744dc4c8bbb04dd3e6a5a7cb6a89bade Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 7 Jun 2026 20:56:45 -0400 Subject: [PATCH] fix(tags): rename-onto-existing in the image modal now merges, not errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image-modal tag kebab's rename dialog still showed a leftover stub ('Merging two tags into one lands in FC-2c') on a name collision, dead-ending the operator. The merge machinery has existed for a while — the Tags view already resolves rename collisions this way. Wire TagRenameDialog to it: on the 409 collision hint, show the same merge confirmation FandomSetDialog uses (target name, image associations moved, alias kept) and POST /api/tags//merge into the existing tag. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/components/modal/TagRenameDialog.vue | 87 +++++++++++++++---- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/modal/TagRenameDialog.vue b/frontend/src/components/modal/TagRenameDialog.vue index 1bd8c08..750c8eb 100644 --- a/frontend/src/components/modal/TagRenameDialog.vue +++ b/frontend/src/components/modal/TagRenameDialog.vue @@ -2,25 +2,55 @@ Rename tag - - - {{ errorMsg }} -
- Merging two tags into one lands in FC-2c. -
-
+ + +
- Cancel - Rename + +
@@ -35,22 +65,41 @@ const emit = defineEmits(['renamed', 'cancel']) const api = useApi() const newName = ref(props.tag.name) const errorMsg = ref(null) -const isCollision = ref(false) +const collision = ref(null) const busy = ref(false) async function submit() { if (!newName.value.trim() || newName.value === props.tag.name) return busy.value = true errorMsg.value = null - isCollision.value = false try { const updated = await api.patch(`/api/tags/${props.tag.id}`, { body: { name: newName.value.trim() } }) emit('renamed', updated) + } catch (e) { + // 409 → the new name collides with an existing tag of the same + // (kind, fandom). Offer to merge into it rather than dead-ending. + if (e.status === 409 && e.body && e.body.target) { + collision.value = e.body + } else { + errorMsg.value = e.message + } + } finally { + busy.value = false + } +} + +async function onMerge() { + busy.value = true + errorMsg.value = null + try { + await api.post(`/api/tags/${props.tag.id}/merge`, { + body: { target_id: collision.value.target.id } + }) + emit('renamed', { id: collision.value.target.id, name: collision.value.target.name }) } catch (e) { errorMsg.value = e.message - isCollision.value = e.status === 409 } finally { busy.value = false }