diff --git a/apps/web/src/components/ProviderUpdateLaunchNotification.tsx b/apps/web/src/components/ProviderUpdateLaunchNotification.tsx deleted file mode 100644 index c5be98b4a4af3..0000000000000 --- a/apps/web/src/components/ProviderUpdateLaunchNotification.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { useAtomValue } from "@effect/atom-react"; -import { PROVIDER_DISPLAY_NAMES } from "@t3tools/contracts"; -import { useEffect, useRef } from "react"; - -import { writeTextToClipboard } from "../hooks/useCopyToClipboard"; -import { primaryServerProvidersAtom } from "../state/server"; -import { CommandBlock } from "./CommandBlock"; -import { ProviderInstanceIcon } from "./chat/ProviderInstanceIcon"; -import { - collectProviderUpdateCandidates, - isProviderUpdateActive, -} from "./ProviderUpdateLaunchNotification.logic"; -import { toastManager } from "./ui/toast"; - -/** Announce each available provider version once per client session, using the server's command. */ -export function ProviderUpdateLaunchNotification() { - const providers = useAtomValue(primaryServerProvidersAtom); - const shown = useRef(new Set()); - const notices = useRef(new Map>()); - - // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- reconciles server version advisories with the external toast manager - useEffect(() => { - const candidates = collectProviderUpdateCandidates(providers).filter( - (provider) => !isProviderUpdateActive(provider), - ); - const active = new Set( - candidates.map((provider) => `${provider.driver}:${provider.versionAdvisory.latestVersion}`), - ); - for (const [key, id] of notices.current) { - if (!active.has(key)) { - toastManager.close(id); - notices.current.delete(key); - } - } - for (const provider of candidates) { - const advisory = provider.versionAdvisory; - const key = `${provider.driver}:${advisory.latestVersion}`; - const command = advisory.updateCommand; - if (shown.current.has(key) || command === null) continue; - shown.current.add(key); - const name = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver; - const current = advisory.currentVersion ?? provider.version; - notices.current.set( - key, - toastManager.add({ - type: "info", - title: `${name} ${advisory.latestVersion} is available`, - description: current - ? `You're on ${current}. New sessions will use the updated provider.` - : "New sessions will use the updated provider.", - timeout: 0, - actionProps: { - children: "Copy update command", - onClick: () => { - void writeTextToClipboard(command, "update command"); - }, - }, - data: { - variant: "notification", - leadingIcon: ( - - ), - body: , - }, - }), - ); - } - }, [providers]); - - // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- removes this coordinator's external notices when its authenticated shell unmounts - useEffect(() => { - const owned = notices.current; - return () => { - for (const id of owned.values()) toastManager.close(id); - }; - }, []); - return null; -} diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index b4295dec9d5ce..3e8a763e5febf 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -32,7 +32,6 @@ import { DesktopWebLinkCoordinator } from "../components/desktop/DesktopWebLinkC import { RunningThreadKeepAlive } from "../components/desktop/RunningThreadKeepAlive"; import { ReopenClosedViewShortcut } from "../components/ReopenClosedViewShortcut"; import { ProjectCloneToastCoordinator } from "../components/ProjectCloneToastCoordinator"; -import { ProviderUpdateLaunchNotification } from "../components/ProviderUpdateLaunchNotification"; import { ChatGptWelcomeCoordinator } from "../components/settings/ChatGptWelcomeCoordinator"; import { ThemeEditorHost } from "../components/settings/ThemeEditorHost"; import { useCopyToClipboard } from "../hooks/useCopyToClipboard"; @@ -191,7 +190,6 @@ function RootRouteBranch() { - {import.meta.env.DEV && primaryEnvironmentAuthenticated ? : null} {primaryEnvironmentAuthenticated ? : null}