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