Files
kandev/apps/web/components/desktop-command-host.tsx
2026-09-25 18:07:55 +01:00

134 lines
4.0 KiB
TypeScript

"use client";
import { useEffect, useMemo } from "react";
import { useRouter } from "@/lib/routing/client-router";
import { useDockviewStore } from "@/lib/state/dockview-store";
import { useTranslation } from "react-i18next";
import { toast } from "@/lib/toast/sonner";
import { createDesktopV1Adapter, type DesktopV1Adapter } from "@/lib/desktop/adapter";
import {
createDesktopCommandActions,
subscribeDesktopCommandActions,
} from "@/lib/desktop/command-actions";
import { closeDesktopContext } from "@/lib/desktop/contextual-close";
import {
desktopExternalLinks,
subscribeDesktopExternalLinks,
type DesktopExternalLinkAdapter,
} from "@/lib/desktop/external-links";
import { requestNewTaskCreation } from "@/lib/desktop/new-task-request";
import { createTauriEventTransport } from "@/lib/desktop/tauri-event-transport";
import { listenForDesktopDownloadReady } from "@/lib/desktop/download-ready";
import { desktopDownloadToastStatus } from "@/lib/desktop/download-feedback";
import { completeNativeBlobDownload } from "@/lib/utils/native-blob-download";
import { desktopUpdater } from "@/lib/desktop/updater-client";
import type { DesktopUpdaterAdapter } from "@/lib/desktop/updater-adapter";
const desktopAdapter = createDesktopV1Adapter(createTauriEventTransport());
export function DesktopCommandHost({
adapter = desktopAdapter,
externalLinks = desktopExternalLinks,
updater = desktopUpdater,
}: {
adapter?: DesktopV1Adapter;
externalLinks?: DesktopExternalLinkAdapter;
updater?: DesktopUpdaterAdapter;
}) {
const router = useRouter();
const { t } = useTranslation();
const actions = useMemo(
() =>
createDesktopCommandActions({
closeContext: () => closeDesktopContext(document, useDockviewStore.getState().api),
navigate: router.push,
requestNewTask: requestNewTaskCreation,
}),
[router.push],
);
useEffect(() => {
if (!adapter.isAvailable()) return;
let disposed = false;
let stop: (() => void) | undefined;
void subscribeDesktopCommandActions(adapter, actions).then(
(unlisten) => {
if (disposed) unlisten();
else stop = unlisten;
},
() => undefined,
);
return () => {
disposed = true;
stop?.();
};
}, [actions, adapter]);
useEffect(() => {
if (!adapter.isAvailable() || !updater.isAvailable()) return;
let disposed = false;
let stop: (() => void) | undefined;
void adapter
.listen("check-for-updates", () => {
router.push("/settings/system/updates");
void updater.checkForUpdates().catch(() => undefined);
})
.then(
(unlisten) => {
if (disposed) unlisten();
else stop = unlisten;
},
() => undefined,
);
return () => {
disposed = true;
stop?.();
};
}, [adapter, router, updater]);
useEffect(() => {
if (!adapter.isAvailable()) return;
let disposed = false;
let stop: (() => void) | undefined;
void adapter
.listen("download", (feedback) => {
completeNativeBlobDownload(feedback);
const status = desktopDownloadToastStatus(feedback);
if (status === "saved") toast.success(t("settings:desktopDownloadSaved"));
if (status === "failed") toast.error(t("settings:desktopDownloadFailed"));
})
.then(
(unlisten) => {
if (disposed) unlisten();
else stop = unlisten;
},
() => undefined,
);
return () => {
disposed = true;
stop?.();
};
}, [adapter, t]);
useEffect(() => {
if (!adapter.isAvailable()) return;
let disposed = false;
let stop: (() => void) | undefined;
void listenForDesktopDownloadReady(adapter).then(
(unlisten) => {
if (disposed) unlisten();
else stop = unlisten;
},
() => undefined,
);
return () => {
disposed = true;
stop?.();
};
}, [adapter]);
useEffect(() => subscribeDesktopExternalLinks(document, externalLinks), [externalLinks]);
return null;
}