From a2efbda65ee30407176f8a5015019f2c5ec4fa4b Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Thu, 14 Aug 2025 16:37:31 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E9=87=8D=E5=A4=8D=E5=9B=BE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=9A1=EF=BC=8C=E8=A1=A8=E6=A0=BC=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BC=98=E5=8C=96=EF=BC=9B2=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=B9=B3=E5=9D=87=E8=80=97=E6=97=B6=E5=92=8C=E6=80=BB?= =?UTF-8?q?=E8=80=97=E6=97=B6=E5=AF=BC=E5=85=A5=E4=B8=8E=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ModelStructure/Control/FsgControl.tsx | 2 +- .../app/src/ModelStructure/Fsg/Filter.tsx | 61 ++++--- .../app/src/ModelStructure/Fsg/index.tsx | 152 +++++++++++++++--- .../ModelVis/app/src/features/Project.tsx | 90 ++++++----- .../app/src/hooks/useNewPathForLayout.ts | 7 +- .../ModelVis/app/src/libs/file-dialog.ts | 8 +- .../ModelVis/app/src/locales/en.json | 11 +- .../ModelVis/app/src/locales/zh-CN.json | 11 +- .../ModelVis/app/src/types/model.d.ts | 11 ++ .../ModelVis/app/src/ui/Resizer.tsx | 62 +++++++ 10 files changed, 318 insertions(+), 97 deletions(-) create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/app/src/ui/Resizer.tsx diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/FsgControl.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/FsgControl.tsx index 8bb21c1b7..31a1d3475 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/FsgControl.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/FsgControl.tsx @@ -30,7 +30,7 @@ const FsgControl = () => { setVisible(!visible) } - return - + {t('fsg.minRepeatTimes')} + handleInput(e, 'repeat')} + /> + {t('fsg.nodeInFsg')} + handleInput(e, 'min')} + /> + ~ + handleInput(e, 'max')} + /> + + + } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index 5982afb40..ae7e6bb1a 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -18,23 +18,34 @@ import { useAtomValue } from 'jotai' import { joinCls } from 'libs' import Filter from './Filter' import { - loadingAtom, modelPathAtom, fsgPanelVisibleAtom, fsgVisibleAtom, themeAtom, currentGraphAtom } from '../../stores' -import { useAtom, useSetAtom } from 'jotai/index' +import { useAtom } from 'jotai/index' import { invoke } from '@tauri-apps/api/core' import type { ColumnsType } from 'antd/es/table' import { ConfigProvider, Table, theme } from 'antd' -import { useEffect, useState } from 'react' +import { DragOutlined, PushpinOutlined } from '@ant-design/icons'; +import { useEffect, useRef, useState } from 'react' import { workerInitFsgs, workerToggleFsgs } from '../../worker-apis' +import { Resizer, type ResizerType } from 'ui/Resizer' /** * The current algorithm is flawed, results returned are duplicated, * and there are differences only in order * @param graphs Array of NodeId array */ +let opDuration: OpDuration = {} +let fsgDataCach: FsgRet[] = [] + +const getOpStructAvgTime = (opStruct: string, type: TimeType): number => { + const opList = opStruct.split(',') + let avgTime = 0 + opList.forEach(op => (avgTime += opDuration[op]?.[type] ?? 0)) + return avgTime +} + const dedup = (graphs: FsgRet[]): FsgTableRow[] => { const seen = new Set() return graphs.map((item, index) => { @@ -46,13 +57,18 @@ const dedup = (graphs: FsgRet[]): FsgTableRow[] => { return seen.has(key) ? false : seen.add(key) && true }) + const meanDuration = getOpStructAvgTime(item.optype_struct, 'avg_duration_us') + const meanMte2Time = getOpStructAvgTime(item.optype_struct, 'avg_mte2_time_us') + return { - key: `${item.optype_struct}_${index}`, + key: `${item.optype_struct}_${index}_${meanDuration}_${meanMte2Time}`, fsg: item.optype_struct, count: nodes.length, nodeCount: item.instances[0]?.node_num ?? 0, - meanDuration: 0, - totalDuration: 0, + meanDuration, + totalDuration: meanDuration * nodes.length, + meanMte2Time, + totalMte2Time: meanMte2Time * nodes.length, nodes } }).filter(item => item.count > 0 && item.nodeCount > 0) @@ -68,38 +84,65 @@ const getColumns = (t: I18nFunc): ColumnsType => { { dataIndex: 'fsg', title: t('fsg.fsg'), - sorter: (a: FsgTableRow, b: FsgTableRow): number => a.fsg.localeCompare(b.fsg), - width: '50%', - ellipsis: true + width: 200, + ellipsis: true, + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.fsg.localeCompare(b.fsg) }, { dataIndex: 'count', title: t('fsg.count'), + width: 90, + ellipsis: true, sorter: (a: FsgTableRow, b: FsgTableRow): number => a.count - b.count }, { dataIndex: 'nodeCount', title: t('fsg.nodeCount'), + width: 130, + ellipsis: true, sorter: (a: FsgTableRow, b: FsgTableRow): number => a.nodeCount - b.nodeCount }, { dataIndex: 'meanDuration', title: t('fsg.meanDuration'), + width: 155, + ellipsis: true, sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanDuration - b.meanDuration }, { dataIndex: 'totalDuration', title: t('fsg.totalDuration'), + width: 150, + ellipsis: true, sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalDuration - b.totalDuration + }, + { + dataIndex: 'meanMte2Time', + title: t('fsg.meanMte2Time'), + width: 165, + ellipsis: true, + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanMte2Time - b.meanMte2Time + }, + { + dataIndex: 'totalMte2Time', + title: t('fsg.totalMte2Time'), + width: 160, + ellipsis: true, + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalMte2Time - b.totalMte2Time } ] } const Fsg = () => { - const visible = useAtomValue(fsgPanelVisibleAtom) + const [visible, setVisible] = useAtom(fsgPanelVisibleAtom) const t = useI18n() - const setLoading = useSetAtom(loadingAtom) + const containerRef = useRef(null) + const [loading, setLoading] = useState(false) + const [width, setWidth] = useState(690) + const [top, setTop] = useState(5) + const [left, setLeft] = useState(10) + const [isLock, setIsLock] = useState(false) const [fsgVis, setFsgVis] = useAtom(fsgVisibleAtom) const path = useAtomValue(modelPathAtom) const [fsgData, setFsgData] = useState([]) @@ -118,6 +161,18 @@ const Fsg = () => { const fsgs = dedup(sortedFsgs(res)) setFsgData(fsgs) setLoading(false) + fsgDataCach = res + } + const exportOpDuration = async (path: string): Promise => { + setLoading(true) + try { + const res = await invoke('analyze_duration', { path }) + + opDuration = res + } catch { } + const fsgs = dedup(sortedFsgs(fsgDataCach)) + setFsgData(fsgs) + setLoading(false) } const toggleFsg = (): void => { @@ -139,20 +194,75 @@ const Fsg = () => { } } + const changeWidth: ResizerType['callback'] = (value, _) => { + if (containerRef.current === null) { + return + } + setWidth(containerRef.current.offsetWidth + value) + } + + const moveContainer: ResizerType['callback'] = (moveX, moveY) => { + setLeft(oLeft => { + const newLeft = oLeft + moveX + return newLeft > 0 ? newLeft : 0 + }) + setTop(oTop => { + const newTop = oTop + moveY + return newTop > 0 ? newTop : 0 + }) + } + + const mouseDown = (e: MouseEvent) => { + if (e === null) return + const isInside = containerRef.current?.contains(e.target as HTMLElement); + const isFsgControlBtn = document.getElementById("fsgControlBtn")?.contains(e.target as HTMLElement) + if (isFsgControlBtn) { + return + } + if (!isInside && !isLock) { + setVisible(false) + } + } + + useEffect(() => { + document.addEventListener('mousedown', mouseDown); + return () => { + document.removeEventListener('mousedown', mouseDown) + } + }, [isLock]) + useEffect(() => { setFsgData([]); + setLoading(false); setSelectedRow(undefined); - }, [path]); + opDuration = {} + fsgDataCach = [] + }, [path]) return
- + +
+
+ + +
+ setIsLock(oVal => !oVal)} + /> +
+ { > record.key === selectedRow?.key ? 'bg-blue-300' : ''} pagination={{ className: '!my-2', pageSizeOptions: ['10', '20', '50', '100'], total: fsgData.length, - showTotal: (total: number): string => t('fsg.paginationTotal', {total: total}), + showTotal: (total: number): string => t('fsg.paginationTotal', { total: total }), showSizeChanger: true, showQuickJumper: true }} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx index d1c81cc53..5204aed18 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx @@ -25,7 +25,7 @@ import TrashIcon from "icons/trash.svg?react" import XIcon from "icons/x.svg?react" import { useAtomValue, } from "jotai" import { joinCls, openDialog } from "libs" -import { modelPathAtom, recentProjCache, } from "stores" +import { modelPathAtom, recentProjCache } from "stores" const Project = () => { const { visible, open, close } = useVisible() @@ -41,15 +41,13 @@ const Project = () => { const handleNewProject = async () => { const path = await openDialog() - - await layoutNewPath(path) - close() + await layoutNewPath(path) } const toggle = async (path: string) => { - await layoutNewPath(path) close() + await layoutNewPath(path) } return
@@ -65,40 +63,40 @@ const Project = () => { {visible &&
+ + + - - - -
- -

{t("project.recent")}

- {recentProjCache.items.map(p => ( - - ))} -
+ + {t("project.close")} + + +
+ +

{t("project.recent")}

+ {recentProjCache.items.map(p => ( + + ))} +
}
} @@ -109,24 +107,34 @@ type ProjectLineProps = { } const RecentProj = ({ path, toggle }: ProjectLineProps) => { - const handleNew = () => toggle(path) + const cleanup = useCleanup() + const handleNew = () => toggle(path) + const curPath = useAtomValue(modelPathAtom) + const deletePro = () => { + recentProjCache.remove(path) + if (recentProjCache.items.length === 0) { + cleanup(); + } else if (path === curPath) { + toggle(recentProjCache.items[0]) + } + } return
- +
} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts index 6f92ee6e4..94de122bd 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts @@ -22,7 +22,8 @@ import { modelPathAtom, recentProjCache, fsgVisibleAtom, - translateAtom, useSelectionHistory, useZoom, currentGraphAtom, allGraphAtom + translateAtom, useSelectionHistory, useZoom, currentGraphAtom, allGraphAtom, + fsgPanelVisibleAtom } from "stores" type LayoutNewPath = (path: string | null) => Promise @@ -33,6 +34,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { const setCurrentGraphAtom = useSetAtom(currentGraphAtom) const setAllGraphAtom = useSetAtom(allGraphAtom) const setDynamicVisible = useSetAtom(dynamicVisibleAtom) + const setFsgPanelVisible = useSetAtom(fsgPanelVisibleAtom) const setFsgsVisible = useSetAtom(fsgVisibleAtom) const [translate, setTranslate] = useAtom(translateAtom) const [zoom, , resetZoom] = useZoom() @@ -41,6 +43,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { return async (path: string | null) => { if (!path || path === modelPath) return + setFsgPanelVisible(false) setModelPath(path) const start = performance.now() @@ -54,7 +57,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { }) if (res) { - history.clear() + history.clear() setCurrentGraphAtom(res) setAllGraphAtom(res) setDynamicVisible(false) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/libs/file-dialog.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/libs/file-dialog.ts index d676e1eb5..52b4e34fd 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/libs/file-dialog.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/libs/file-dialog.ts @@ -19,13 +19,17 @@ const EntryFilter: Record = { pb: { name: "pb format model", extensions: ["onnx", "mindir", "geir", "pbtxt"] + }, + csv: { + name: "operator csv", + extensions: ["csv"] } } -export const openDialog = () => +export const openDialog = (key: string = "pb") => open({ multiple: false, directory: false, canCreateDirectories: true, - filters: [EntryFilter.pb] + filters: [EntryFilter[key]] }) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/en.json b/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/en.json index 8d6692997..7fc716f7b 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/en.json +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/en.json @@ -30,8 +30,8 @@ "recent": "Recent Projects" }, "fsg": { - "minRepeatTimes": "Minimum Repetition: ", - "nodeInFsg": "Nodes Number: ", + "minRepeatTimes": "Minimum Repetition:", + "nodeInFsg": "Nodes Number:", "query": "Query", "fsg": "Structure", "count": "Count", @@ -41,6 +41,9 @@ "paginationTotal": "Total {total} items", "displayFsgs": "Display", "hideFsgs": "Hide", - "invalidQueryWarning": "Invalid Condition: The number of nodes on the left side cannot be greater than that on the right side" + "invalidQueryWarning": "Invalid Condition: The number of nodes on the left side cannot be greater than that on the right side", + "meanMte2Time": "Mean Mte2 Time(us)", + "totalMte2Time": "Total Mte2 Time(us)", + "importCSV": "Import CSV" } -} +} \ No newline at end of file diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/zh-CN.json b/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/zh-CN.json index a27c52df1..28a02f565 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/zh-CN.json +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/locales/zh-CN.json @@ -30,8 +30,8 @@ "recent": "最近的项目" }, "fsg": { - "minRepeatTimes": "至少重复:", - "nodeInFsg": "结构中节点数量", + "minRepeatTimes": "至少重复:", + "nodeInFsg": "结构中节点数量:", "query": "查询", "fsg": "结构", "count": "出现次数", @@ -41,6 +41,9 @@ "paginationTotal": "总共{total}条", "displayFsgs": "标记重复结构", "hideFsgs": "隐藏重复结构", - "invalidQueryWarning": "无效查询条件:结构中节点数量范围左侧不能大于右侧" + "invalidQueryWarning": "无效查询条件:结构中节点数量范围左侧不能大于右侧", + "meanMte2Time": "Mte2平均时间(us)", + "totalMte2Time": "Mte2总时间(us)", + "importCSV": "导入CSV" } -} +} \ No newline at end of file diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/types/model.d.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/types/model.d.ts index 0f4f27d3d..80b1fb555 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/types/model.d.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/types/model.d.ts @@ -126,5 +126,16 @@ type FsgTableRow = { nodeCount: number meanDuration: number totalDuration: number + meanMte2Time: number + totalMte2Time: number nodes: string[][] } + +type TimeType = 'avg_duration_us' | 'avg_mte2_time_us' +type OpDuration = { + [key: string]: { + op_type: string + avg_duration_us: number + avg_mte2_time_us: number + } +} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ui/Resizer.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ui/Resizer.tsx new file mode 100644 index 000000000..c13c557b7 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ui/Resizer.tsx @@ -0,0 +1,62 @@ +// Copyright (c) 2025, Huawei Technologies Co., Ltd. +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { useRef } from 'react' + +export type ResizerType = { + style?: object + callback?: (moveWidthLength: number, moveHeightLength: number) => void +} + +export const Resizer = ({ style, callback }: ResizerType): JSX.Element => { + const resizeRef = useRef(null) + let isDrag = false + let offsetX: number + let offsetY: number + + const handleMouseDown = (event: any) => { + event.preventDefault() + isDrag = true + offsetX = event.screenX + offsetY = event.screenY + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } + + const handleMouseMove = (event: MouseEvent) => { + event.preventDefault(); + if (isDrag) { + const moveWidthLength = event.screenX - offsetX + const moveHeightLength = event.screenY - offsetY + offsetX = event.screenX + offsetY = event.screenY + if (callback) { + callback(moveWidthLength, moveHeightLength); + } + } + } + + const handleMouseUp = (event: MouseEvent) => { + if (event !== undefined) { + event.preventDefault(); + } + isDrag = false; + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + return
; +}; -- Gitee From 44703a6ab4a65ffa7b85c2c288a8befb49a70924 Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Thu, 14 Aug 2025 17:37:49 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E9=99=90=E5=88=B6=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=9A=84=E5=8F=B3=E4=BE=A7=E5=92=8C=E4=B8=8B=E4=BE=A7=E8=8C=83?= =?UTF-8?q?=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelVis/app/src/ModelStructure/Fsg/index.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index ae7e6bb1a..9e5e6f89a 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -204,10 +204,18 @@ const Fsg = () => { const moveContainer: ResizerType['callback'] = (moveX, moveY) => { setLeft(oLeft => { const newLeft = oLeft + moveX + if (newLeft > window.innerWidth - 30) { + return window.innerWidth - 30 + } return newLeft > 0 ? newLeft : 0 }) setTop(oTop => { const newTop = oTop + moveY + console.log(newTop, window.innerHeight); + + if (newTop > window.innerHeight - 80) { + return window.innerHeight - 80 + } return newTop > 0 ? newTop : 0 }) } -- Gitee From a3189e4d5e2118fc6da9d184398ad6711f3ed403 Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Fri, 15 Aug 2025 10:49:39 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=BA0=E6=97=B6?= =?UTF-8?q?=E7=BD=AE=E4=B8=BANA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelVis/app/src/ModelStructure/Fsg/index.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index 9e5e6f89a..1fdb4485f 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -107,28 +107,32 @@ const getColumns = (t: I18nFunc): ColumnsType => { title: t('fsg.meanDuration'), width: 155, ellipsis: true, - sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanDuration - b.meanDuration + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanDuration - b.meanDuration, + render: (value) => (value > 0 ? value : 'NA') }, { dataIndex: 'totalDuration', title: t('fsg.totalDuration'), width: 150, ellipsis: true, - sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalDuration - b.totalDuration + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalDuration - b.totalDuration, + render: (value) => (value > 0 ? value : 'NA') }, { dataIndex: 'meanMte2Time', title: t('fsg.meanMte2Time'), width: 165, ellipsis: true, - sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanMte2Time - b.meanMte2Time + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.meanMte2Time - b.meanMte2Time, + render: (value) => (value > 0 ? value : 'NA') }, { dataIndex: 'totalMte2Time', title: t('fsg.totalMte2Time'), width: 160, ellipsis: true, - sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalMte2Time - b.totalMte2Time + sorter: (a: FsgTableRow, b: FsgTableRow): number => a.totalMte2Time - b.totalMte2Time, + render: (value) => (value > 0 ? value : 'NA') } ] } @@ -212,7 +216,7 @@ const Fsg = () => { setTop(oTop => { const newTop = oTop + moveY console.log(newTop, window.innerHeight); - + if (newTop > window.innerHeight - 80) { return window.innerHeight - 80 } -- Gitee From 0fc33c18adb159c3acf2718427a3c6cce706388d Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Fri, 15 Aug 2025 11:27:58 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/ModelStructure/Fsg/index.tsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index 1fdb4485f..9c557e156 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -25,8 +25,8 @@ import { import { useAtom } from 'jotai/index' import { invoke } from '@tauri-apps/api/core' import type { ColumnsType } from 'antd/es/table' -import { ConfigProvider, Table, theme } from 'antd' -import { DragOutlined, PushpinOutlined } from '@ant-design/icons'; +import { ConfigProvider, message, Table, theme } from 'antd' +import { PushpinOutlined } from '@ant-design/icons'; import { useEffect, useRef, useState } from 'react' import { workerInitFsgs, workerToggleFsgs } from '../../worker-apis' import { Resizer, type ResizerType } from 'ui/Resizer' @@ -173,7 +173,9 @@ const Fsg = () => { const res = await invoke('analyze_duration', { path }) opDuration = res - } catch { } + } catch (err) { + message.error(typeof err === 'string' ? err : JSON.stringify(err)) + } const fsgs = dedup(sortedFsgs(fsgDataCach)) setFsgData(fsgs) setLoading(false) @@ -260,19 +262,18 @@ const Fsg = () => { ref={containerRef} > -
-
- - -
+
setIsLock(oVal => !oVal)} /> +
+ +
Date: Fri, 15 Aug 2025 14:54:56 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/ModelStructure/Control/index.tsx | 2 +- .../app/src/ModelStructure/Dynamic/index.tsx | 2 +- .../ModelVis/app/src/ModelStructure/Fsg/Filter.tsx | 2 +- .../ModelVis/app/src/ModelStructure/Fsg/index.tsx | 13 ++++++++----- .../app/src/ModelStructure/Properties/index.tsx | 2 +- .../ModelVis/app/src/ModelStructure/index.tsx | 2 +- .../ModelVis/app/src/bootstrap.ts | 7 ++++++- .../ModelVis/app/src/features/Project.tsx | 2 +- .../app/src/features/Search/SearchModal.tsx | 4 ++-- .../ModelVis/app/src/features/Search/index.tsx | 2 +- .../ModelVis/app/src/icons/pushpin.svg | 5 +++++ 11 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/app/src/icons/pushpin.svg diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/index.tsx index c887d4a83..07061dbcf 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Control/index.tsx @@ -24,7 +24,7 @@ import { TranslateControl, ZoomControl } from "./TransformControl" const Control = () =>
{ return

{t("dynamicNodes")}

diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/Filter.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/Filter.tsx index 0a9121bb5..c943d2031 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/Filter.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/Filter.tsx @@ -23,7 +23,7 @@ import { Button } from 'antd' const commonInputNumberClass: string = joinCls( 'h-8 w-12 pr-0.5 pl-1 text-sm mx-1', - 'select-none rounded-xs bg-white outline-none ring-1 ring-inset', + 'rounded-xs bg-white outline-none ring-1 ring-inset', 'ring-violet-300 transition-color duration-150 dark:ring-violet-50', 'focus:bg-white focus:text-gray-600 dark:bg-dark-medium', 'dark:focus:bg-dark-primary dark:focus:text-white' diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index 9c557e156..e4c75551f 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -26,10 +26,10 @@ import { useAtom } from 'jotai/index' import { invoke } from '@tauri-apps/api/core' import type { ColumnsType } from 'antd/es/table' import { ConfigProvider, message, Table, theme } from 'antd' -import { PushpinOutlined } from '@ant-design/icons'; import { useEffect, useRef, useState } from 'react' import { workerInitFsgs, workerToggleFsgs } from '../../worker-apis' import { Resizer, type ResizerType } from 'ui/Resizer' +import Pushpin from "icons/pushpin.svg?react" /** * The current algorithm is flawed, results returned are duplicated, @@ -174,7 +174,10 @@ const Fsg = () => { opDuration = res } catch (err) { - message.error(typeof err === 'string' ? err : JSON.stringify(err)) + message.error({ + content: typeof err === 'string' ? err : JSON.stringify(err), + className: 'dark:text-white dark:[&_div]:!bg-dark-light', + }) } const fsgs = dedup(sortedFsgs(fsgDataCach)) setFsgData(fsgs) @@ -255,7 +258,7 @@ const Fsg = () => { return
{ >
- setIsLock(oVal => !oVal)} /> diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Properties/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Properties/index.tsx index d322f8132..a9fc53e65 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Properties/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Properties/index.tsx @@ -46,7 +46,7 @@ const Properties = () => {
diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx index 8fec5c4df..789ec82ad 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx @@ -189,7 +189,7 @@ const GraphPath = () => { return
diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts index cde8b2033..5c71e0473 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts @@ -29,7 +29,12 @@ document.addEventListener( { passive: false } ) document.addEventListener("contextmenu", e => e.preventDefault(), { passive: false }) -document.addEventListener("keydown", e => (e.ctrlKey || e.metaKey) && e.preventDefault(), { +document.addEventListener("keydown", e => { + if ((e.ctrlKey || e.metaKey) && ["c", "v"].includes(e.key.toLocaleLowerCase())) { + return + } + (e.ctrlKey || e.metaKey) && e.preventDefault() +}, { passive: false }) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx index 5204aed18..c7a4dc3ea 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx @@ -50,7 +50,7 @@ const Project = () => { await layoutNewPath(path) } - return
+ return
+ diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx index 442e32694..0b237abe2 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/Fsg/index.tsx @@ -158,14 +158,21 @@ const Fsg = () => { const queryFsg = async (repeat: number, min: number, max: number) => { setLoading(true) - const res = await invoke( - 'mine_fsg', - { path, minSup: repeat, min, max, name: currentGraph.name } - ) - const fsgs = dedup(sortedFsgs(res)) - setFsgData(fsgs) + try { + const res = await invoke( + 'mine_fsg', + { path, minSup: repeat, min, max, name: currentGraph.name } + ) + const fsgs = dedup(sortedFsgs(res)) + setFsgData(fsgs) + fsgDataCach = res + } catch (err) { + message.error({ + content: typeof err === 'string' ? err : JSON.stringify(err), + className: 'dark:text-white dark:[&_div]:!bg-dark-light', + }) + } setLoading(false) - fsgDataCach = res } const exportOpDuration = async (path: string): Promise => { setLoading(true) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts index 94de122bd..95a85ddc5 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts @@ -57,7 +57,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { }) if (res) { - history.clear() + history.clear() setCurrentGraphAtom(res) setAllGraphAtom(res) setDynamicVisible(false) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/HistorySelection.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/HistorySelection.ts index ed2412bb8..2419dd43b 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/HistorySelection.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/HistorySelection.ts @@ -42,8 +42,12 @@ export const useSelectionHistory = () => { } const clear = () => { - setHistory([]) - setIndex(-1) + if (history.length > 0) { + setHistory([]) + } + if (index > -1) { + setIndex(-1) + } } const back = () => { diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/useWorkerMessage.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/useWorkerMessage.ts index e050f658d..e2e046477 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/useWorkerMessage.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/useWorkerMessage.ts @@ -21,8 +21,8 @@ import { } from "./stores" import WebWorker from "./worker" import { getSubgraph } from "./libs"; -import { useAtom } from "jotai/index"; import { listen } from "@tauri-apps/api/event"; +import { useEffect } from "react"; const PARSE_GRAPH_EVENT = "parse_graph_success" @@ -31,49 +31,51 @@ const useWorkerMessage = () => { const setDynamicNodes = useSetAtom(dynamicNodesAtom) const allGraphs = useAtomValue(allGraphAtom) const setCurrentGraph = useSetAtom(currentGraphAtom) - const [translate, setTranslate] = useAtom(translateAtom) - const [subgraphs, setSubGraphs] = useAtom(subgraphesAtom) + const setTranslate = useSetAtom(translateAtom) + const setSubGraphs = useSetAtom(subgraphesAtom) const { update, clear } = useSelectionHistory() - WebWorker.onmessage = ({ data: payload }) => { - switch (payload.type) { - case "search/ret": - setSearchResult(payload.nodes) - break + useEffect(() => { + WebWorker.onmessage = ({ data: payload }) => { + switch (payload.type) { + case "search/ret": + setSearchResult(payload.nodes) + break - case "hit-test/ret": { - const ret = payload?.data - if (ret?.id) { - const currentGraph = getSubgraph(allGraphs, ret.id) - if (currentGraph) { - setCurrentGraph(currentGraph) - if (translate.x !== 0 || translate.y !== 0) { + case "hit-test/ret": { + const ret = payload?.data + if (ret?.id) { + const currentGraph = getSubgraph(allGraphs, ret.id) + if (currentGraph) { + setCurrentGraph(currentGraph) setTranslate({ x: 0, y: 0 }) + } else { + update(ret.id) } - } else { - update(ret.id) } - } else if (ret?.source) update({ source: ret?.source, target: ret?.target }) else clear() - break - } + break + } - case "dynamic-nodes": - setDynamicNodes(payload.dynamicNodes) - break + case "dynamic-nodes": + setDynamicNodes(payload.dynamicNodes) + break + } } - } - listen(PARSE_GRAPH_EVENT, (event: any) => { - const { model } = event.payload - if (model?.name) { - subgraphs[model.name] = event.payload - setSubGraphs({ ...subgraphs }) - } - }) + listen(PARSE_GRAPH_EVENT, (event: any) => { + const { model } = event.payload + if (model?.name) { + setSubGraphs((oVal) => { + oVal[model.name] = event.payload + return { ...oVal } + }) + } + }) + }, []) } export default useWorkerMessage -- Gitee From 6ff9450f6a704fa576d156cc42cac32c2709c990 Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Sat, 16 Aug 2025 18:35:20 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelVis/app/src/FileUpload.tsx | 31 +++++--- .../ModelVis/app/src/bootstrap.ts | 6 -- .../ModelVis/app/src/features/Project.tsx | 16 +++-- .../app/src/hooks/useNewPathForLayout.ts | 5 +- .../ModelVis/app/src/stores/graph.ts | 1 - .../app/src/stores/useRecentProjectStorage.ts | 71 +++++++++++++++++++ 6 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/useRecentProjectStorage.ts diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx index 748ae3e11..dc8cd7f2c 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx @@ -15,25 +15,36 @@ import { useNewPathForLayout } from "hooks" import { openDialog } from "./libs" +import { useRecentProjectStorage } from "stores/useRecentProjectStorage"; +import { RecentProj } from "features/Project"; const FileUpload = () => { + const { recentProjectList } = useRecentProjectStorage(); const layoutNewPath = useNewPathForLayout() const handleUpload = async () => { const path = await openDialog() await layoutNewPath(path) } + const toggle = async (path: string) => { + await layoutNewPath(path) + } - return
- -
+ return <> +
+ +
+ {recentProjectList.map(p => ( + + ))} + } export default FileUpload diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts index 5c71e0473..c4954fbed 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/bootstrap.ts @@ -14,14 +14,8 @@ // limitations under the License. import { LogicalSize } from "@tauri-apps/api/dpi" -import { once } from "@tauri-apps/api/event" import { currentMonitor, type Monitor } from "@tauri-apps/api/window" import NativeWindow from "./native" -import { recentProjCache } from "./stores" - -await once("tauri://close-requested", () => { - localStorage.setItem("recentProj", JSON.stringify(recentProjCache.items)) -}) document.addEventListener( "wheel", diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx index c7a4dc3ea..a3e1d735b 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx @@ -25,9 +25,12 @@ import TrashIcon from "icons/trash.svg?react" import XIcon from "icons/x.svg?react" import { useAtomValue, } from "jotai" import { joinCls, openDialog } from "libs" -import { modelPathAtom, recentProjCache } from "stores" +import { useEffect } from "react" +import { modelPathAtom } from "stores" +import { useRecentProjectStorage } from "stores/useRecentProjectStorage" const Project = () => { + const { recentProjectList } = useRecentProjectStorage(); const { visible, open, close } = useVisible() const ref = useClickOutside(close) @@ -93,7 +96,7 @@ const Project = () => {

{t("project.recent")}

- {recentProjCache.items.map(p => ( + {recentProjectList.map(p => ( ))}
@@ -106,17 +109,18 @@ type ProjectLineProps = { toggle: (newPath: string) => void } -const RecentProj = ({ path, toggle }: ProjectLineProps) => { +export const RecentProj = ({ path, toggle }: ProjectLineProps) => { + const { recentProjectList, recentProjCacheRemove } = useRecentProjectStorage() const cleanup = useCleanup() const handleNew = () => toggle(path) const curPath = useAtomValue(modelPathAtom) const deletePro = () => { - recentProjCache.remove(path) - if (recentProjCache.items.length === 0) { + recentProjCacheRemove(path) + if (recentProjectList.length === 0) { cleanup(); } else if (path === curPath) { - toggle(recentProjCache.items[0]) + toggle(recentProjectList[0]) } } return
diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts index 95a85ddc5..9a0ed70e1 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/hooks/useNewPathForLayout.ts @@ -20,11 +20,11 @@ import { dynamicVisibleAtom, loadingAtom, modelPathAtom, - recentProjCache, fsgVisibleAtom, translateAtom, useSelectionHistory, useZoom, currentGraphAtom, allGraphAtom, fsgPanelVisibleAtom } from "stores" +import { useRecentProjectStorage } from "stores/useRecentProjectStorage" type LayoutNewPath = (path: string | null) => Promise @@ -39,6 +39,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { const [translate, setTranslate] = useAtom(translateAtom) const [zoom, , resetZoom] = useZoom() const setLoading = useSetAtom(loadingAtom) + const { recentProjCacheAdd } = useRecentProjectStorage() return async (path: string | null) => { if (!path || path === modelPath) return @@ -67,7 +68,7 @@ export const useNewPathForLayout = (): LayoutNewPath => { y: 0 }) if (zoom !== 1) resetZoom() - recentProjCache.add(path) + recentProjCacheAdd(path) } } } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/graph.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/graph.ts index 7de0c7c25..b6048c52a 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/graph.ts +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/graph.ts @@ -50,4 +50,3 @@ export const useZoom = () => { export const searchVisibleAtom = atom(false) -export const recentProjCache = new RingCache(7) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/useRecentProjectStorage.ts b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/useRecentProjectStorage.ts new file mode 100644 index 000000000..65570ba75 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/stores/useRecentProjectStorage.ts @@ -0,0 +1,71 @@ +import { atom, useAtom } from "jotai"; +import { useCallback, useEffect } from "react"; + +const cacheAtom = atom([]); + +export function useRecentProjectStorage() { + const capacity: number = 7; + const [cache, setCache] = useAtom(cacheAtom); + + // 从 localStorage 初始化 cache + const read = useCallback(() => { + const str = localStorage.getItem("recentProj"); + if (str !== null) { + const parsed = JSON.parse(str); + if (Array.isArray(parsed)) { + setCache(parsed); + } + } + }, []); + + // 移除项目 + const remove = useCallback((value: string) => { + setCache(prev => { + const tmp = [...prev]; + const index = tmp.indexOf(value); + if (index !== -1) { + tmp.splice(index, 1); + } + + // 同步更新 localStorage + localStorage.setItem("recentProj", JSON.stringify(tmp)); + return tmp; + }); + }, []); + + // 添加项目 + const add = useCallback((value: string) => { + setCache(prev => { + let tmp = [...prev]; + const index = tmp.indexOf(value); + + // 如果已存在,先移除 + if (index !== -1) { + tmp.splice(index, 1); + } + // 如果超过容量,移除最老的一项 + else if (tmp.length >= capacity) { + tmp.shift(); + } + + // 添加到最新 + tmp.push(value); + + // 持久化 + localStorage.setItem("recentProj", JSON.stringify(tmp)); + return tmp; + }); + }, [capacity]); + + // 组件挂载时读取一次 + useEffect(() => { + read(); + }, [read]); + + return { + recentProjectList: cache, + recentProjCacheRead: read, + recentProjCacheAdd: add, + recentProjCacheRemove: remove, + }; +} \ No newline at end of file -- Gitee From c310c29bd36587d1a9c6d003b9eece1e3cca0832 Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Mon, 18 Aug 2025 09:21:26 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelVis/app/src/FileUpload.tsx | 24 +++++++++++-------- .../ModelVis/app/src/features/Project.tsx | 3 ++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx index dc8cd7f2c..33704bf07 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/FileUpload.tsx @@ -33,17 +33,21 @@ const FileUpload = () => { return <>
- +
+ +
+ {recentProjectList.map(p => ( + + ))} +
+
- {recentProjectList.map(p => ( - - ))} } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx index a3e1d735b..debe07892 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx @@ -128,6 +128,7 @@ export const RecentProj = ({ path, toggle }: ProjectLineProps) => { type="button" className="flex w-full rounded-md px-3 py-2 hover:bg-cyan-100" onClick={handleNew} + title={path} > { )}> A - {path} + {path}
-- Gitee From a04bc017b4b17b850df19b71ab2c7b3a54ea2269 Mon Sep 17 00:00:00 2001 From: heiheihei <1395202740@qq.com> Date: Mon, 18 Aug 2025 11:22:15 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E7=AE=97=E5=AD=90=E6=97=A0=E6=B3=95=E8=A7=A6=E5=8F=91=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModelVis/app/src/ModelStructure/index.tsx | 3 ++- .../ModelVis/app/src/features/Project.tsx | 11 +++++--- .../ModelVis/app/src/src-worker/worker.ts | 4 +-- .../app/src/stores/HistorySelection.ts | 18 ++++++++----- .../ModelVis/app/src/types/ipc.d.ts | 1 + .../ModelVis/app/src/useWorkerMessage.ts | 20 +++++++------- .../ModelVis/app/src/worker-apis.ts | 26 +++++++++---------- 7 files changed, 49 insertions(+), 34 deletions(-) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx index 789ec82ad..caf280f51 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/ModelStructure/index.tsx @@ -49,6 +49,7 @@ import Fsg from "./Fsg" const ModelStructureComp = ({ width, height }: WindowSize) => { const [isDragging, setIsDragging] = useState(false) const [origin, setOrigin] = useState({ x: 0, y: 0 }) + const allGraphs = useAtomValue(allGraphAtom) const data = useAtomValue(nodesEdgesAtom) const [translate, setTranslate] = useAtom(translateAtom) @@ -90,7 +91,7 @@ const ModelStructureComp = ({ width, height }: WindowSize) => { const px = (clientX - bbox.left - translate.x) / zoom const py = (clientY - bbox.top - translate.y) / zoom - workerHitTest(px, py) + workerHitTest(px, py, allGraphs) } const handleWheel = debounce((ev: WheelEvent) => { diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx index debe07892..1fa426ba3 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src/features/Project.tsx @@ -116,13 +116,18 @@ export const RecentProj = ({ path, toggle }: ProjectLineProps) => { const handleNew = () => toggle(path) const curPath = useAtomValue(modelPathAtom) const deletePro = () => { + // 因为修改recentProjCache是异步操作,所以先判断之后的操作 + const wasLastItem = recentProjectList.length === 1 + const isCurrentPath = path === curPath + recentProjCacheRemove(path) - if (recentProjectList.length === 0) { - cleanup(); - } else if (path === curPath) { + if (wasLastItem) { + cleanup() + } else if (isCurrentPath) { toggle(recentProjectList[0]) } } + return