feat: build with nsis
This commit is contained in:
parent
2caf55facc
commit
097a89ca37
|
@ -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}",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export const EVENT_PARSE_DICOM = "PARSE_DICOM";
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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",
|
||||
|
|
8
apps/desktop/scripts/installer.nsh
Normal file
8
apps/desktop/scripts/installer.nsh
Normal 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
|
|
@ -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 };
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
|
@ -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: "性别",
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -2,8 +2,6 @@ import { Link, useLocation } from "react-router-dom";
|
|||
import {
|
||||
IoCubeOutline,
|
||||
IoHammerOutline,
|
||||
IoHandLeftOutline,
|
||||
IoLayersOutline,
|
||||
IoListOutline,
|
||||
IoPlayOutline,
|
||||
IoSettingsOutline,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import React from "react";
|
||||
|
||||
export const Tools = () => {
|
||||
return <div>Tools</div>;
|
||||
};
|
||||
|
|
|
@ -7,5 +7,7 @@
|
|||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
|
@ -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: {}
|
||||
|
|
Loading…
Reference in New Issue
Block a user