v1.6.0 #221
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Read(/C:\\Users\\29037\\WebstormProjects\\Termix\\docker/**)",
|
||||
"Bash(git fetch:*)",
|
||||
"Bash(git pull:*)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(git branch:*)",
|
||||
"Bash(npm run build:*)",
|
||||
"Bash(npm install)",
|
||||
"Bash(npm run electron:build:*)",
|
||||
"Bash(npm uninstall:*)",
|
||||
"Bash(git remote set-url:*)",
|
||||
"Bash(npm run dev:backend:*)",
|
||||
"Bash(taskkill:*)",
|
||||
"Bash(node:*)",
|
||||
"WebFetch(domain:ui.shadcn.com)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,3 +24,4 @@ dist-ssr
|
||||
*.sw?
|
||||
/db/
|
||||
/release/
|
||||
/.claude/
|
||||
|
||||
35
build-electron.js
Normal file
35
build-electron.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Check if we're in a path with spaces
|
||||
const currentPath = process.cwd();
|
||||
if (currentPath.includes(' ')) {
|
||||
console.log('⚠️ Warning: Project path contains spaces which may cause issues with native modules.');
|
||||
console.log('Current path:', currentPath);
|
||||
console.log('Consider moving the project to a path without spaces for better compatibility.');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Set environment variables to help with native module compilation
|
||||
process.env.npm_config_cache = path.join(process.cwd(), 'node_modules', '.cache');
|
||||
process.env.npm_config_tmp = path.join(process.cwd(), 'node_modules', '.tmp');
|
||||
|
||||
console.log('Building Electron application...');
|
||||
|
||||
// Skip better-sqlite3 rebuild due to path issues
|
||||
console.log('Skipping better-sqlite3 rebuild due to path space issues...');
|
||||
console.log('Note: Using existing better-sqlite3 installation.');
|
||||
|
||||
// Run the electron-builder
|
||||
try {
|
||||
execSync('npx electron-builder', { stdio: 'inherit' });
|
||||
console.log('✅ Electron build completed successfully!');
|
||||
} catch (error) {
|
||||
console.error('❌ Electron build failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -6,18 +6,23 @@
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"electron/**/*"
|
||||
"electron/**/*",
|
||||
"public/**/*",
|
||||
"!**/node_modules/**/*",
|
||||
"!src/**/*",
|
||||
"!*.md",
|
||||
"!tsconfig*.json",
|
||||
"!vite.config.ts",
|
||||
"!eslint.config.js"
|
||||
],
|
||||
"extraMetadata": {
|
||||
"main": "electron/main-simple.cjs"
|
||||
},
|
||||
"buildDependenciesFromSource": false,
|
||||
"nodeGypRebuild": false,
|
||||
"npmRebuild": false,
|
||||
"mac": {
|
||||
"category": "public.app-category.developer-tools",
|
||||
"icon": "public/icon.icns",
|
||||
"hardenedRuntime": true,
|
||||
"gatekeeperAssess": false,
|
||||
"entitlements": "build/entitlements.mac.plist",
|
||||
"entitlementsInherit": "build/entitlements.mac.plist",
|
||||
"target": [
|
||||
{
|
||||
"target": "dmg",
|
||||
@@ -31,7 +36,7 @@
|
||||
},
|
||||
"win": {
|
||||
"target": "nsis",
|
||||
"icon": "public/icon.ico"
|
||||
"forceCodeSigning": false
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
|
||||
@@ -16,27 +16,68 @@ function startBackendServer() {
|
||||
return;
|
||||
}
|
||||
|
||||
const backendPath = path.join(__dirname, '../dist/backend/starter.js');
|
||||
// 在打包环境中,后端文件在 resources/app/dist/backend/backend/ 目录下
|
||||
const backendPath = isDev
|
||||
? path.join(__dirname, '../dist/backend/starter.js')
|
||||
: path.join(process.resourcesPath, 'app', 'dist', 'backend', 'backend', 'starter.js');
|
||||
|
||||
console.log('Starting backend server from:', backendPath);
|
||||
console.log('Working directory:', process.cwd());
|
||||
|
||||
// 设置环境变量
|
||||
const env = {
|
||||
...process.env,
|
||||
NODE_ENV: 'production',
|
||||
DATA_PATH: app.getPath('userData'),
|
||||
DB_PATH: path.join(app.getPath('userData'), 'database.db'),
|
||||
VERSION: app.getVersion()
|
||||
};
|
||||
|
||||
// 检查文件是否存在
|
||||
const fs = require('fs');
|
||||
if (!fs.existsSync(backendPath)) {
|
||||
console.error('Backend file not found at:', backendPath);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Backend file exists, starting process...');
|
||||
console.log('Environment variables:', env);
|
||||
|
||||
backendProcess = spawn('node', [backendPath], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
cwd: path.join(__dirname, '..') // Set working directory to app root
|
||||
cwd: isDev ? path.join(__dirname, '..') : process.resourcesPath,
|
||||
env: env
|
||||
});
|
||||
|
||||
backendProcess.stdout.on('data', (data) => {
|
||||
console.log('Backend:', data.toString());
|
||||
console.log('Backend stdout:', data.toString());
|
||||
});
|
||||
|
||||
backendProcess.stderr.on('data', (data) => {
|
||||
console.error('Backend Error:', data.toString());
|
||||
console.error('Backend stderr:', data.toString());
|
||||
});
|
||||
|
||||
backendProcess.on('close', (code) => {
|
||||
console.log(`Backend process exited with code ${code}`);
|
||||
backendProcess = null;
|
||||
});
|
||||
|
||||
backendProcess.on('error', (error) => {
|
||||
console.error('Failed to start backend process:', error);
|
||||
console.error('Error details:', error.message);
|
||||
console.error('Error code:', error.code);
|
||||
backendProcess = null;
|
||||
});
|
||||
|
||||
// 等待一下看看进程是否启动成功
|
||||
setTimeout(() => {
|
||||
if (backendProcess && !backendProcess.killed) {
|
||||
console.log('Backend process appears to be running');
|
||||
} else {
|
||||
console.error('Backend process failed to start or died immediately');
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 停止后端服务
|
||||
@@ -144,12 +185,29 @@ ipcMain.handle('get-platform', () => {
|
||||
return process.platform;
|
||||
});
|
||||
|
||||
// 应用事件处理
|
||||
app.whenReady().then(() => {
|
||||
// 在生产环境启动后端服务
|
||||
if (!isDev) {
|
||||
ipcMain.handle('get-backend-port', () => {
|
||||
return 8081; // 后端服务端口
|
||||
});
|
||||
|
||||
ipcMain.handle('restart-backend', async () => {
|
||||
try {
|
||||
stopBackendServer();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒
|
||||
startBackendServer();
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
// 应用事件处理
|
||||
app.whenReady().then(async () => {
|
||||
// 启动后端服务
|
||||
startBackendServer();
|
||||
|
||||
// 等待后端服务启动
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
createWindow();
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// 获取平台信息
|
||||
getPlatform: () => ipcRenderer.invoke('get-platform'),
|
||||
|
||||
// 获取后端端口
|
||||
getBackendPort: () => ipcRenderer.invoke('get-backend-port'),
|
||||
|
||||
// 重启后端服务
|
||||
restartBackend: () => ipcRenderer.invoke('restart-backend'),
|
||||
|
||||
// 环境检测
|
||||
isElectron: true,
|
||||
isDev: process.env.NODE_ENV === 'development',
|
||||
|
||||
5449
package-lock.json
generated
5449
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"name": "termix",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "1.6.0",
|
||||
"description": "A web-based server management platform with SSH terminal, tunneling, and file editing capabilities",
|
||||
"author": "Karmaa",
|
||||
"main": "electron/main-simple.cjs",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,7 +12,12 @@
|
||||
"build:backend": "tsc -p tsconfig.node.json",
|
||||
"dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/backend/starter.js",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"electron": "electron .",
|
||||
"electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:5173 && electron .\"",
|
||||
"electron:build": "npm run build && npm run build:backend && electron-builder --dir",
|
||||
"electron:build-win": "npm run build && npm run build:backend && electron-builder --win --dir",
|
||||
"electron:pack": "npm run build && npm run build:backend && electron-packager . Termix --platform=all --arch=x64,arm64 --out=release --overwrite"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
@@ -97,6 +105,10 @@
|
||||
"@types/ws": "^8.18.1",
|
||||
"@vitejs/plugin-react-swc": "^3.10.2",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"concurrently": "^9.2.1",
|
||||
"electron": "^38.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-packager": "^17.1.2",
|
||||
"eslint": "^9.34.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
@@ -105,6 +117,7 @@
|
||||
"tw-animate-css": "^1.3.5",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript-eslint": "^8.40.0",
|
||||
"vite": "^7.1.5"
|
||||
"vite": "^7.1.5",
|
||||
"wait-on": "^8.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,13 +537,12 @@ export function LeftSidebar({
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex-1"
|
||||
className="flex-1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setDeleteAccountOpen(false);
|
||||
setDeletePassword("");
|
||||
setDeleteError(null);
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -152,7 +152,7 @@ export const Terminal = forwardRef<any, SSHTerminalProps>(function SSHTerminal(
|
||||
scrollback: 10000,
|
||||
fontSize: 14,
|
||||
fontFamily: '"JetBrains Mono Nerd Font", "MesloLGS NF", "FiraCode Nerd Font", "Cascadia Code", "JetBrains Mono", Consolas, "Courier New", monospace',
|
||||
theme: {background: 'var(--color-dark-bg-darkest)', foreground: '#f7f7f7'},
|
||||
theme: {background: '#09090b', foreground: '#f7f7f7'},
|
||||
allowTransparency: true,
|
||||
convertEol: true,
|
||||
windowsMode: false,
|
||||
|
||||
@@ -742,7 +742,7 @@ export function HomepageAuth({
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="password">{t('common.password')}</Label>
|
||||
<PasswordInput id="password" required className="h-55 text-base"
|
||||
<PasswordInput id="password" required className="h-11 text-base"
|
||||
value={password} onChange={e => setPassword(e.target.value)}
|
||||
disabled={loading || internalLoggedIn}/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user