feat(desktop): implement workspace foundation + desktop-client skeleton
Plan 0 (workspaces): add workspaces + workspace_memberships schema, extend JWT/Actor/claims with primary_workspace_id, seed default workspace per tenant, thread workspace_id through tenant monitoring quota. Plan A (desktop skeleton): new Electron app (apps/desktop-client) with main/ preload/renderer, shared Vue component package (packages/ui-shared), and server surface — desktop client registration + token rotation + heartbeat, SSE task event stream, desktop accounts/tasks/content handlers, publish job endpoint, and supporting repositories, services, sqlc queries, and migrations. Hard cutover per plan: remove browser-extension monitoring callback endpoints, stub legacy media API in admin-web, and delete monitoring_callback_handler.go.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { BrowserWindow, nativeTheme } from "electron/main";
|
||||
import type { Session } from "electron/main";
|
||||
|
||||
import { attachWindowDiagnostics, loadWindowURLSafely } from "./external-window";
|
||||
|
||||
interface ReviewWindowRecord {
|
||||
taskId: string;
|
||||
window: BrowserWindow;
|
||||
}
|
||||
|
||||
const reviewWindows = new Map<string, ReviewWindowRecord>();
|
||||
|
||||
export async function openReviewWindow(options: {
|
||||
taskId: string;
|
||||
title: string;
|
||||
url: string;
|
||||
session: Session;
|
||||
}): Promise<void> {
|
||||
const existing = reviewWindows.get(options.taskId);
|
||||
if (existing && !existing.window.isDestroyed()) {
|
||||
existing.window.show();
|
||||
existing.window.focus();
|
||||
if (existing.window.webContents.getURL() !== options.url) {
|
||||
await loadWindowURLSafely(existing.window, options.url, options.title);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
width: 1440,
|
||||
height: 960,
|
||||
minWidth: 1120,
|
||||
minHeight: 760,
|
||||
title: options.title,
|
||||
autoHideMenuBar: true,
|
||||
backgroundColor: nativeTheme.shouldUseDarkColors ? "#15191a" : "#f4f1ea",
|
||||
webPreferences: {
|
||||
session: options.session,
|
||||
sandbox: true,
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
},
|
||||
});
|
||||
|
||||
attachWindowDiagnostics(window, options.title);
|
||||
reviewWindows.set(options.taskId, { taskId: options.taskId, window });
|
||||
window.on("closed", () => {
|
||||
reviewWindows.delete(options.taskId);
|
||||
});
|
||||
|
||||
await loadWindowURLSafely(window, options.url, options.title);
|
||||
window.show();
|
||||
window.focus();
|
||||
}
|
||||
Reference in New Issue
Block a user