feat: implement updateTagTreeStatus function to manage tag status updates without mutating original tree
This commit is contained in:
@@ -64,6 +64,7 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { updateTagTreeStatus } from "@/lib/tag-tree"
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -443,7 +444,10 @@ export default function DashboardTagsPage() {
|
|||||||
const nextStatus = item.status === 0 ? 1 : 0
|
const nextStatus = item.status === 0 ? 1 : 0
|
||||||
await updateTagStatus(item.id, nextStatus)
|
await updateTagStatus(item.id, nextStatus)
|
||||||
toast.success(t(nextStatus === 0 ? "tag.enabled" : "tag.disabled", { name: item.name }))
|
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) {
|
} catch (error) {
|
||||||
toast.error(error instanceof Error ? error.message : t("tag.statusUpdateFailed"))
|
toast.error(error instanceof Error ? error.message : t("tag.statusUpdateFailed"))
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -102,3 +102,14 @@ test("flattens only visible branches when a parent is collapsed", async () => {
|
|||||||
JSON.stringify([1, 3])
|
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])
|
||||||
|
})
|
||||||
|
|||||||
@@ -87,3 +87,40 @@ export function flattenVisibleTagTree(
|
|||||||
walk(nodes, 0, "")
|
walk(nodes, 0, "")
|
||||||
return result
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user