style(desktop): format gitnexus-desktop package

This commit is contained in:
Sparsh 2026-04-20 10:13:29 +05:30
parent 6c644e3b17
commit 21fb1b9a0c
13 changed files with 147 additions and 75 deletions

View file

@ -51,4 +51,4 @@ linux:
- AppImage
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
allowToChangeInstallationDirectory: true

View file

@ -45,4 +45,4 @@ export default {
},
},
},
};
};

View file

@ -34,4 +34,4 @@
"typescript": "^6.0.3",
"vite": "^7.0.0"
}
}
}

View file

@ -129,7 +129,9 @@ const ensureDesktopRendererPortAvailable = () => {
process.exit(1);
}
console.info(`Stopping stale desktop renderer process on port ${desktopRendererPort} (PID ${owner.pid}).`);
console.info(
`Stopping stale desktop renderer process on port ${desktopRendererPort} (PID ${owner.pid}).`,
);
killProcessTree(owner.pid);
};

View file

@ -11,18 +11,32 @@ const workspaceRoot = path.resolve(packageRoot, '..');
const gitnexusRoot = path.join(workspaceRoot, 'gitnexus');
const gitnexusWebRoot = path.join(workspaceRoot, 'gitnexus-web');
const releaseRoot = path.join(packageRoot, 'release');
const desktopPackageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
const desktopPackageLock = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package-lock.json'), 'utf8'));
const electronVersion = desktopPackageJson.devDependencies?.electron?.replace(/^[^\d]*/, '') ?? '41.2.1';
const electronBuilderVersion = desktopPackageJson.devDependencies?.['electron-builder']?.replace(/^[^\d]*/, '') ?? '26.8.1';
const desktopPackageJson = JSON.parse(
fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
);
const desktopPackageLock = JSON.parse(
fs.readFileSync(path.join(packageRoot, 'package-lock.json'), 'utf8'),
);
const electronVersion =
desktopPackageJson.devDependencies?.electron?.replace(/^[^\d]*/, '') ?? '41.2.1';
const electronBuilderVersion =
desktopPackageJson.devDependencies?.['electron-builder']?.replace(/^[^\d]*/, '') ?? '26.8.1';
const appBuilderLibVersion =
desktopPackageLock.packages?.['node_modules/app-builder-lib']?.version ?? electronBuilderVersion.replace(/^[^\d]*/, '');
desktopPackageLock.packages?.['node_modules/app-builder-lib']?.version ??
electronBuilderVersion.replace(/^[^\d]*/, '');
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
const outputDir = path.join(releaseRoot, stamp);
const generatedBuilderConfigPath = path.join(outputDir, 'electron-builder.generated.json');
const requiredNsisTemplateFiles = [
path.join(packageRoot, 'node_modules', 'app-builder-lib', 'templates', 'nsis', 'messages.yml'),
path.join(packageRoot, 'node_modules', 'app-builder-lib', 'templates', 'nsis', 'assistedMessages.yml'),
path.join(
packageRoot,
'node_modules',
'app-builder-lib',
'templates',
'nsis',
'assistedMessages.yml',
),
];
const supportedTargetHosts = {
'--linux': 'linux',
@ -142,7 +156,9 @@ const overlayDirectoryContents = (sourceDirectory, destinationDirectory) => {
};
const repairAppBuilderLibPackage = () => {
const repairDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-desktop-app-builder-lib-'));
const repairDirectory = fs.mkdtempSync(
path.join(os.tmpdir(), 'gitnexus-desktop-app-builder-lib-'),
);
try {
const tarballName = `app-builder-lib-${appBuilderLibVersion}.tgz`;
@ -150,7 +166,10 @@ const repairAppBuilderLibPackage = () => {
const extractedPackageRoot = path.join(repairDirectory, 'package');
const installedPackageRoot = path.join(packageRoot, 'node_modules', 'app-builder-lib');
runCommand(`npm pack app-builder-lib@${appBuilderLibVersion} --pack-destination "${repairDirectory}"`, packageRoot);
runCommand(
`npm pack app-builder-lib@${appBuilderLibVersion} --pack-destination "${repairDirectory}"`,
packageRoot,
);
runCommand(`tar -xzf "${tarballPath}" -C "${repairDirectory}"`, packageRoot);
overlayDirectoryContents(extractedPackageRoot, installedPackageRoot);
} finally {
@ -159,7 +178,9 @@ const repairAppBuilderLibPackage = () => {
};
const assertSupportedHostForRequestedTargets = () => {
const unsupportedTargets = requestedTargets.filter((target) => supportedTargetHosts[target] !== process.platform);
const unsupportedTargets = requestedTargets.filter(
(target) => supportedTargetHosts[target] !== process.platform,
);
if (unsupportedTargets.length === 0) {
return;
@ -185,13 +206,17 @@ const ensureDesktopToolchainHealthy = () => {
return;
}
const missingNsisTemplates = requiredNsisTemplateFiles.filter((filePath) => !fs.existsSync(filePath));
const missingNsisTemplates = requiredNsisTemplateFiles.filter(
(filePath) => !fs.existsSync(filePath),
);
if (missingNsisTemplates.length === 0) {
return;
}
console.warn('[build] electron-builder NSIS templates are missing. Restoring app-builder-lib package contents first...');
console.warn(
'[build] electron-builder NSIS templates are missing. Restoring app-builder-lib package contents first...',
);
try {
repairAppBuilderLibPackage();
@ -203,7 +228,9 @@ const ensureDesktopToolchainHealthy = () => {
return;
}
console.warn('[build] Package overlay repair was not enough. Reinstalling electron-builder next...');
console.warn(
'[build] Package overlay repair was not enough. Reinstalling electron-builder next...',
);
const targetedRepairWorked = tryRunCommand(
`npm install --no-save --package-lock=false electron-builder@${electronBuilderVersion}`,
@ -218,7 +245,9 @@ const ensureDesktopToolchainHealthy = () => {
runCommand('npm ci', packageRoot);
}
const unresolvedTemplates = requiredNsisTemplateFiles.filter((filePath) => !fs.existsSync(filePath));
const unresolvedTemplates = requiredNsisTemplateFiles.filter(
(filePath) => !fs.existsSync(filePath),
);
if (unresolvedTemplates.length > 0) {
throw new Error(
@ -275,4 +304,4 @@ if (artifacts.length > 0) {
for (const artifact of artifacts) {
console.log(` - ${artifact}`);
}
}
}

View file

@ -209,7 +209,11 @@ const isAnyHttpUrlReady = async (urls: string[], expectedMarkers?: string[]): Pr
return false;
};
const waitForUrlReady = async (url: string, timeoutMs: number, expectedMarkers?: string[]): Promise<void> => {
const waitForUrlReady = async (
url: string,
timeoutMs: number,
expectedMarkers?: string[],
): Promise<void> => {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
@ -250,18 +254,26 @@ const getGitNexusWebDevRoot = (): string => {
};
const getNodeCommand = (): string => {
return process.env.npm_node_execpath || process.env.NODE || (process.platform === 'win32' ? 'node.exe' : 'node');
return (
process.env.npm_node_execpath ||
process.env.NODE ||
(process.platform === 'win32' ? 'node.exe' : 'node')
);
};
const spawnGitNexusServer = (): ChildProcess => {
const childProcess = spawn(getNodeCommand(), [getGitNexusCliEntry(), 'serve', '--host', GITNEXUS_HOST], {
cwd: getGitNexusRuntimeDir(),
env: {
...process.env,
const childProcess = spawn(
getNodeCommand(),
[getGitNexusCliEntry(), 'serve', '--host', GITNEXUS_HOST],
{
cwd: getGitNexusRuntimeDir(),
env: {
...process.env,
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
},
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
});
);
childProcess.stdout?.on('data', (chunk) => {
appendGitNexusServerOutput(chunk);
@ -312,8 +324,22 @@ const spawnWebDevServer = (): ChildProcess => {
const command = process.platform === 'win32' ? 'cmd.exe' : 'npm';
const args =
process.platform === 'win32'
? ['/d', '/s', '/c', `npm run dev -- --host ${GITNEXUS_WEB_DEV_HOST} --port ${GITNEXUS_WEB_DEV_PORT} --strictPort`]
: ['run', 'dev', '--', '--host', GITNEXUS_WEB_DEV_HOST, '--port', String(GITNEXUS_WEB_DEV_PORT), '--strictPort'];
? [
'/d',
'/s',
'/c',
`npm run dev -- --host ${GITNEXUS_WEB_DEV_HOST} --port ${GITNEXUS_WEB_DEV_PORT} --strictPort`,
]
: [
'run',
'dev',
'--',
'--host',
GITNEXUS_WEB_DEV_HOST,
'--port',
String(GITNEXUS_WEB_DEV_PORT),
'--strictPort',
];
const childProcess = spawn(command, args, {
cwd: getGitNexusWebDevRoot(),
@ -352,7 +378,11 @@ const ensureWebDevServerStarted = async (): Promise<void> => {
webDevServerProcess = spawnWebDevServer();
}
await waitForUrlReady(GITNEXUS_WEB_DEV_URL, GITNEXUS_WEB_READY_TIMEOUT_MS, GITNEXUS_WEB_EXPECTED_MARKERS);
await waitForUrlReady(
GITNEXUS_WEB_DEV_URL,
GITNEXUS_WEB_READY_TIMEOUT_MS,
GITNEXUS_WEB_EXPECTED_MARKERS,
);
};
const normalizeStaticPath = (rootDir: string, requestPath: string): string | null => {
@ -454,7 +484,11 @@ const stopWebDevServer = (): void => {
};
const stopGitNexusServer = (): void => {
if (!gitNexusServerProcess || !gitNexusServerProcess.pid || gitNexusServerProcess.exitCode !== null) {
if (
!gitNexusServerProcess ||
!gitNexusServerProcess.pid ||
gitNexusServerProcess.exitCode !== null
) {
return;
}
@ -559,7 +593,9 @@ const createEmbeddedContentView = (contentUrl: string): BrowserView => {
contentView.webContents.on('dom-ready', () => {
void contentView.webContents.insertCSS(EMBEDDED_APP_SCROLLBAR_CSS).catch((error) => {
console.warn(`[gitnexus-desktop] Failed to inject embedded app CSS: ${getErrorMessage(error)}`);
console.warn(
`[gitnexus-desktop] Failed to inject embedded app CSS: ${getErrorMessage(error)}`,
);
});
});
@ -761,4 +797,4 @@ app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
});

View file

@ -7,47 +7,50 @@ const DESKTOP_WINDOW_STATE_CHANGED_CHANNEL = 'gitnexus-desktop:window-state-chan
const DESKTOP_SHELL_TITLEBAR_HEIGHT = process.platform === 'darwin' ? 38 : 0;
type DesktopShellState = {
appName: string;
isAlwaysOnTop: boolean;
isMaximized: boolean;
platform: NodeJS.Platform;
titleBarHeight: number;
appName: string;
isAlwaysOnTop: boolean;
isMaximized: boolean;
platform: NodeJS.Platform;
titleBarHeight: number;
};
type DesktopWindowAction = 'close' | 'minimize' | 'toggle-always-on-top' | 'toggle-maximize';
const invokeWindowAction = (action: DesktopWindowAction): Promise<DesktopShellState | null> => {
return ipcRenderer.invoke(DESKTOP_WINDOW_ACTION_CHANNEL, action) as Promise<DesktopShellState | null>;
return ipcRenderer.invoke(
DESKTOP_WINDOW_ACTION_CHANNEL,
action,
) as Promise<DesktopShellState | null>;
};
contextBridge.exposeInMainWorld('gitnexusDesktop', {
appName: DESKTOP_APP_NAME,
platform: process.platform,
titleBarHeight: DESKTOP_SHELL_TITLEBAR_HEIGHT,
close: async (): Promise<void> => {
await invokeWindowAction('close');
},
getShellState: (): Promise<DesktopShellState> => {
return ipcRenderer.invoke(DESKTOP_GET_SHELL_STATE_CHANNEL) as Promise<DesktopShellState>;
},
minimize: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('minimize');
},
onWindowStateChanged: (callback: (state: DesktopShellState) => void): (() => void) => {
const listener = (_event: IpcRendererEvent, state: DesktopShellState): void => {
callback(state);
};
appName: DESKTOP_APP_NAME,
platform: process.platform,
titleBarHeight: DESKTOP_SHELL_TITLEBAR_HEIGHT,
close: async (): Promise<void> => {
await invokeWindowAction('close');
},
getShellState: (): Promise<DesktopShellState> => {
return ipcRenderer.invoke(DESKTOP_GET_SHELL_STATE_CHANNEL) as Promise<DesktopShellState>;
},
minimize: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('minimize');
},
onWindowStateChanged: (callback: (state: DesktopShellState) => void): (() => void) => {
const listener = (_event: IpcRendererEvent, state: DesktopShellState): void => {
callback(state);
};
ipcRenderer.on(DESKTOP_WINDOW_STATE_CHANGED_CHANNEL, listener);
ipcRenderer.on(DESKTOP_WINDOW_STATE_CHANGED_CHANNEL, listener);
return () => {
ipcRenderer.removeListener(DESKTOP_WINDOW_STATE_CHANGED_CHANNEL, listener);
};
},
toggleAlwaysOnTop: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('toggle-always-on-top');
},
toggleMaximize: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('toggle-maximize');
},
});
return () => {
ipcRenderer.removeListener(DESKTOP_WINDOW_STATE_CHANGED_CHANNEL, listener);
};
},
toggleAlwaysOnTop: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('toggle-always-on-top');
},
toggleMaximize: (): Promise<DesktopShellState | null> => {
return invokeWindowAction('toggle-maximize');
},
});

View file

@ -40,7 +40,8 @@ const fallbackDesktopApi: DesktopApi = {
toggleMaximize: async () => defaultDesktopState,
};
const desktopApi = (window as Window & { gitnexusDesktop?: DesktopApi }).gitnexusDesktop ?? fallbackDesktopApi;
const desktopApi =
(window as Window & { gitnexusDesktop?: DesktopApi }).gitnexusDesktop ?? fallbackDesktopApi;
const styles = `
:root {
@ -352,4 +353,4 @@ export default function App() {
</div>
</>
);
}
}

View file

@ -44,7 +44,8 @@ const fallbackDesktopApi: DesktopApi = {
toggleMaximize: async () => defaultDesktopState,
};
const desktopApi = (window as Window & { gitnexusDesktop?: DesktopApi }).gitnexusDesktop ?? fallbackDesktopApi;
const desktopApi =
(window as Window & { gitnexusDesktop?: DesktopApi }).gitnexusDesktop ?? fallbackDesktopApi;
const shellState: DesktopShellState = {
...defaultDesktopState,
@ -203,4 +204,4 @@ void desktopApi.getShellState().then((state) => {
desktopApi.onWindowStateChanged((state) => {
applyShellState(state);
});
});

View file

@ -19,4 +19,4 @@ body {
font-size: 2rem;
font-weight: 600;
letter-spacing: 0.04em;
}
}

View file

@ -12,4 +12,4 @@
"path": "./tsconfig.renderer.json"
}
]
}
}

View file

@ -15,4 +15,4 @@
"noEmit": true
},
"include": ["electron.vite.config.ts", "src/main/**/*.ts"]
}
}

View file

@ -18,4 +18,4 @@
"types": ["vite/client"]
},
"include": ["src/renderer/src/main.tsx"]
}
}