diff --git a/apps/desktop/src/main/index.ts b/apps/desktop/src/main/index.ts index 976d45b3982..9a712e2cdb2 100644 --- a/apps/desktop/src/main/index.ts +++ b/apps/desktop/src/main/index.ts @@ -1,13 +1,25 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { settings } from "@superset/local-db"; -import { app, BrowserWindow, dialog, net, protocol, session } from "electron"; +import { + app, + BrowserWindow, + dialog, + Notification, + net, + protocol, + session, +} from "electron"; import { makeAppSetup } from "lib/electron-app/factories/app/setup"; import { handleAuthCallback, parseAuthDeepLink, } from "lib/trpc/routers/auth/utils/auth-functions"; -import { DEFAULT_CONFIRM_ON_QUIT, PROTOCOL_SCHEME } from "shared/constants"; +import { + DEFAULT_CONFIRM_ON_QUIT, + PLATFORM, + PROTOCOL_SCHEME, +} from "shared/constants"; import { getWorkspaceName } from "shared/env.shared"; import { setupAgentHooks } from "./lib/agent-setup"; import { initAppState } from "./lib/app-state"; @@ -82,6 +94,33 @@ function focusMainWindow(): void { } } +function registerWithMacOSNotificationCenter() { + if (!PLATFORM.IS_MAC || !Notification.isSupported()) return; + + const registrationNotification = new Notification({ + title: app.name, + body: " ", + silent: true, + }); + + let handled = false; + const cleanup = () => { + if (handled) return; + handled = true; + registrationNotification.close(); + }; + + registrationNotification.on("show", () => { + cleanup(); + console.log("[notifications] Registered with Notification Center"); + }); + + // Fallback timeout in case macOS doesn't fire events + setTimeout(cleanup, 1000); + + registrationNotification.show(); +} + // macOS open-url can fire before the window exists (cold-start via protocol link). // Queue the URL and process it after initialization. let pendingDeepLinkUrl: string | null = null; @@ -217,6 +256,7 @@ if (!gotTheLock) { (async () => { await app.whenReady(); + registerWithMacOSNotificationCenter(); // Must register on both default session and the app's custom partition const iconProtocolHandler = (request: Request) => {