fix: clean up orphan labels when syncing note labels
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 43s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 43s
After syncing a note's labels, detect and delete labels in the same notebook that are no longer referenced by any note (neither via JSON nor labelRelations). Prevents phantom labels from accumulating. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,8 @@ async function syncLabels(userId: string, noteLabels: string[] = [], notebookId?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sync both Note.labels (JSON) AND labelRelations for a single note. */
|
/** Sync both Note.labels (JSON) AND labelRelations for a single note.
|
||||||
|
* Also cleans up orphan labels in the same notebook scope. */
|
||||||
async function syncNoteLabels(noteId: string, labelNames: string[], notebookId: string | null, userId: string) {
|
async function syncNoteLabels(noteId: string, labelNames: string[], notebookId: string | null, userId: string) {
|
||||||
const uniqueNames = [...new Set(labelNames.map(n => n.trim()).filter(Boolean))]
|
const uniqueNames = [...new Set(labelNames.map(n => n.trim()).filter(Boolean))]
|
||||||
const labelRows = await syncLabels(userId, uniqueNames, notebookId)
|
const labelRows = await syncLabels(userId, uniqueNames, notebookId)
|
||||||
@@ -146,6 +147,46 @@ async function syncNoteLabels(noteId: string, labelNames: string[], notebookId:
|
|||||||
labelRelations: { set: labelIds.map(id => ({ id })) },
|
labelRelations: { set: labelIds.map(id => ({ id })) },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Clean up orphan labels: labels in this notebook scope that are no longer
|
||||||
|
// referenced by any note (neither via JSON nor via labelRelations)
|
||||||
|
if (notebookId !== null) {
|
||||||
|
const allLabels = await prisma.label.findMany({
|
||||||
|
where: { notebookId, userId },
|
||||||
|
select: { id: true, name: true },
|
||||||
|
})
|
||||||
|
if (allLabels.length > 0) {
|
||||||
|
const labelIdsSet = new Set(allLabels.map(l => l.id))
|
||||||
|
// Find notes in this notebook that have any label relation
|
||||||
|
const notesWithLabels = await prisma.note.findMany({
|
||||||
|
where: {
|
||||||
|
notebookId,
|
||||||
|
userId,
|
||||||
|
labelRelations: { some: { id: { in: Array.from(labelIdsSet) } } },
|
||||||
|
},
|
||||||
|
select: { labels: true },
|
||||||
|
})
|
||||||
|
// Collect all label names still in use via JSON
|
||||||
|
const namesInUse = new Set<string>()
|
||||||
|
for (const n of notesWithLabels) {
|
||||||
|
if (n.labels) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(n.labels as string)
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
parsed.filter((x: any) => typeof x === 'string').forEach((x: string) => namesInUse.add(x.toLowerCase()))
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Delete labels not in use
|
||||||
|
const orphans = allLabels.filter(l => !namesInUse.has(l.name.toLowerCase()))
|
||||||
|
if (orphans.length > 0) {
|
||||||
|
await prisma.label.deleteMany({
|
||||||
|
where: { id: { in: orphans.map(l => l.id) } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Après déplacement via API : rattacher les étiquettes de la note au bon carnet */
|
/** Après déplacement via API : rattacher les étiquettes de la note au bon carnet */
|
||||||
|
|||||||
Reference in New Issue
Block a user