feat: implement updateTagTreeStatus function to manage tag status updates without mutating original tree

This commit is contained in:
mlogclub
2026-05-30 21:02:37 +08:00
parent 21ac67de5e
commit 6f05d1ebcc
3 changed files with 53 additions and 1 deletions
+5 -1
View File
@@ -64,6 +64,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Input } from "@/components/ui/input"
import { updateTagTreeStatus } from "@/lib/tag-tree"
import {
Table,
TableBody,
@@ -443,7 +444,10 @@ export default function DashboardTagsPage() {
const nextStatus = item.status === 0 ? 1 : 0
await updateTagStatus(item.id, nextStatus)
toast.success(t(nextStatus === 0 ? "tag.enabled" : "tag.disabled", { name: item.name }))
await loadData()
setTree((prev) => updateTagTreeStatus(prev, item.id, nextStatus))
setAllTags((prev) =>
prev.map((tag) => (tag.id === item.id ? { ...tag, status: nextStatus } : tag))
)
} catch (error) {
toast.error(error instanceof Error ? error.message : t("tag.statusUpdateFailed"))
} finally {
+11
View File
@@ -102,3 +102,14 @@ test("flattens only visible branches when a parent is collapsed", async () => {
JSON.stringify([1, 3])
)
})
test("updates a tag status in tree data without mutating the original tree", async () => {
const { updateTagTreeStatus } = await loadModule()
const nextTags = updateTagTreeStatus(tags, 2, 1)
assert.equal(tags[0].children[0].status, 0)
assert.equal(nextTags[0].children[0].status, 1)
assert.equal(nextTags[0].status, 0)
assert.equal(nextTags[1], tags[1])
})
+37
View File
@@ -87,3 +87,40 @@ export function flattenVisibleTagTree(
walk(nodes, 0, "")
return result
}
type MutableTagTreeLike<T> = {
id: number
status: number
children: T[]
}
export function updateTagTreeStatus<T extends MutableTagTreeLike<T>>(
nodes: T[] | null | undefined,
id: number,
status: number
): T[] {
const safeNodes = Array.isArray(nodes) ? nodes : []
function walk(items: T[]): { nodes: T[]; changed: boolean } {
let changed = false
const nextNodes = items.map((item) => {
const nextChildren = walk(item.children)
const statusChanged = item.id === id && item.status !== status
if (!statusChanged && !nextChildren.changed) {
return item
}
changed = true
return {
...item,
status: statusChanged ? status : item.status,
children: nextChildren.nodes,
}
})
return { nodes: changed ? nextNodes : items, changed }
}
return walk(safeNodes).nodes
}