fix(structuredclone): change
This commit is contained in:
@@ -51,6 +51,7 @@ import { useRightToolsStore } from "./useRightToolsStore"
|
||||
import { useIntervalStore, useTimerStore } from "./useTimerStore"
|
||||
import { useTopToolsStore } from "./useTopToolsStore"
|
||||
import { findGroupKey } from "./util"
|
||||
import { safeClone } from "./utils/clone"
|
||||
import { labelTypeMap } from "./utils/constants"
|
||||
|
||||
// Splitter component - will need custom implementation or alternative
|
||||
@@ -662,19 +663,19 @@ const LabelPage = ({
|
||||
if (JSON.stringify(current_data) === "{}") {
|
||||
current_data = qaData.get("init")
|
||||
}
|
||||
const qaMap = structuredClone(qaData)
|
||||
const qaMap = safeClone(qaData)
|
||||
qaMap.set(key, current_data)
|
||||
useDescToolsStore.getState().setQaData(qaMap)
|
||||
}
|
||||
} else if (useDescToolsStore.getState().descOperations.length) {
|
||||
if (desc) {
|
||||
const { meta_operation, other_desc } = desc
|
||||
const currentMetaMap = structuredClone(
|
||||
const currentMetaMap = safeClone(
|
||||
useDescToolsStore.getState().metaData
|
||||
)
|
||||
currentMetaMap.set(key, meta_operation || [])
|
||||
useDescToolsStore.getState().setMetaData(currentMetaMap)
|
||||
const currentDescMap = structuredClone(
|
||||
const currentDescMap = safeClone(
|
||||
useDescToolsStore.getState().descData
|
||||
)
|
||||
let descMap = new Map()
|
||||
@@ -1084,7 +1085,7 @@ const LabelPage = ({
|
||||
// }
|
||||
// }
|
||||
// 更新当前数据
|
||||
useLabelStore.getState().setLabel(structuredClone(data))
|
||||
useLabelStore.getState().setLabel(safeClone(data))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import { useOtherToolsStore } from "../useOtherToolsStore"
|
||||
import { usePaperStore } from "../usePaperStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
import { getSubAttrStatus } from "../util"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import CustomModal from "./CustomModal"
|
||||
import MetaOperationTool from "./MetaOperationTool"
|
||||
|
||||
@@ -175,20 +176,16 @@ const BottomTools: React.FC<BottomToolsComponentProps> = (props) => {
|
||||
const prevFramehasTextDesc = () => {
|
||||
if (projectDetail?.label_type === 5) {
|
||||
let flag = false
|
||||
const currentDescData = structuredClone(
|
||||
useDescToolsStore.getState().descData
|
||||
)
|
||||
const currentDescData = safeClone(useDescToolsStore.getState().descData)
|
||||
const prevData1 = currentDescData.get(previousFrameKey) ?? new Map()
|
||||
flag = prevData1.size ? true : false
|
||||
if (flag) return true
|
||||
const currentMetaData = structuredClone(
|
||||
useDescToolsStore.getState().metaData
|
||||
)
|
||||
const currentMetaData = safeClone(useDescToolsStore.getState().metaData)
|
||||
const prevData2 = currentMetaData.get(previousFrameKey) ?? []
|
||||
flag = prevData2.length ? true : false
|
||||
return flag
|
||||
} else if (projectDetail?.label_type === 6) {
|
||||
const currentQaData = structuredClone(useDescToolsStore.getState().qaData)
|
||||
const currentQaData = safeClone(useDescToolsStore.getState().qaData)
|
||||
const prevData = currentQaData.get(previousFrameKey) ?? {}
|
||||
return JSON.stringify(prevData) === "{}" ? false : true
|
||||
}
|
||||
@@ -217,24 +214,20 @@ const BottomTools: React.FC<BottomToolsComponentProps> = (props) => {
|
||||
// LLM
|
||||
if (projectDetail?.label_type === 5) {
|
||||
// 文本描述
|
||||
const currentDescData = structuredClone(
|
||||
useDescToolsStore.getState().descData
|
||||
)
|
||||
const currentDescData = safeClone(useDescToolsStore.getState().descData)
|
||||
const prevData1 = currentDescData.get(previousFrameKey) ?? new Map()
|
||||
currentDescData.set(activeImage, prevData1)
|
||||
useDescToolsStore.getState().setDescData(currentDescData)
|
||||
useDescToolsStore.getState().updateFlag(true)
|
||||
// 元操作序列
|
||||
const currentMetaData = structuredClone(
|
||||
useDescToolsStore.getState().metaData
|
||||
)
|
||||
const currentMetaData = safeClone(useDescToolsStore.getState().metaData)
|
||||
const prevData2 = currentMetaData.get(previousFrameKey) ?? []
|
||||
currentMetaData.set(activeImage, prevData2)
|
||||
useDescToolsStore.getState().setMetaData(currentMetaData)
|
||||
}
|
||||
// QA
|
||||
if (projectDetail?.label_type === 6) {
|
||||
const currentQaData = structuredClone(useDescToolsStore.getState().qaData)
|
||||
const currentQaData = safeClone(useDescToolsStore.getState().qaData)
|
||||
const prevData = currentQaData.get(previousFrameKey) ?? {}
|
||||
currentQaData.set(activeImage, prevData)
|
||||
useDescToolsStore.getState().setQaData(currentQaData)
|
||||
|
||||
@@ -55,6 +55,7 @@ import { useRightToolsStore } from "../useRightToolsStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
import { checkCommentsIsSame } from "../util"
|
||||
import { labelTypeMap } from "../utils/constants"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import { adjustPoints } from "../utils/paperjs"
|
||||
import CrosshairComponent from "./CrosshairComponent"
|
||||
import { renderOperationIcon } from "./RightObjectTools"
|
||||
@@ -456,9 +457,7 @@ const PaperContainer = (
|
||||
hollows: boolean[]
|
||||
}[]
|
||||
} = resData
|
||||
const nowTaskData = structuredClone(
|
||||
useLabelStore.getState().label
|
||||
)
|
||||
const nowTaskData = safeClone(useLabelStore.getState().label)
|
||||
future_contours.forEach(({ contours, hollows }, index) => {
|
||||
const fileName = file_names[index + 1]
|
||||
const imgScale =
|
||||
@@ -1013,7 +1012,7 @@ const PaperContainer = (
|
||||
.selectedItems.filter((k) => k !== activeImage)
|
||||
const copyArr = useKeyboardStore.getState().copyDataIds
|
||||
if (picArr.length && copyArr.length) {
|
||||
const data = structuredClone(useLabelStore.getState().label)
|
||||
const data = safeClone(useLabelStore.getState().label)
|
||||
// 先判断是否有重复的id
|
||||
let existedIds: number[] = []
|
||||
picArr.forEach((imageId) => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useLabelStore } from "../store"
|
||||
import { useBottomToolsStore } from "../useBottomToolsStore"
|
||||
import { usePaperStore } from "../usePaperStore"
|
||||
import { useRightToolsStore } from "../useRightToolsStore"
|
||||
import { safeClone } from "../utils/clone"
|
||||
|
||||
interface ComponentProps {
|
||||
open: boolean
|
||||
@@ -59,7 +60,7 @@ const RightGroupEditModal = ({
|
||||
if (groupMap?.has(id)) return
|
||||
|
||||
const oldIds = groupMap?.get(editId) ?? []
|
||||
const labelData = structuredClone(useLabelStore.getState().label)
|
||||
const labelData = safeClone(useLabelStore.getState().label)
|
||||
// update path
|
||||
let operationIds: any[] = []
|
||||
oldIds.forEach((childId) => {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { renderGroupPath } from "../useRenderGroupPath"
|
||||
import { useRightToolsStore } from "../useRightToolsStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
import { labelTypeMap } from "../utils/constants"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import RightGroupEditModal from "./RightGroupEditModal"
|
||||
|
||||
interface RightGroupToolsComponentProps {
|
||||
@@ -212,7 +213,7 @@ const RightGroupTools: React.FC<RightGroupToolsComponentProps> = (props) => {
|
||||
needUpdateOperationIds[index] = childPath.data.operationId
|
||||
})
|
||||
// handle labeldata update
|
||||
const currentData = structuredClone(useLabelStore.getState().label)
|
||||
const currentData = safeClone(useLabelStore.getState().label)
|
||||
needUpdateOperationIds.forEach((operationId, index) => {
|
||||
if (currentData.get(imageId)?.get(operationId)?.length) {
|
||||
let result =
|
||||
@@ -260,7 +261,7 @@ const RightGroupTools: React.FC<RightGroupToolsComponentProps> = (props) => {
|
||||
needRemoveOperationIds[index] = p.data.operationId
|
||||
})
|
||||
})
|
||||
const currentData = structuredClone(useLabelStore.getState().label)
|
||||
const currentData = safeClone(useLabelStore.getState().label)
|
||||
needRemoveOperationIds.forEach((operationId, index) => {
|
||||
if (currentData.get(imageId)?.get(operationId)?.length) {
|
||||
let result =
|
||||
|
||||
@@ -34,6 +34,7 @@ import { usePermissionStore } from "../store/auth"
|
||||
import { useBottomToolsStore } from "../useBottomToolsStore"
|
||||
import { useDescToolsStore } from "../useDescToolsStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import CustomModal from "./CustomModal"
|
||||
import EditorContainer, { splitWord } from "./EditorContainer"
|
||||
|
||||
@@ -147,7 +148,7 @@ const RightQAContent = forwardRef(
|
||||
}
|
||||
})
|
||||
try {
|
||||
const finalData = structuredClone(currentQaData)
|
||||
const finalData = safeClone(currentQaData)
|
||||
finalData[category] = newArr
|
||||
qaData.set(activeImage, finalData)
|
||||
setQaData(new Map(qaData)) // Force update
|
||||
@@ -192,7 +193,7 @@ const RightQAContent = forwardRef(
|
||||
|
||||
// 处理问题上移
|
||||
const handleQuestionUp = (category: string, index: number) => {
|
||||
const finalData = structuredClone(currentQaData)
|
||||
const finalData = safeClone(currentQaData)
|
||||
let arr = finalData[category]
|
||||
let temp = arr[index]
|
||||
arr[index] = arr[index - 1]
|
||||
@@ -205,7 +206,7 @@ const RightQAContent = forwardRef(
|
||||
|
||||
// 处理问题置顶
|
||||
const handleQuestionUpToTop = (category: string, index: number) => {
|
||||
const finalData = structuredClone(currentQaData)
|
||||
const finalData = safeClone(currentQaData)
|
||||
let arr = finalData[category]
|
||||
const element = arr.splice(index, 1)[0]
|
||||
arr.unshift(element)
|
||||
@@ -226,7 +227,7 @@ const RightQAContent = forwardRef(
|
||||
const currentImg = useBottomToolsStore.getState().activeImage
|
||||
const qaData = useDescToolsStore.getState().qaData
|
||||
const currentQaData = qaData.get(currentImg) ?? qaData.get("init") ?? {}
|
||||
const newQaData = structuredClone(currentQaData)
|
||||
const newQaData = safeClone(currentQaData)
|
||||
|
||||
const handleText = (v: string) => {
|
||||
// 提取文本内容
|
||||
@@ -370,9 +371,8 @@ const RightQAContent = forwardRef(
|
||||
size="compact-xs"
|
||||
onClick={() => {
|
||||
const finalData =
|
||||
structuredClone(currentQaData)
|
||||
const updateData =
|
||||
structuredClone(qaDataArr)
|
||||
safeClone(currentQaData)
|
||||
const updateData = safeClone(qaDataArr)
|
||||
updateData.splice(index, 1)
|
||||
finalData[qaCategory] = updateData
|
||||
qaData.set(activeImage, finalData)
|
||||
@@ -396,9 +396,8 @@ const RightQAContent = forwardRef(
|
||||
size="compact-xs"
|
||||
onClick={() => {
|
||||
const finalData =
|
||||
structuredClone(currentQaData)
|
||||
const updateData =
|
||||
structuredClone(qaDataArr)
|
||||
safeClone(currentQaData)
|
||||
const updateData = safeClone(qaDataArr)
|
||||
updateData[index] = {
|
||||
[question_name]: {
|
||||
...detail,
|
||||
@@ -599,8 +598,8 @@ const RightQAContent = forwardRef(
|
||||
}
|
||||
}
|
||||
|
||||
const finalData = structuredClone(currentQaData)
|
||||
const updateData = structuredClone(currentOperation)
|
||||
const finalData = safeClone(currentQaData)
|
||||
const updateData = safeClone(currentOperation)
|
||||
let obj = {
|
||||
value: formData.value ?? "<p></p>",
|
||||
id: formData.round_id,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Skeleton, Stack, Flex, Box, Text } from "@mantine/core"
|
||||
import { FolderPen, ImageDown, Trash2 } from "lucide-react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import { storage, useImagesStore } from "../store"
|
||||
import { safeClone } from "../utils/clone"
|
||||
|
||||
interface ComponentProps {
|
||||
open: boolean
|
||||
@@ -65,7 +66,7 @@ const TaskCacheModal = ({ open, handleClose, taskDetail }: ComponentProps) => {
|
||||
// 删除图片缓存
|
||||
if (data1 === "0.00 B") return
|
||||
const imgNames = taskDetail?.data_name.map((item) => item.name[0]) ?? []
|
||||
const imageData = structuredClone(useImagesStore.getState().images)
|
||||
const imageData = safeClone(useImagesStore.getState().images)
|
||||
imgNames.forEach((name) => {
|
||||
imageData.delete(name)
|
||||
})
|
||||
|
||||
@@ -93,6 +93,7 @@ import { useIntervalStore } from "../useTimerStore"
|
||||
import { useTopToolsStore } from "../useTopToolsStore"
|
||||
import { getSubAttrStatus } from "../util"
|
||||
import { labelTypeMap, TaskStatusEnum } from "../utils/constants"
|
||||
import { safeClone } from "../utils/clone"
|
||||
import { adjustAllPoints } from "../utils/paperjs"
|
||||
import BackConfirmModal from "./BackConfirmModal"
|
||||
import BackupModal from "./BackupModal"
|
||||
@@ -562,7 +563,7 @@ const TopTools = (
|
||||
}
|
||||
// 处理QA数据
|
||||
if (projectDetail?.label_type === 6) {
|
||||
const currentQaData = structuredClone(
|
||||
const currentQaData = safeClone(
|
||||
useDescToolsStore.getState().qaData.get(name) || {}
|
||||
)
|
||||
let other_desc: any = {}
|
||||
@@ -977,7 +978,7 @@ const TopTools = (
|
||||
useDescToolsStore.getState().setMetaData(meta)
|
||||
} else if (projectDetail?.label_type === 6) {
|
||||
const { text } = data
|
||||
const updateQaData = structuredClone(
|
||||
const updateQaData = safeClone(
|
||||
useDescToolsStore.getState().qaData
|
||||
)
|
||||
text.entries().forEach(([key, value]: any) => {
|
||||
@@ -1542,7 +1543,7 @@ const TopTools = (
|
||||
}}
|
||||
c={showTagsConfigs.includes(config) ? "blue" : undefined}
|
||||
onClick={() => {
|
||||
let arr = structuredClone(showTagsConfigs)
|
||||
let arr = safeClone(showTagsConfigs)
|
||||
const index = arr.findIndex((item) => item === config)
|
||||
if (index !== -1) {
|
||||
arr.splice(index, 1)
|
||||
|
||||
@@ -3,6 +3,7 @@ import superjson from "superjson"
|
||||
import { create } from "zustand"
|
||||
import { persist, PersistStorage, StorageValue } from "zustand/middleware"
|
||||
import { Comment } from "./api/label/typing"
|
||||
import { safeClone } from "./utils/clone"
|
||||
|
||||
type LabelData = Map<string, Map<string, [number, any[], any, any[]][]>>
|
||||
interface LabelState {
|
||||
@@ -145,56 +146,6 @@ const initialLabelState = {
|
||||
},
|
||||
}
|
||||
|
||||
const deepCloneFallback = <T>(value: T, cache = new WeakMap()): T => {
|
||||
if (value === null || typeof value !== "object") return value
|
||||
if (cache.has(value as object)) return cache.get(value as object)
|
||||
|
||||
if (value instanceof Date) return new Date(value.getTime()) as T
|
||||
if (value instanceof Map) {
|
||||
const clonedMap = new Map()
|
||||
cache.set(value as object, clonedMap)
|
||||
value.forEach((mapValue, mapKey) => {
|
||||
clonedMap.set(
|
||||
deepCloneFallback(mapKey, cache),
|
||||
deepCloneFallback(mapValue, cache)
|
||||
)
|
||||
})
|
||||
return clonedMap as T
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
const clonedSet = new Set()
|
||||
cache.set(value as object, clonedSet)
|
||||
value.forEach((setValue) => {
|
||||
clonedSet.add(deepCloneFallback(setValue, cache))
|
||||
})
|
||||
return clonedSet as T
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const clonedArr: any[] = []
|
||||
cache.set(value as object, clonedArr)
|
||||
value.forEach((item, index) => {
|
||||
clonedArr[index] = deepCloneFallback(item, cache)
|
||||
})
|
||||
return clonedArr as T
|
||||
}
|
||||
|
||||
const clonedObj: Record<string, any> = {}
|
||||
cache.set(value as object, clonedObj)
|
||||
Object.keys(value as object).forEach((key) => {
|
||||
clonedObj[key] = deepCloneFallback((value as any)[key], cache)
|
||||
})
|
||||
return clonedObj as T
|
||||
}
|
||||
|
||||
const safeClone = <T>(value: T): T => {
|
||||
try {
|
||||
return structuredClone(value)
|
||||
} catch (error) {
|
||||
console.warn("structuredClone failed, fallback to deep clone", error)
|
||||
return deepCloneFallback(value)
|
||||
}
|
||||
}
|
||||
|
||||
export const initialDetail = {
|
||||
comment: [],
|
||||
create_timestamp: 0,
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useOtherToolsStore } from "./useOtherToolsStore"
|
||||
import { usePaperSupportStore } from "./usePaperSupportStore"
|
||||
import { useRightToolsStore } from "./useRightToolsStore"
|
||||
import { useTopToolsStore } from "./useTopToolsStore"
|
||||
import { safeClone } from "./utils/clone"
|
||||
|
||||
interface PaperState {
|
||||
paperScope: paper.PaperScope | null
|
||||
@@ -239,7 +240,7 @@ const handleDelete = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
const currentLabelData = structuredClone(useLabelStore.getState().label)
|
||||
const currentLabelData = safeClone(useLabelStore.getState().label)
|
||||
operationIds.forEach((operationId, index) => {
|
||||
let result =
|
||||
currentLabelData
|
||||
@@ -1808,7 +1809,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
!child.data ||
|
||||
(child.data && !Object.keys(child.data).length)
|
||||
)
|
||||
child.data = structuredClone(newDrawPath?.data || {})
|
||||
child.data = safeClone(newDrawPath?.data || {})
|
||||
})
|
||||
oldPolygon.remove()
|
||||
oldPolygon = null
|
||||
@@ -1886,7 +1887,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
// if (!newDrawPath?.clockwise) newDrawPath?.reverse();
|
||||
if (newDrawPath instanceof paper.CompoundPath) {
|
||||
;(newDrawPath.children as paper.Path[]).forEach((child) => {
|
||||
child.data = structuredClone(
|
||||
child.data = safeClone(
|
||||
Object.assign({}, newDrawPath?.data || {}, {
|
||||
isHollowPolygon: !child.clockwise,
|
||||
})
|
||||
@@ -1894,7 +1895,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
})
|
||||
if (oldParent instanceof paper.CompoundPath) {
|
||||
;(oldParent.children as paper.Path[]).forEach((child) => {
|
||||
child.data = structuredClone(
|
||||
child.data = safeClone(
|
||||
Object.assign({}, newDrawPath?.data || {}, {
|
||||
isHollowPolygon: !child.clockwise,
|
||||
})
|
||||
@@ -1946,7 +1947,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
// if (!newDrawPath?.clockwise) newDrawPath?.reverse();
|
||||
if (newDrawPath instanceof paper.CompoundPath)
|
||||
(newDrawPath.children as paper.Path[]).forEach((child) => {
|
||||
child.data = structuredClone(newDrawPath?.data || {})
|
||||
child.data = safeClone(newDrawPath?.data || {})
|
||||
})
|
||||
oldPolygon.remove()
|
||||
oldPolygon = null
|
||||
@@ -2153,7 +2154,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
return
|
||||
}
|
||||
// hollowPath.path.clockwise = false;
|
||||
hollowPath.path.data = structuredClone(
|
||||
hollowPath.path.data = safeClone(
|
||||
Object.assign({}, hollowPath.path?.data || {}, {
|
||||
isHollowPolygon: true,
|
||||
})
|
||||
@@ -2168,7 +2169,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
// if (finnalPath instanceof paper.CompoundPath) {
|
||||
// (finnalPath.children as paper.Path[]).forEach((child) => {
|
||||
// // child.clockwise = false;
|
||||
// child.data = structuredClone(
|
||||
// child.data = safeClone(
|
||||
// Object.assign({}, oldPolygon?.data || {}, {
|
||||
// isHollowPolygon: true,
|
||||
// })
|
||||
@@ -2176,7 +2177,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
// });
|
||||
// } else if (finnalPath instanceof paper.Path) {
|
||||
// // finnalPath.clockwise = false;
|
||||
// finnalPath.data = structuredClone(
|
||||
// finnalPath.data = safeClone(
|
||||
// Object.assign({}, oldPolygon?.data || {}, {
|
||||
// isHollowPolygon: true,
|
||||
// })
|
||||
@@ -2656,7 +2657,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
if (polygon instanceof paper.CompoundPath)
|
||||
(polygon.children as paper.Path[]).forEach((child) => {
|
||||
if (!child.data || (child.data && !Object.keys(child.data).length))
|
||||
child.data = structuredClone(
|
||||
child.data = safeClone(
|
||||
Object.assign(
|
||||
{ isHollowPolygon: !child.clockwise },
|
||||
polygon?.data || {}
|
||||
@@ -2674,7 +2675,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
polygon = oldPolygon?.subtract(eachPath) as any
|
||||
if (polygon instanceof paper.CompoundPath)
|
||||
(polygon.children as paper.Path[]).forEach((child) => {
|
||||
child.data = structuredClone(
|
||||
child.data = safeClone(
|
||||
Object.assign(
|
||||
{ isHollowPolygon: !child.clockwise },
|
||||
polygon?.data || {}
|
||||
@@ -2716,7 +2717,7 @@ export const usePaperStore = create<PaperState>((set) => ({
|
||||
polygon = oldPolygon.unite(eachPath) as any
|
||||
if (polygon instanceof paper.CompoundPath)
|
||||
(polygon.children as paper.Path[]).forEach((child) => {
|
||||
child.data = structuredClone(polygon?.data || {})
|
||||
child.data = safeClone(polygon?.data || {})
|
||||
})
|
||||
oldPolygon?.remove()
|
||||
oldPolygon = null
|
||||
|
||||
@@ -2,6 +2,7 @@ import { create } from "zustand"
|
||||
import { persist } from "zustand/middleware"
|
||||
import { storage, useLabelStore } from "./store"
|
||||
import { usePaperStore } from "./usePaperStore"
|
||||
import { safeClone } from "./utils/clone"
|
||||
|
||||
interface RightToolsState {
|
||||
pathIds: number[]
|
||||
@@ -94,7 +95,7 @@ export const useRightToolsStore = create(
|
||||
}
|
||||
state.pathGroupMap.get(imageId)?.set(groupId, pathIds)
|
||||
// update LabelData
|
||||
const data = structuredClone(useLabelStore.getState().label)
|
||||
const data = safeClone(useLabelStore.getState().label)
|
||||
// handle delete
|
||||
if (deleteIds.length) {
|
||||
let operationIds: any[] = []
|
||||
|
||||
49
components/label/utils/clone.ts
Normal file
49
components/label/utils/clone.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
const deepCloneFallback = <T>(value: T, cache = new WeakMap()): T => {
|
||||
if (value === null || typeof value !== "object") return value
|
||||
if (cache.has(value as object)) return cache.get(value as object)
|
||||
|
||||
if (value instanceof Date) return new Date(value.getTime()) as T
|
||||
if (value instanceof Map) {
|
||||
const clonedMap = new Map()
|
||||
cache.set(value as object, clonedMap)
|
||||
value.forEach((mapValue, mapKey) => {
|
||||
clonedMap.set(
|
||||
deepCloneFallback(mapKey, cache),
|
||||
deepCloneFallback(mapValue, cache)
|
||||
)
|
||||
})
|
||||
return clonedMap as T
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
const clonedSet = new Set()
|
||||
cache.set(value as object, clonedSet)
|
||||
value.forEach((setValue) => {
|
||||
clonedSet.add(deepCloneFallback(setValue, cache))
|
||||
})
|
||||
return clonedSet as T
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const clonedArr: any[] = []
|
||||
cache.set(value as object, clonedArr)
|
||||
value.forEach((item, index) => {
|
||||
clonedArr[index] = deepCloneFallback(item, cache)
|
||||
})
|
||||
return clonedArr as T
|
||||
}
|
||||
|
||||
const clonedObj: Record<string, any> = {}
|
||||
cache.set(value as object, clonedObj)
|
||||
Object.keys(value as object).forEach((key) => {
|
||||
clonedObj[key] = deepCloneFallback((value as any)[key], cache)
|
||||
})
|
||||
return clonedObj as T
|
||||
}
|
||||
|
||||
export const safeClone = <T>(value: T): T => {
|
||||
try {
|
||||
return structuredClone(value)
|
||||
} catch (error) {
|
||||
console.warn("structuredClone failed, fallback to deep clone", error)
|
||||
return deepCloneFallback(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user