feat: 上传分析入口

This commit is contained in:
mozzie 2024-09-06 14:27:41 +08:00
parent 9920d5eeca
commit ab22fcbf52
19 changed files with 461 additions and 513 deletions

View File

@ -4,5 +4,5 @@ import { machineIdSync } from "node-machine-id";
export const getMachineId = async () => {
const id = await machineIdSync();
console.log(id);
console.warn("机器码id: ", id);
};

View File

@ -3,36 +3,51 @@ import { JSONFilePreset } from "lowdb/node";
import { app } from "electron";
import { Low } from "node_modules/lowdb/lib/core/Low";
import { StructuredMetadata } from "./dicom";
import { existsSync } from "node:fs";
import { merge } from "lodash";
interface ICreateDatabase {
export interface ICreateDatabase {
name: string;
}
type SeriesTableType = StructuredMetadata & {
export type SeriesTableType = StructuredMetadata & {
createTime?: number;
updateTime?: number;
};
interface DbTable {
export type SettingTableType = {
/**
* GPUCPUNPU
* @default GPU
*/
inferDevice: string;
/**
*
* @description
*/
outputPath: string;
};
export interface DbTable {
series: SeriesTableType[];
setting: SettingTableType;
}
const defaultData: DbTable = { series: [] };
export let db: Low<{ series: SeriesTableType[] }>;
const defaultTable: DbTable = {
series: [],
setting: {
inferDevice: "gpu",
outputPath: path.join(app.getPath("userData"), "output"),
},
};
export let db: Low<DbTable>;
export const createDatabase = async (config: ICreateDatabase) => {
const { name } = config;
db = await JSONFilePreset(
path.join(app.getPath("userData"), name),
defaultData
);
const dbJsonFilePath = path.join(app.getPath("userData"), name);
db = await JSONFilePreset(dbJsonFilePath, defaultTable);
// 表结构更新,增量合并
db.data = merge({}, defaultTable, db.data);
await db.write();
};
// Update db.json
// await db.update(({ posts }) => posts.push("hello world"));
// Alternatively you can call db.write() explicitely later to write to db.json
// db.data.posts.push("hello world");
// await db.write();
// console.log(db);

View File

@ -1,4 +1,4 @@
import { app, dialog, ipcMain } from "electron";
import { app, dialog, ipcMain, shell } from "electron";
import os from "os";
import {
findDcmFiles,
@ -9,6 +9,8 @@ import {
import { db } from "./core/db";
import axios from "axios";
import path from "node:path";
import { mkdirSync, statSync } from "fs";
import { mkdir, stat } from "fs/promises";
/**
*
@ -82,22 +84,12 @@ const registerIpcMainHandlers = (mainWindow: Electron.BrowserWindow | null) => {
const overallDuration = (overallEndTime - overallStartTime) / 1000; // 总耗时
console.log(`All dicoms processed in ${overallDuration} seconds.`);
});
// const img_path =
// const {
// img_path,
// save_path,
// pu = "GPU",
// module = "root",
// turbo = true,
// } = data;
});
/**
* dialog
*/
ipcMain.on("import-dicom-dialog-visible", async (event) => {
console.log(1111);
const result = await dialog.showOpenDialog({
properties: ["openDirectory"],
});
@ -140,6 +132,31 @@ const registerIpcMainHandlers = (mainWindow: Electron.BrowserWindow | null) => {
const seriesList = db.data.series;
event.reply("db:series:select:response", seriesList);
});
/**
*
*/
ipcMain.on("setInferDevice", async (event, device) => {
await db.update(({ setting }) => ({ ...setting, inferDevice: device }));
event.reply("setInferDevice:response", `推理硬件修改为${device}`);
});
/**
*
*/
ipcMain.on("openOutputPath", async () => {
await db.read();
const optPath = db.data.setting.outputPath;
const resolvedPath = path.resolve(optPath);
try {
// 检查路径是否存在
const stats = await stat(resolvedPath);
if (stats.isDirectory()) shell.openPath(resolvedPath);
} catch (error: any) {
await mkdir(resolvedPath, { recursive: true });
shell.openPath(resolvedPath);
}
});
};
export default registerIpcMainHandlers;

View File

@ -9,7 +9,6 @@ import {
// import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import path from "node:path";
// import registerIpcMainHandlers from "./ipcMainHandlers";
import { createDatabase } from "./core/db";
import { getMachineId } from "./core/auth";
import registerIpcMainHandlers from "./ipcMainHandlers";
@ -39,6 +38,8 @@ const themeTitleBarStyles = {
light: {},
};
const platform = process.platform === "darwin" ? "macos" : "windows";
function createWindow() {
win = new BrowserWindow({
width: 1280,
@ -54,10 +55,12 @@ function createWindow() {
},
});
// Test active push message to Renderer-process.
/**
*
*/
win.webContents.on("did-finish-load", () => {
win?.webContents.send("main-process-message", {
platform: process.platform === "darwin" ? "macos" : "windows",
win?.webContents.send("mount", {
platform,
theme,
});
});
@ -65,18 +68,23 @@ function createWindow() {
if (VITE_DEV_SERVER_URL) {
win.loadURL(VITE_DEV_SERVER_URL);
registerIpcMainHandlers(win);
python_process = spawn(path.join(process.env.VITE_PUBLIC!, "main.exe"));
if (platform !== "macos") {
python_process = spawn(path.join(process.env.VITE_PUBLIC!, "main.exe"));
}
} else {
win.loadFile(path.join(RENDERER_DIST, "index.html")).then(() => {
if (process.argv.length >= 2) {
const folderPath = process.argv[2];
win?.webContents.send("open-folder", folderPath);
win?.webContents.send("context-menu-launch", folderPath);
registerIpcMainHandlers(win);
}
});
}
}
/**
* /
*/
function createTray() {
if (tray) tray.destroy();
const iconPath = path.join(process.env.VITE_PUBLIC, "AI.png"); // 使用 PNG 图标
@ -102,14 +110,11 @@ function createTray() {
},
]);
tray.setToolTip("My Electron App");
tray.setToolTip("Cvpilot Tool");
tray.setContextMenu(contextMenu);
tray.on("click", () => {
if (win) {
win.isVisible() ? win.hide() : win.show();
}
});
const toggle = () => win && (win.isVisible() ? win.hide() : win.show());
tray.on("click", () => toggle);
}
function registerGlobalShortcuts() {
@ -122,8 +127,7 @@ function registerGlobalShortcuts() {
}
app.on("window-all-closed", async () => {
console.log(python_process?.pid);
if (process.platform !== "darwin") {
if (platform !== "macos") {
app.quit();
win = null;
}
@ -145,10 +149,10 @@ app.whenReady().then(() => {
createTray();
registerGlobalShortcuts();
createDatabase({ name: "cvpilot.json" });
console.log(path.join(app.getPath("userData")));
console.log("userData路径", path.join(app.getPath("userData")));
// 设置 Dock 图标
if (process.platform === "darwin") {
if (platform === "macos") {
const dockIconPath = path.join(process.env.VITE_PUBLIC, "girl.png");
const dockIcon = nativeImage.createFromPath(dockIconPath);
app.dock.setIcon(dockIcon);

View File

@ -63,7 +63,7 @@
"tailwindcss-animate": "^1.0.7",
"zod": "3.23.8",
"axios": "1.7.7",
"fkill": "9.0.0"
"lodash": "4.17.21"
},
"devDependencies": {
"@radix-ui/react-icons": "^1.3.0",
@ -84,6 +84,7 @@
"typescript": "^5.2.2",
"vite": "^5.1.6",
"vite-plugin-electron": "^0.28.6",
"vite-plugin-electron-renderer": "^0.14.5"
"vite-plugin-electron-renderer": "^0.14.5",
"@types/lodash": "4.17.7"
}
}

View File

@ -13,8 +13,14 @@ function App() {
| "dark"
| "light";
/**
*
*/
useEffect(() => {
window.ipcRenderer.send("ipc-loaded");
return () => {
window.ipcRenderer.off("ipc-loaded", () => {});
};
}, []);
return (

View File

@ -0,0 +1,19 @@
import { inferDeviceType } from "./type";
export const inferDevices: inferDeviceType[] = [
{
key: "gpu",
name: "GPU",
checked: true,
},
{
key: "cpu",
name: "CPU",
checked: false,
},
{
key: "npu",
name: "NPU",
checked: false,
},
];

View File

@ -0,0 +1,280 @@
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { inferDeviceType } from "./type";
import { inferDevices } from "./constant";
import { useToast } from "@/components/ui/use-toast";
import { ToastAction } from "@/components/ui/toast";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { RocketIcon } from "@radix-ui/react-icons";
interface ScanProgress {
percentage: number;
}
const defaultProgress = {
percentage: 0,
};
export const MenuBar = () => {
const { toast } = useToast();
const navigate = useNavigate();
const [progress, setProgress] = useState<ScanProgress>(defaultProgress);
const [inferOption, setInferOption] =
useState<inferDeviceType[]>(inferDevices);
const [, setResult] = useState<[]>([]);
const [importDialogVisible, setImportDialogVisible] = useState(false);
useEffect(() => {
const handleScanProgress = (
_event: Electron.IpcRendererEvent,
data: any
) => {
setProgress(data);
if (data.error) return;
};
window.ipcRenderer.on("scan-progress", handleScanProgress);
return () => {
window.ipcRenderer.off("scan-progress", handleScanProgress);
};
}, []);
useEffect(() => {
window.ipcRenderer.once("scan-start", () => {
setImportDialogVisible(true);
});
}, []);
useEffect(() => {
const handleScanFinished = (
_event: Electron.IpcRendererEvent,
data: any
) => {
const { scanDuration, structDicom } = data;
console.log(data);
setResult(structDicom);
setImportDialogVisible(false);
if (data.error) {
return toast({
variant: "destructive",
title: "Uh oh! Something went wrong.",
description: "There was a problem with your request.",
action: <ToastAction altText="重试"></ToastAction>,
});
} else {
toast({
variant: "default",
title: "完成",
description: `本次操作共导入${structDicom.length}组序列数据,耗时:${(
scanDuration / 1000
).toFixed(2)} s`,
action: (
<ToastAction
altText="启动AI测量"
onClick={() => handleTasks(structDicom)}
>
</ToastAction>
),
duration: 30 * 1000,
});
window.ipcRenderer.send("db:series:select");
}
};
window.ipcRenderer.on("scan-progress-done", handleScanFinished);
return () => {
window.ipcRenderer.off("scan-progress-done", handleScanFinished);
};
}, [toast]);
useEffect(() => {
if (!importDialogVisible) {
setProgress(defaultProgress);
}
}, [importDialogVisible]);
const handleImportDicom = () => {
navigate("datasource");
window.ipcRenderer.send("import-dicom-dialog-visible");
};
/**
*
*/
const handleSwtichInferDevice = (item: inferDeviceType) => {
setInferOption((p) =>
p.map((i) => ({ ...i, checked: i.key === item.key }))
);
window.ipcRenderer.send("setInferDevice", item.key);
};
useEffect(() => {
const actionToast = (
_event: Electron.IpcRendererEvent,
response: string
) => {
toast({
title: "操作成功",
description: response,
});
};
window.ipcRenderer.on("setInferDevice:response", actionToast);
return () => {
window.ipcRenderer.off("setInferDevice:response", actionToast);
};
}, [toast]);
const handleOpenOutputPath = () => {
window.ipcRenderer.send("openOutputPath");
};
const handleTasks = (structDicoms: any) => {
localStorage.setItem("selectDicoms", JSON.stringify(structDicoms));
navigate("/", { state: { selectDicoms: structDicoms } });
};
return (
<>
<Menubar
style={{ background: "transparent", border: 0, boxShadow: "none" }}
>
<MenubarMenu>
<MenubarTrigger></MenubarTrigger>
<MenubarContent>
<MenubarItem onSelect={handleImportDicom}>
Dicom<MenubarShortcut>T</MenubarShortcut>
</MenubarItem>
<MenubarItem onClick={handleOpenOutputPath}>
<MenubarShortcut>N</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>New Incognito Window</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger></MenubarSubTrigger>
<MenubarSubContent>
{inferOption.map((item) => (
<MenubarCheckboxItem
key={item.key}
onClick={() => handleSwtichInferDevice(item)}
checked={item.checked}
>
{item.name}
</MenubarCheckboxItem>
))}
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>
<MenubarShortcut>P</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>
Undo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Redo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Find</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Search the web</MenubarItem>
<MenubarSeparator />
<MenubarItem>Find...</MenubarItem>
<MenubarItem>Find Next</MenubarItem>
<MenubarItem>Find Previous</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>Cut</MenubarItem>
<MenubarItem>Copy</MenubarItem>
<MenubarItem>Paste</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>View</MenubarTrigger>
<MenubarContent>
<MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
<MenubarCheckboxItem checked>
Always Show Full URLs
</MenubarCheckboxItem>
<MenubarSeparator />
<MenubarItem inset>
Reload <MenubarShortcut>R</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled inset>
Force Reload <MenubarShortcut>R</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Toggle Fullscreen</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Hide Sidebar</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Profiles</MenubarTrigger>
<MenubarContent>
<MenubarRadioGroup value="benoit">
<MenubarRadioItem value="andy">Andy</MenubarRadioItem>
<MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
<MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarItem inset>Edit...</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Add Profile...</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
{/* 导入数据dialog */}
<Dialog open={importDialogVisible} onOpenChange={setImportDialogVisible}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
</DialogDescription>
</DialogHeader>
<div className="flex items-center space-x-2">
<Alert>
<RocketIcon className="h-4 w-4" />
<AlertTitle></AlertTitle>
<AlertDescription>
<Progress value={progress?.percentage} />
</AlertDescription>
</Alert>
</div>
</DialogContent>
</Dialog>
</>
);
};

View File

@ -0,0 +1,7 @@
import { ReactNode } from "react";
export type inferDeviceType = {
key: string;
name: string | ReactNode;
checked: boolean;
};

View File

@ -0,0 +1,11 @@
import { MenuItem } from "./type";
import { BrainCircuit, Package, HardDrive, Wrench } from "lucide-react";
export const menuItems: MenuItem[] = [
{ to: "/", name: "自动分析", icon: <BrainCircuit /> },
{ to: "/datasource", name: "数据列表", icon: <HardDrive /> },
{ to: "/models", name: "模型管理", icon: <Package /> },
{ to: "/tools", name: "小工具", icon: <Wrench /> },
// { to: "/help", name: "帮助", icon: <IoHandLeftOutline size={24} /> },
// { to: "/setting", name: "设置", icon: <IoSettingsOutline size={24} /> },
];

View File

@ -1,31 +1,8 @@
import { Link, useLocation } from "react-router-dom";
import {
IoCubeOutline,
IoHammerOutline,
IoListOutline,
IoPlayOutline,
IoSettingsOutline,
} from "react-icons/io5";
import "./LeftDocker.css";
import { menuItems } from "./constant";
import { MenuItem } from "./type";
import { ReactNode } from "react";
type MenuItem = {
to: string;
name: string;
icon: ReactNode;
};
const menuItems: MenuItem[] = [
{ to: "/", name: "自动分析", icon: <IoPlayOutline size={24} /> },
{ to: "/datasource", name: "数据列表", icon: <IoListOutline size={24} /> },
{ to: "/models", name: "模型管理", icon: <IoCubeOutline size={24} /> },
{ to: "/tools", name: "小工具", icon: <IoHammerOutline size={24} /> },
// { to: "/help", name: "帮助", icon: <IoHandLeftOutline size={24} /> },
{ to: "/setting", name: "设置", icon: <IoSettingsOutline size={24} /> },
];
export const LeftDocker = () => {
export const SideBarLeft = () => {
const location = useLocation();
const handleClick = (item: MenuItem) => {

View File

@ -0,0 +1,7 @@
import { ReactNode } from "react";
export type MenuItem = {
to: string;
name: string;
icon: ReactNode;
};

View File

@ -2,10 +2,10 @@ import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "@/style/global.css";
window.ipcRenderer.on("main-process-message", (_event, message) => {
const { platform, theme } = message
document.querySelector('html')?.setAttribute('platform', platform)
document.querySelector('html')?.setAttribute('theme', theme)
window.ipcRenderer.on("mount", (_event, message) => {
const { platform, theme } = message;
document.querySelector("html")?.setAttribute("platform", platform);
document.querySelector("html")?.setAttribute("theme", theme);
ReactDOM.createRoot(document.getElementById("root")!).render(<App />);
});

View File

@ -1,20 +1,11 @@
import { Button } from "@/components/ui/button";
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { ToastAction } from "@/components/ui/toast";
import { useToast } from "@/components/ui/use-toast";
import { RocketIcon } from "@radix-ui/react-icons";
import { useLocation } from "react-router-dom";
import { SparkleIcon } from "lucide-react";
import { SparkleIcon, Trash2 } from "lucide-react";
import {
ResizableHandle,
ResizablePanel,
@ -22,17 +13,10 @@ import {
} from "@/components/ui/resizable";
import { Card } from "@/components/ui/card";
import { CarouselApi } from "@/components/ui/carousel";
import { Series } from "../Datasource/SeriesTable";
import { ScrollArea } from "@/components/ui/scroll-area";
interface ScanProgress {
percentage: number;
}
const defaultProgress = {
percentage: 0,
};
const Boot = () => {
const location = useLocation();
@ -44,89 +28,28 @@ const Boot = () => {
* windows系统右键启动应用菜单的入口路径
*/
const [bootDirectoryPath, setBootDirectoryPath] = useState("");
const [tasks, setTasks] = useState(selectDicoms);
const [progress, setProgress] = useState<ScanProgress>(defaultProgress);
const { toast } = useToast();
const [, setResult] = useState<[]>([]);
const [importDialogVisible, setImportDialogVisible] = useState(false);
useEffect(() => {
const handleScanProgress = (
_event: Electron.IpcRendererEvent,
data: any
) => {
setProgress(data);
if (data.error) return;
};
window.ipcRenderer.on("scan-progress", handleScanProgress);
return () => {
window.ipcRenderer.off("scan-progress", handleScanProgress);
};
}, []);
useEffect(() => {
window.ipcRenderer.once("scan-start", () => {
setImportDialogVisible(true);
});
}, []);
useEffect(() => {
const handleScanFinished = (
_event: Electron.IpcRendererEvent,
data: any
) => {
const { scanDuration, structDicom } = data;
console.log(structDicom);
setResult(structDicom);
setImportDialogVisible(false);
if (data.error) {
return toast({
variant: "destructive",
title: "Uh oh! Something went wrong.",
description: "There was a problem with your request.",
action: <ToastAction altText="重试"></ToastAction>,
});
} else {
toast({
variant: "default",
title: "完成",
description: `本次操作共导入${structDicom.length}组序列数据,耗时:${(
scanDuration / 1000
).toFixed(2)} s`,
action: <ToastAction altText="启动AI测量">AI测量</ToastAction>,
duration: 30 * 1000,
});
window.ipcRenderer.send("db:series:select");
}
};
window.ipcRenderer.on("scan-progress-done", handleScanFinished);
return () => {
window.ipcRenderer.off("scan-progress-done", handleScanFinished);
};
}, [toast]);
useEffect(() => {
if (!importDialogVisible) {
setProgress(defaultProgress);
}
}, [importDialogVisible]);
/**
* electron主进程
*/
const handleTasks = () => {
window.ipcRenderer.send("ai:task", { selectDicoms });
window.ipcRenderer.send("ai:task", { selectDicoms: tasks });
};
useEffect(() => {
window.ipcRenderer.on("open-folder", (_, data) => {
window.ipcRenderer.on("context-menu-launch", (_, data) => {
console.log("右键菜单拉起启动文件夹路径", data);
setBootDirectoryPath(data);
});
}, []);
const handleEmptyTasks = () => {
setTasks([]);
localStorage.removeItem("selectDicoms");
};
return (
<motion.div
initial={{ y: 10, opacity: 0 }}
@ -138,13 +61,13 @@ const Boot = () => {
<div className="p-4 h-full flex flex-col">
<ResizablePanelGroup
direction="horizontal"
className="w-full h-full border rounded-lg"
className="w-full h-full"
>
<ResizablePanel defaultSize={38.2}>
<div className="flex flex-col h-full pt-4">
<ScrollArea className="flex-grow w-full h-full px-4 pb-2">
<div className="w-full flex flex-col gap-y-2">
{selectDicoms.map((dicom: Series, index: number) => (
{tasks.map((dicom: Series, index: number) => (
<Card
key={index}
className="flex shadow-none flex-col items-start gap-2 rounded-lg border p-3 text-left text-sm transition-all hover:bg-accent"
@ -183,7 +106,11 @@ const Boot = () => {
))}
</div>
</ScrollArea>
<div className="flex-shrink-0 px-4 py-4 text-right">
<div className="flex-shrink-0 flex items-center justify-end gap-2 px-4 py-4">
<Button onClick={handleEmptyTasks} variant="ghost">
<Trash2 className="mr-2 h-4 w-4" />
</Button>
<Button onClick={handleTasks}>
<SparkleIcon className="mr-2 h-4 w-4" />
@ -199,26 +126,6 @@ const Boot = () => {
</ResizablePanel>
</ResizablePanelGroup>
</div>
{/* 导入数据dialog */}
<Dialog open={importDialogVisible} onOpenChange={setImportDialogVisible}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
</DialogDescription>
</DialogHeader>
<div className="flex items-center space-x-2">
<Alert>
<RocketIcon className="h-4 w-4" />
<AlertTitle></AlertTitle>
<AlertDescription>
<Progress value={progress?.percentage} />
</AlertDescription>
</Alert>
</div>
</DialogContent>
</Dialog>
</motion.div>
);
};

View File

@ -1,18 +0,0 @@
/* Layout.css */
.custom-tab-strip {
border-bottom-color: hsl(var(--border));
padding-left: 0;
.flexlayout__tabset_tabbar_inner_tab_container {
border-top: 0;
padding-left: 0;
}
.flexlayout__tab_button--selected {
background: hsl(var(--secondary));
}
.flexlayout__tabset-selected {
background: transparent;
}
}

View File

@ -1,13 +1,11 @@
import { Toaster } from "@/components/ui/toaster";
import { LeftDocker } from "./LeftDocker";
import { Outlet } from "react-router-dom";
import { MenuBar } from "./MenuBar";
import { MenuBar } from "@/components/base/MenuBar";
import { SideBarLeft } from "@/components/base/SideBarLeft";
const LayoutMain = () => {
const platform =
document.querySelector("html")?.getAttribute("platform") ?? "macos";
// const titleBarStyles =
// platform === "macos" ? "pl-[5rem] pr-[.5rem]" : "pl-[.5rem]";
const titleBarStyles = platform === "macos" ? "pl-[80px]" : "pl-[.5rem]";
return (
@ -16,13 +14,12 @@ const LayoutMain = () => {
<div className={`inline-flex no-drag items-center ${titleBarStyles}`}>
{platform !== "macos" && <img src="logo.svg" className="h-[20px]" />}
<MenuBar />
{/* <span className="pl-2 text-xs">CVPilot Tool</span> */}
</div>
</div>
<div className="relative h-[calc(100%-36px)]">
<div className="flex h-full">
<div className="workspace w-[80px] drag">
<LeftDocker />
<SideBarLeft />
</div>
<div className="relative w-[calc(100%-80px)]">
<div className="rounded-tl-lg h-full">

View File

@ -1,117 +0,0 @@
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar";
import { useNavigate } from "react-router-dom";
export const MenuBar = () => {
const navigate = useNavigate();
const handleImportDicom = () => {
navigate("/");
window.ipcRenderer.send("import-dicom-dialog-visible");
};
return (
<Menubar
style={{ background: "transparent", border: 0, boxShadow: "none" }}
>
<MenubarMenu>
<MenubarTrigger></MenubarTrigger>
<MenubarContent>
<MenubarItem onSelect={handleImportDicom}>
Dicom<MenubarShortcut>T</MenubarShortcut>
</MenubarItem>
<MenubarItem>
New Window <MenubarShortcut>N</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>New Incognito Window</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Share</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Email link</MenubarItem>
<MenubarItem>Messages</MenubarItem>
<MenubarItem>Notes</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>
Print... <MenubarShortcut>P</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>
Undo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Redo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Find</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Search the web</MenubarItem>
<MenubarSeparator />
<MenubarItem>Find...</MenubarItem>
<MenubarItem>Find Next</MenubarItem>
<MenubarItem>Find Previous</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>Cut</MenubarItem>
<MenubarItem>Copy</MenubarItem>
<MenubarItem>Paste</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>View</MenubarTrigger>
<MenubarContent>
<MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
<MenubarCheckboxItem checked>
Always Show Full URLs
</MenubarCheckboxItem>
<MenubarSeparator />
<MenubarItem inset>
Reload <MenubarShortcut>R</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled inset>
Force Reload <MenubarShortcut>R</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Toggle Fullscreen</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Hide Sidebar</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Profiles</MenubarTrigger>
<MenubarContent>
<MenubarRadioGroup value="benoit">
<MenubarRadioItem value="andy">Andy</MenubarRadioItem>
<MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
<MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarItem inset>Edit...</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Add Profile...</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
);
};

View File

@ -106,15 +106,15 @@ importers:
embla-carousel-react:
specifier: ^8.2.0
version: 8.2.0(react@18.3.1)
fkill:
specifier: 9.0.0
version: 9.0.0
flexlayout-react:
specifier: ^0.7.15
version: 0.7.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
framer-motion:
specifier: ^11.3.24
version: 11.3.30(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
lodash:
specifier: 4.17.21
version: 4.17.21
lowdb:
specifier: ^7.0.1
version: 7.0.1
@ -173,6 +173,9 @@ importers:
'@radix-ui/react-icons':
specifier: ^1.3.0
version: 1.3.0(react@18.3.1)
'@types/lodash':
specifier: 4.17.7
version: 4.17.7
'@types/node':
specifier: 22.5.2
version: 22.5.2
@ -1509,6 +1512,9 @@ packages:
'@types/keyv@3.1.4':
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
'@types/lodash@4.17.7':
resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
'@types/long@4.0.2':
resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
@ -1654,10 +1660,6 @@ packages:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
aggregate-error@5.0.0:
resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
engines: {node: '>=18'}
ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies:
@ -1946,10 +1948,6 @@ packages:
classnames@2.5.1:
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
clean-stack@5.2.0:
resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==}
engines: {node: '>=14.16'}
cli-truncate@2.1.0:
resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
engines: {node: '>=8'}
@ -2275,10 +2273,6 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
eslint-plugin-react-hooks@4.6.2:
resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
engines: {node: '>=10'}
@ -2333,14 +2327,6 @@ packages:
events-intercept@2.0.0:
resolution: {integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==}
execa@6.1.0:
resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
exenv@1.2.2:
resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==}
@ -2404,10 +2390,6 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
fkill@9.0.0:
resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==}
engines: {node: '>=18'}
flat-cache@3.2.0:
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -2520,14 +2502,6 @@ packages:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
get-stream@6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
@ -2652,14 +2626,6 @@ packages:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
human-signals@3.0.1:
resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==}
engines: {node: '>=12.20.0'}
human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
@ -2687,10 +2653,6 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
indent-string@5.0.0:
resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
engines: {node: '>=12'}
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
@ -2757,10 +2719,6 @@ packages:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
is@3.3.0:
resolution: {integrity: sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==}
@ -2960,10 +2918,6 @@ packages:
engines: {node: '>=4.0.0'}
hasBin: true
mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
mimic-function@5.0.1:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
@ -3077,10 +3031,6 @@ packages:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
npm-run-path@5.3.0:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@ -3096,10 +3046,6 @@ packages:
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
onnx-proto@4.0.4:
resolution: {integrity: sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==}
@ -3175,10 +3121,6 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-key@4.0.0:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@ -3203,10 +3145,6 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
pid-port@1.0.0:
resolution: {integrity: sha512-LSNBeKChRPA4Xlrs6+zV588G1hSrFvANtPV5rt/5MPfSPK3V9XPWxx1d29svsrOjngT9ifLisXWCLS7DvO9ZhQ==}
engines: {node: '>=18'}
pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
@ -3272,10 +3210,6 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
process-exists@5.0.0:
resolution: {integrity: sha512-6QPRh5fyHD8MaXr4GYML8K/YY0Sq5dKHGIOrAKS3cYpHQdmygFCcijIu1dVoNKAZ0TWAMoeh8KDK9dF8auBkJA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
@ -3305,10 +3239,6 @@ packages:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
ps-list@8.1.1:
resolution: {integrity: sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
pump@2.0.1:
resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
@ -3808,9 +3738,6 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@ -3905,10 +3832,6 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
@ -3981,10 +3904,6 @@ packages:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
taskkill@5.0.0:
resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==}
engines: {node: '>=14.16'}
teeny-request@9.0.0:
resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==}
engines: {node: '>=14'}
@ -5565,6 +5484,8 @@ snapshots:
dependencies:
'@types/node': 22.5.2
'@types/lodash@4.17.7': {}
'@types/long@4.0.2': {}
'@types/ms@0.7.34': {}
@ -5754,11 +5675,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
aggregate-error@5.0.0:
dependencies:
clean-stack: 5.2.0
indent-string: 5.0.0
ajv-formats@3.0.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@ -5862,7 +5778,7 @@ snapshots:
app-builder-bin@4.0.0: {}
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
dependencies:
'@develar/schema-utils': 2.6.5
'@electron/notarize': 2.2.1
@ -5876,7 +5792,7 @@ snapshots:
builder-util-runtime: 9.2.4
chromium-pickle-js: 0.2.0
debug: 4.3.6
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
ejs: 3.1.10
electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3)
electron-publish: 24.13.1
@ -6173,10 +6089,6 @@ snapshots:
classnames@2.5.1: {}
clean-stack@5.2.0:
dependencies:
escape-string-regexp: 5.0.0
cli-truncate@2.1.0:
dependencies:
slice-ansi: 3.0.0
@ -6366,9 +6278,9 @@ snapshots:
dlv@1.1.3: {}
dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3):
dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
builder-util: 24.13.1
builder-util-runtime: 9.2.4
fs-extra: 10.1.0
@ -6436,7 +6348,7 @@ snapshots:
electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3):
dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
archiver: 5.3.2
builder-util: 24.13.1
fs-extra: 10.1.0
@ -6446,11 +6358,11 @@ snapshots:
electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
builder-util: 24.13.1
builder-util-runtime: 9.2.4
chalk: 4.1.2
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
fs-extra: 10.1.0
is-ci: 3.0.1
lazy-val: 1.0.5
@ -6557,8 +6469,6 @@ snapshots:
escape-string-regexp@4.0.0: {}
escape-string-regexp@5.0.0: {}
eslint-plugin-react-hooks@4.6.2(eslint@8.57.0):
dependencies:
eslint: 8.57.0
@ -6641,30 +6551,6 @@ snapshots:
events-intercept@2.0.0: {}
execa@6.1.0:
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 3.0.1
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.3.0
onetime: 6.0.0
signal-exit: 3.0.7
strip-final-newline: 3.0.0
execa@8.0.1:
dependencies:
cross-spawn: 7.0.3
get-stream: 8.0.1
human-signals: 5.0.0
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.3.0
onetime: 6.0.0
signal-exit: 4.1.0
strip-final-newline: 3.0.0
exenv@1.2.2: {}
expand-template@2.0.3: {}
@ -6731,15 +6617,6 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
fkill@9.0.0:
dependencies:
aggregate-error: 5.0.0
execa: 8.0.1
pid-port: 1.0.0
process-exists: 5.0.0
ps-list: 8.1.1
taskkill: 5.0.0
flat-cache@3.2.0:
dependencies:
flatted: 3.3.1
@ -6853,10 +6730,6 @@ snapshots:
dependencies:
pump: 3.0.0
get-stream@6.0.1: {}
get-stream@8.0.1: {}
github-from-package@0.0.0: {}
glob-parent@5.1.2:
@ -7046,10 +6919,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
human-signals@3.0.1: {}
human-signals@5.0.0: {}
hyphenate-style-name@1.1.0: {}
iconv-corefoundation@1.1.7:
@ -7073,8 +6942,6 @@ snapshots:
imurmurhash@0.1.4: {}
indent-string@5.0.0: {}
inflight@1.0.6:
dependencies:
once: 1.4.0
@ -7127,8 +6994,6 @@ snapshots:
is-stream@2.0.1: {}
is-stream@3.0.0: {}
is@3.3.0: {}
isarray@1.0.0: {}
@ -7299,8 +7164,6 @@ snapshots:
mime@2.6.0: {}
mimic-fn@4.0.0: {}
mimic-function@5.0.1: {}
mimic-response@1.0.1: {}
@ -7382,10 +7245,6 @@ snapshots:
normalize-url@6.1.0: {}
npm-run-path@5.3.0:
dependencies:
path-key: 4.0.0
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@ -7397,10 +7256,6 @@ snapshots:
dependencies:
wrappy: 1.0.2
onetime@6.0.0:
dependencies:
mimic-fn: 4.0.0
onnx-proto@4.0.4:
dependencies:
protobufjs: 6.11.4
@ -7480,8 +7335,6 @@ snapshots:
path-key@3.1.1: {}
path-key@4.0.0: {}
path-parse@1.0.7: {}
path-scurry@1.11.1:
@ -7503,10 +7356,6 @@ snapshots:
picomatch@2.3.1: {}
pid-port@1.0.0:
dependencies:
execa: 8.0.1
pify@2.3.0: {}
pirates@4.0.6: {}
@ -7573,10 +7422,6 @@ snapshots:
prelude-ls@1.2.1: {}
process-exists@5.0.0:
dependencies:
ps-list: 8.1.1
process-nextick-args@2.0.1: {}
progress@2.0.3: {}
@ -7629,8 +7474,6 @@ snapshots:
proxy-from-env@1.1.0: {}
ps-list@8.1.1: {}
pump@2.0.1:
dependencies:
end-of-stream: 1.4.4
@ -8254,8 +8097,6 @@ snapshots:
shebang-regex@3.0.0: {}
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
simple-concat@1.0.1: {}
@ -8357,8 +8198,6 @@ snapshots:
dependencies:
ansi-regex: 6.0.1
strip-final-newline@3.0.0: {}
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {}
@ -8475,10 +8314,6 @@ snapshots:
mkdirp: 3.0.1
yallist: 5.0.0
taskkill@5.0.0:
dependencies:
execa: 6.1.0
teeny-request@9.0.0:
dependencies:
http-proxy-agent: 5.0.0