feat: build with nsis

This commit is contained in:
mozzie 2024-09-03 15:28:30 +08:00
parent 2caf55facc
commit 097a89ca37
22 changed files with 159 additions and 370 deletions

View File

@ -1,43 +1,40 @@
// @see - https://www.electron.build/configuration/configuration
{
"$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
"appId": "YourAppID",
"asar": true,
"productName": "YourAppName",
"directories": {
"output": "release/${version}"
$schema: "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
appId: "cvpilot",
asar: true,
productName: "cvpilot",
directories: {
output: "release/${version}",
},
"files": [
"dist",
"dist-electron"
],
"mac": {
"target": [
"dmg"
],
"artifactName": "${productName}-Mac-${version}-Installer.${ext}"
files: ["dist", "dist-electron"],
mac: {
target: ["dmg"],
artifactName: "${productName}-Mac-${version}-Installer.${ext}",
},
"win": {
"target": [
win: {
target: [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}-Windows-${version}-Setup.${ext}"
target: "nsis",
arch: ["x64"],
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false
},
"linux": {
"target": [
"AppImage"
],
"artifactName": "${productName}-Linux-${version}.${ext}"
}
artifactName: "${productName}-Windows-${version}-Setup.${ext}",
},
nsis: {
oneClick: false,
perMachine: false,
allowElevation: true,
allowToChangeInstallationDirectory: true,
createDesktopShortcut: true,
runAfterFinish: true,
shortcutName: "CvpilotAI",
guid:"cvpilot",
include: "./script/installer.nsh",
deleteAppDataOnUninstall: false,
},
linux: {
target: ["AppImage"],
artifactName: "${productName}-Linux-${version}.${ext}",
},
}

View File

@ -1,4 +1,4 @@
import http from "node:http";
// import http from "node:http";
import path from "node:path";
import { spawn, ChildProcess } from "node:child_process";
import { BrowserWindow } from "electron";
@ -9,8 +9,8 @@ class PythonManager {
constructor(
private mainWindow: BrowserWindow | null,
private url: string,
private interval = 5000
// private url: string,
// private interval = 5000
) {}
// 启动 Python 服务
@ -62,32 +62,32 @@ class PythonManager {
}
// 检查 Flask 服务状态
private checkFlaskStatus() {
if (!this.mainWindow) return;
// private checkFlaskStatus() {
// if (!this.mainWindow) return;
http
.get(this.url, (res) => {
const { statusCode } = res;
this.mainWindow?.webContents.send("flask-check", {
running: statusCode === 200,
});
})
.on("error", (err) => {
console.error(`Error checking Flask service: ${err.message}`);
this.mainWindow?.webContents.send("flask-check", {
running: false,
});
});
}
// http
// .get(this.url, (res) => {
// const { statusCode } = res;
// this.mainWindow?.webContents.send("flask-check", {
// running: statusCode === 200,
// });
// })
// .on("error", (err) => {
// console.error(`Error checking Flask service: ${err.message}`);
// this.mainWindow?.webContents.send("flask-check", {
// running: false,
// });
// });
// }
// 开始轮询 Flask 服务状态
private startCheckingFlaskStatus() {
if (this.intervalId) {
console.log("Already checking Flask status.");
return;
}
this.intervalId = setInterval(() => this.checkFlaskStatus(), this.interval);
}
// private startCheckingFlaskStatus() {
// if (this.intervalId) {
// console.log("Already checking Flask status.");
// return;
// }
// this.intervalId = setInterval(() => this.checkFlaskStatus(), this.interval);
// }
// 停止轮询 Flask 服务状态
private stopCheckingFlaskStatus() {

View File

@ -81,12 +81,12 @@ export const parseDICOMFile = async (
const PatientName = dataSet.string("x00100030");
const PatientSex = dataSet.string("x00100040") ?? "";
const PatientAge = dataSet.string("x00101010") ?? "";
const pixelDataElement = dataSet.elements.x7fe00010;
const pixelData = new Uint16Array(
dataSet.byteArray.buffer,
pixelDataElement.dataOffset,
pixelDataElement.length / 2
);
// const pixelDataElement = dataSet.elements.x7fe00010;
// const pixelData = new Uint16Array(
// dataSet.byteArray.buffer,
// pixelDataElement.dataOffset,
// pixelDataElement.length / 2
// );
return {
filePath,

View File

@ -1 +0,0 @@
export const EVENT_PARSE_DICOM = "PARSE_DICOM";

View File

@ -4,10 +4,8 @@ import {
findDcmFiles,
keyProp,
processFilesInBatches,
StructuredMetadata,
structureMetadata,
} from "./core/dicom";
import { EVENT_PARSE_DICOM } from "./ipcEvent";
import PythonManager from "./core/PythonManager";
import { db } from "./core/db";
@ -27,25 +25,7 @@ const registerIpcMainHandlers = (
*/
ipcMain.on("ipc-loaded", () => mainWindow.show());
/**
* dicoM
*/
ipcMain.on(EVENT_PARSE_DICOM, async (event, file: string) => {
const dirDialog = await dialog.showOpenDialog(mainWindow, {
properties: ["openDirectory"],
});
if (dirDialog.filePaths.length > 0) {
const filePaths = await findDcmFiles(dirDialog.filePaths[0]);
const batchSize = os.cpus().length * 1 || 10;
console.time("分批处理");
const unraw = await processFilesInBatches(filePaths, batchSize);
console.timeEnd("分批处理");
const result = structureMetadata(unraw);
event.reply(EVENT_PARSE_DICOM + ":RES", result);
}
});
ipcMain.on("python-service", (event, data) => {
ipcMain.on("python-service", (_, data) => {
const { running } = data;
running ? pythonManager.startFlask() : pythonManager.stopFlask();
});
@ -91,7 +71,7 @@ const registerIpcMainHandlers = (
/**
* api
*/
ipcMain.on("db:series:select", async (event, data) => {
ipcMain.on("db:series:select", async (event) => {
await db.read();
const seriesList = db.data.series;
event.reply("db:series:select:response", seriesList);

View File

@ -6,15 +6,15 @@ import {
globalShortcut,
nativeImage,
} from "electron";
import { createRequire } from "node:module";
// import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import path from "node:path";
import registerIpcMainHandlers from "./ipcMainHandlers";
// import registerIpcMainHandlers from "./ipcMainHandlers";
import PythonManager from "./core/PythonManager";
import { createDatabase } from "./core/db";
import { getMachineId, mid } from "./core/auth";
import { getMachineId } from "./core/auth";
const require = createRequire(import.meta.url);
// const require = createRequire(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
process.env.APP_ROOT = path.join(__dirname, "..");
@ -66,8 +66,17 @@ function createWindow() {
win.loadFile(path.join(RENDERER_DIST, "index.html"));
}
pythonManager = new PythonManager(win, "http://127.0.0.1:15001", 3000);
registerIpcMainHandlers(win, pythonManager);
// pythonManager = new PythonManager(win, "http://127.0.0.1:15001", 3000);
// registerIpcMainHandlers(win, pythonManager);
// 如果有传递路径通过IPC传递给渲染进程
if (process.argv.length >= 2) {
const folderPath = process.argv[1]; // 第二个参数是文件或文件夹路径
console.log("Opened folder path:", folderPath);
// 你可以将路径发送到渲染进程
win.webContents.send("open-folder", folderPath);
}
}
function createTray() {

View File

@ -1,7 +1,7 @@
{
"name": "@cvpilot/desktop",
"private": true,
"version": "0.0.0",
"version": "1.0.0",
"type": "module",
"main": "dist-electron/main.js",
"scripts": {
@ -63,6 +63,7 @@
"node-machine-id": "1.1.12"
},
"devDependencies": {
"@types/node": "22.5.2",
"@radix-ui/react-icons": "^1.3.0",
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",

View File

@ -0,0 +1,8 @@
!macro customInstall
WriteRegStr HKCR "*\shell\cvpilot" "" "Upload dicom w&ith cvpilot"
WriteRegStr HKCR "*\shell\cvpilot" "Icon" "$INSTDIR\cvpilot.exe"
WriteRegStr HKCR "*\shell\cvpilot\command" "" '"$INSTDIR\cvpilot.exe" "upload" "%1"'
!macroend
!macro customUninstall
DeleteRegKey HKCR "*\shell\cvpilot"
!macroend

View File

@ -1,13 +1,13 @@
"use client"
"use client";
import * as React from "react"
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"
import { DayPicker } from "react-day-picker"
import * as React from "react";
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
import { DayPicker } from "react-day-picker";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
export type CalendarProps = React.ComponentProps<typeof DayPicker>
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
function Calendar({
className,
@ -50,7 +50,8 @@ function Calendar({
day_range_end: "day-range-end",
day_selected:
"bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900",
day_today: "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50",
day_today:
"bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50",
day_outside:
"day-outside text-slate-500 opacity-50 aria-selected:bg-slate-100/50 aria-selected:text-slate-500 aria-selected:opacity-30 dark:text-slate-400 dark:aria-selected:bg-slate-800/50 dark:aria-selected:text-slate-400",
day_disabled: "text-slate-500 opacity-50 dark:text-slate-400",
@ -60,13 +61,13 @@ function Calendar({
...classNames,
}}
components={{
IconLeft: ({ ...props }) => <ChevronLeftIcon className="h-4 w-4" />,
IconRight: ({ ...props }) => <ChevronRightIcon className="h-4 w-4" />,
IconLeft: () => <ChevronLeftIcon className="h-4 w-4" />,
IconRight: () => <ChevronRightIcon className="h-4 w-4" />,
}}
{...props}
/>
)
);
}
Calendar.displayName = "Calendar"
Calendar.displayName = "Calendar";
export { Calendar }
export { Calendar };

View File

@ -1,20 +1,13 @@
import { Button } from "@/components/ui/button";
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { IoCheckmarkCircleSharp } from "react-icons/io5";
const Boot = () => {
const [flaskWaiting, setFlaskWaiting] = useState(false);
const [flaskRunning, setflaskRunning] = useState(false);
const [flaskInfo, setFlaskInfo] = useState("");
const [openFolder, setOpenFolder] = useState("");
const handleBootPythonServer = () => {
if (!flaskRunning) setFlaskWaiting(true);
@ -22,7 +15,7 @@ const Boot = () => {
};
useEffect(() => {
window.ipcRenderer.on("flask-service:response", (event, data) => {
window.ipcRenderer.on("flask-service:response", (_, data) => {
console.log(data);
if (data.running) {
setflaskRunning(true);
@ -40,6 +33,13 @@ const Boot = () => {
});
}, []);
useEffect(() => {
window.ipcRenderer.on("open-folder", (_, data) => {
console.log(data);
setOpenFolder(data);
});
}, []);
return (
<motion.div
initial={{ y: 10, opacity: 0 }}
@ -50,6 +50,7 @@ const Boot = () => {
>
<div className="p-4 h-full flex flex-col">
{/* card */}
<div>{openFolder}</div>
<main className="flex-1 flex flex-col">
<div className="mt-4 flex-1">
<pre className="text-xs">{flaskInfo}</pre>

View File

@ -1,46 +0,0 @@
import React from "react";
import { Button } from "@/components/ui/button";
import { useDropzone } from "react-dropzone";
interface FileUploadProps {
onFilesSelected?: (files: File[]) => void;
}
const FileUpload: React.FC<FileUploadProps> = ({ onFilesSelected }) => {
const onDrop = (acceptedFiles: File[]) => {
console.log("Accepted files:", acceptedFiles);
if (onFilesSelected) {
onFilesSelected(acceptedFiles);
}
};
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
onDrop,
multiple: true,
accept: {
"file/dicom": [".dcm"],
"file/model": [".stl"],
},
noClick: true,
noKeyboard: true,
});
return (
<div
{...getRootProps()}
className="border-dashed border-2 p-4 py-8 rounded-md text-center cursor-pointer"
>
<input {...getInputProps({ webkitdirectory: true })} />
{isDragActive ? (
<p>/</p>
) : (
<p>/</p>
)}
<Button className="mt-2" onClick={open}>
</Button>
</div>
);
};
export default FileUpload;

View File

@ -11,7 +11,7 @@ import {
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react";
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
@ -33,7 +33,7 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useEffect, useState } from "react";
import { useState } from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
export type Series = {
@ -48,7 +48,7 @@ export type Series = {
filePaths: string[];
};
const columnsAlias: { [K in keyof Partial<Series>]: string } = {
const columnsAlias: { [K in keyof Partial<Series> as string]: string } = {
PatientName: "姓名",
PatientAge: "年龄",
PatientSex: "性别",

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Dialog,
@ -10,7 +11,7 @@ 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 { useEffect, useRef, useState } from "react";
import { useEffect, useState } from "react";
import { Series, SeriesTable } from "./SeriesTable";
import { motion } from "framer-motion";
@ -25,13 +26,16 @@ const defaultProgress = {
export const Datasource = () => {
const [progress, setProgress] = useState<ScanProgress>(defaultProgress);
const { toast } = useToast();
const [result, setResult] = useState<[]>([]);
const [, setResult] = useState<[]>([]);
const [seriesData, setSeriesData] = useState<Series[]>([]);
const [importDialogVisible, setImportDialogVisible] = useState(false);
useEffect(() => {
const handleScanProgress = (event, data) => {
const handleScanProgress = (
_event: Electron.IpcRendererEvent,
data: any
) => {
setProgress(data);
if (data.error) return;
};
@ -48,7 +52,10 @@ export const Datasource = () => {
}, []);
useEffect(() => {
const handleScanFinished = (event, data) => {
const handleScanFinished = (
_event: Electron.IpcRendererEvent,
data: any
) => {
const { scanDuration, structDicom } = data;
setResult(structDicom);
setImportDialogVisible(false);
@ -79,10 +86,6 @@ export const Datasource = () => {
};
}, [toast]);
const handleCancelImport = () => {
setImportDialogVisible(false);
};
useEffect(() => {
if (!importDialogVisible) {
setProgress(defaultProgress);
@ -94,7 +97,7 @@ export const Datasource = () => {
}, []);
useEffect(() => {
window.ipcRenderer.on("db:series:select:response", (event, data) => {
window.ipcRenderer.on("db:series:select:response", (_event, data) => {
console.log(data);
setSeriesData(data);
});

View File

@ -1,122 +0,0 @@
import {
DockviewApi,
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from "dockview";
import { useEffect, useState } from "react";
import "dockview/dist/styles/dockview.css";
import "./theme.reset.css";
const Default = (props: IDockviewPanelProps) => {
return (
<div style={{ height: "100%" }}>
<div>{props.api.title}</div>
</div>
);
};
const components = {
default: Default,
};
const Dockview = (props: { theme?: string }) => {
const [disablePanelDrag, setDisablePanelDrag] = useState<boolean>(false);
const [disableGroupDrag, setDisableGroupDrag] = useState<boolean>(false);
const [disableOverlay, setDisableOverlay] = useState<boolean>(false);
const [api, setApi] = useState<DockviewApi>();
useEffect(() => {
if (!api) return;
const disposables = [
api.onWillDragPanel((e) => {
if (!disablePanelDrag) {
return;
}
e.nativeEvent.preventDefault();
}),
api.onWillDragGroup((e) => {
if (!disableGroupDrag) {
return;
}
e.nativeEvent.preventDefault();
}),
api.onWillShowOverlay((e) => {
console.log(e);
if (!disableOverlay) {
return;
}
e.preventDefault();
}),
api.onWillDrop((e) => {
//
}),
api.onDidDrop((e) => {
//
}),
];
return () => {
disposables.forEach((disposable) => {
disposable.dispose();
});
};
}, [api, disablePanelDrag, disableGroupDrag, disableOverlay]);
const onReady = (event: DockviewReadyEvent) => {
setApi(event.api);
event.api.addPanel({
id: "panel_1",
component: "default",
});
event.api.addPanel({
id: "panel_2",
component: "default",
position: {
direction: "right",
referencePanel: "panel_1",
},
});
event.api.addPanel({
id: "panel_3",
component: "default",
position: {
direction: "below",
referencePanel: "panel_1",
},
});
event.api.addPanel({
id: "panel_4",
component: "default",
});
event.api.addPanel({
id: "panel_5",
component: "default",
});
};
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={{ flexGrow: 1 }}>
<DockviewReact
className={`${props.theme || "dockview-theme-light"}`}
onReady={onReady}
components={components}
/>
</div>
</div>
);
};
export default Dockview;

View File

@ -1,28 +0,0 @@
.dockview-theme-light {
--dv-background-color: black;
--dv-paneview-active-outline-color: dodgerblue;
--dv-tabs-and-actions-container-font-size: 13px;
--dv-tabs-and-actions-container-height: 35px;
--dv-drag-over-background-color: hsl(var(--accent));
--dv-drag-over-border-color: white;
--dv-tabs-container-scrollbar-color: #888;
--dv-icon-hover-background-color: rgba(90, 93, 94, 0.31);
--dv-floating-box-shadow: 8px 8px 8px 0px rgba(83, 89, 93, 0.5);
--dv-group-view-background-color: white;
--dv-tabs-and-actions-container-background-color: #f3f3f3;
--dv-activegroup-visiblepanel-tab-background-color: white;
--dv-activegroup-hiddenpanel-tab-background-color: #ececec;
--dv-inactivegroup-visiblepanel-tab-background-color: white;
--dv-inactivegroup-hiddenpanel-tab-background-color: #ececec;
--dv-tab-divider-color: white;
--dv-activegroup-visiblepanel-tab-color: rgb(51, 51, 51);
--dv-activegroup-hiddenpanel-tab-color: rgba(51, 51, 51, 0.7);
--dv-inactivegroup-visiblepanel-tab-color: rgba(51, 51, 51, 0.7);
--dv-inactivegroup-hiddenpanel-tab-color: rgba(51, 51, 51, 0.35);
--dv-separator-border: hsl(var(--border));
--dv-paneview-header-border-color: rgb(51, 51, 51);
}
.tabs-container .tab{
border-radius: 5px 5px 0 0;
}

View File

@ -2,8 +2,6 @@ import { Link, useLocation } from "react-router-dom";
import {
IoCubeOutline,
IoHammerOutline,
IoHandLeftOutline,
IoLayersOutline,
IoListOutline,
IoPlayOutline,
IoSettingsOutline,

View File

@ -13,24 +13,11 @@ import {
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar";
import { EVENT_PARSE_DICOM } from "../../electron/ipcEvent";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
export const MenuBar = () => {
const navigate = useNavigate();
useEffect(() => {
window.ipcRenderer.on(EVENT_PARSE_DICOM + ":RES", (event, data) => {
console.log(data);
if (data.error) return;
});
return () => {
window.ipcRenderer.off(EVENT_PARSE_DICOM + ":RES", () => {});
};
}, []);
const handleImportDicom = () => {
navigate("/datasource");
window.ipcRenderer.send("import-dicom-dialog-visible");

View File

@ -18,7 +18,6 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
@ -251,7 +250,9 @@ export function ModelTable() {
<div className="flex-shrink-0 flex items-center justify-between p-4">
<Input
placeholder="根据名称查询模型"
value={(table.getColumn("modelname")?.getFilterValue() as string) ?? ""}
value={
(table.getColumn("modelname")?.getFilterValue() as string) ?? ""
}
onChange={(event) =>
table.getColumn("modelname")?.setFilterValue(event.target.value)
}

View File

@ -10,7 +10,6 @@ import {
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import {
Select,
@ -20,8 +19,6 @@ import {
SelectValue,
} from "@/components/ui/select";
import { toast } from "@/components/ui/use-toast";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
const FormSchema = z.object({
inferEngine: z.string({

View File

@ -1,5 +1,3 @@
import React from "react";
export const Tools = () => {
return <div>Tools</div>;
};

View File

@ -7,5 +7,7 @@
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
"include": [
"vite.config.ts"
]
}

View File

@ -164,6 +164,9 @@ importers:
'@radix-ui/react-icons':
specifier: ^1.3.0
version: 1.3.0(react@18.3.1)
'@types/node':
specifier: 22.5.2
version: 22.5.2
'@types/react':
specifier: ^18.2.64
version: 18.3.4
@ -178,7 +181,7 @@ importers:
version: 7.18.0(eslint@8.57.0)(typescript@5.5.4)
'@vitejs/plugin-react':
specifier: ^4.2.1
version: 4.3.1(vite@5.4.2(@types/node@22.5.1))
version: 4.3.1(vite@5.4.2(@types/node@22.5.2))
autoprefixer:
specifier: ^10.4.19
version: 10.4.20(postcss@8.4.41)
@ -208,7 +211,7 @@ importers:
version: 5.5.4
vite:
specifier: ^5.1.6
version: 5.4.2(@types/node@22.5.1)
version: 5.4.2(@types/node@22.5.2)
vite-plugin-electron:
specifier: ^0.28.6
version: 0.28.7(vite-plugin-electron-renderer@0.14.5)
@ -1506,8 +1509,8 @@ packages:
'@types/node@20.16.2':
resolution: {integrity: sha512-91s/n4qUPV/wg8eE9KHYW1kouTfDk2FPGjXbBMfRWP/2vg1rCXNQL1OCabwGs0XSdukuK+MwCDXE30QpSeMUhQ==}
'@types/node@22.5.1':
resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==}
'@types/node@22.5.2':
resolution: {integrity: sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==}
'@types/plist@3.0.5':
resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==}
@ -5422,7 +5425,7 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/responselike': 1.0.3
'@types/caseless@0.12.5': {}
@ -5433,19 +5436,19 @@ snapshots:
'@types/duplexify@3.6.4':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/estree@1.0.5': {}
'@types/fs-extra@9.0.13':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/http-cache-semantics@4.0.4': {}
'@types/keyv@3.1.4':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/long@4.0.2': {}
@ -5455,13 +5458,13 @@ snapshots:
dependencies:
undici-types: 6.19.8
'@types/node@22.5.1':
'@types/node@22.5.2':
dependencies:
undici-types: 6.19.8
'@types/plist@3.0.5':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
xmlbuilder: 15.1.1
optional: true
@ -5470,7 +5473,7 @@ snapshots:
'@types/pumpify@1.4.4':
dependencies:
'@types/duplexify': 3.6.4
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/react-dom@18.3.0':
dependencies:
@ -5490,13 +5493,13 @@ snapshots:
'@types/request@2.48.12':
dependencies:
'@types/caseless': 0.12.5
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/tough-cookie': 4.0.5
form-data: 2.5.1
'@types/responselike@1.0.3':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
'@types/stack-trace@0.0.33': {}
@ -5507,7 +5510,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
optional: true
'@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)':
@ -5593,14 +5596,14 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-react@4.3.1(vite@5.4.2(@types/node@22.5.1))':
'@vitejs/plugin-react@4.3.1(vite@5.4.2(@types/node@22.5.2))':
dependencies:
'@babel/core': 7.25.2
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2)
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 5.4.2(@types/node@22.5.1)
vite: 5.4.2(@types/node@22.5.2)
transitivePeerDependencies:
- supports-color
@ -7404,7 +7407,7 @@ snapshots:
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/long': 4.0.2
'@types/node': 22.5.1
'@types/node': 22.5.2
long: 4.0.0
protobufjs@7.4.0:
@ -7419,7 +7422,7 @@ snapshots:
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 22.5.1
'@types/node': 22.5.2
long: 5.2.3
pump@2.0.1:
@ -8400,13 +8403,13 @@ snapshots:
optionalDependencies:
vite-plugin-electron-renderer: 0.14.5
vite@5.4.2(@types/node@22.5.1):
vite@5.4.2(@types/node@22.5.2):
dependencies:
esbuild: 0.21.5
postcss: 8.4.41
rollup: 4.21.1
optionalDependencies:
'@types/node': 22.5.1
'@types/node': 22.5.2
fsevents: 2.3.3
webidl-conversions@3.0.1: {}