返回 DeepSeek-Reasonix
SessionStatusBanners.tsx
根目录 / desktop / frontend / src / app-shell / SessionStatusBanners.tsx
1 import { ErrorMessage } from "../components/ErrorMessage";
2 import { lazy, Suspense } from "react";
3 import type { Translator } from "../lib/i18n";
4 import { RemoteReclaimBanner } from "../components/RemoteReclaimBanner";
5 import { UpdateBanner } from "../components/UpdateBanner";
6 import type { HistoricalSessionBannerProps } from "../components/SessionTakeoverDialog";
7
8 const SessionRuntimeOverlays = lazy(() => import("../components/SessionTakeoverDialog").then((module) => ({ default: module.SessionRuntimeOverlays })));
9
10 export type SessionStatusBannersProps = {
11 t: Translator;
12 takenOver: boolean;
13 reclaimTabId: string;
14 reclaimBusyTabId: string | null;
15 onReclaim: (tabId: string) => void;
16 leaseBlocked: { tabId: string; message: string } | null;
17 startupError: string | undefined;
18 takeoverDialogTabId: string | null;
19 onOpenTakeover: (tabId: string) => void;
20 onCloseTakeover: () => void;
21 configWarnings: readonly string[];
22 onOpenConfigFile: () => void;
23 onReloadConfigFile: () => void;
24 onDismissConfigWarnings: () => void;
25 providerSetupNeeded: boolean;
26 needsOnboarding: boolean | null;
27 onConfigureProvider: () => void;
28 updateChecksEnabled: boolean;
29 onShowReleaseNotes: (latest: string) => void;
30 historical?: HistoricalSessionBannerProps;
31 };
32
33 /** Presentation-only banner stack between the topic bar and the main pane. */
34 export function SessionStatusBanners(props: SessionStatusBannersProps) {
35 const { t } = props;
36 return (
37 <>
38 {props.takenOver ? (
39 <RemoteReclaimBanner
40 tabId={props.reclaimTabId}
41 busyTabId={props.reclaimBusyTabId}
42 onReclaim={props.onReclaim}
43 />
44 ) : null}
45 {props.leaseBlocked ? (
46 <div className="banner banner--error">
47 <span className="banner__msg"><ErrorMessage error={t("topbar.startupError", { msg: props.leaseBlocked.message })} /></span>
48 <span className="banner__spacer" />
49 <button type="button" className="btn btn--small" onClick={() => props.onOpenTakeover(props.leaseBlocked!.tabId)}>
50 {t("takeover.bannerButton")}
51 </button>
52 </div>
53 ) : props.startupError ? (
54 <div className="banner banner--error">
55 <span className="banner__msg"><ErrorMessage error={t("topbar.startupError", { msg: props.startupError })} /></span>
56 </div>
57 ) : null}
58 {props.configWarnings.length > 0 && (
59 <div className="banner banner--warning banner--actionable">
60 <span className="banner__msg" title={props.configWarnings.join("\n")}>
61 <ErrorMessage error={t("config.loadWarning", { msg: props.configWarnings.join("\n") })} />
62 </span>
63 <span className="banner__spacer" />
64 <button type="button" className="btn btn--small" onClick={props.onOpenConfigFile}>
65 {t("config.openConfig")}
66 </button>
67 <button type="button" className="btn btn--small" onClick={props.onReloadConfigFile}>
68 {t("config.reloadConfig")}
69 </button>
70 <span className="banner__hint">{t("config.doctorHint")}</span>
71 <button type="button" className="btn btn--small" onClick={props.onDismissConfigWarnings}>
72 {t("updater.dismiss")}
73 </button>
74 </div>
75 )}
76 {props.providerSetupNeeded && (
77 <div className="banner banner--warning banner--actionable">
78 <span className="banner__msg">{t("onboarding.inlinePrompt")}</span>
79 <span className="banner__spacer" />
80 <button type="button" className="btn btn--small" onClick={props.onConfigureProvider}>
81 {t("onboarding.configureProvider")}
82 </button>
83 </div>
84 )}
85 <UpdateBanner
86 enabled={props.updateChecksEnabled}
87 onShowReleaseNotes={props.onShowReleaseNotes}
88 />
89 {props.takeoverDialogTabId || props.historical ? <Suspense fallback={null}>
90 <SessionRuntimeOverlays takeoverTabId={props.takeoverDialogTabId} onCloseTakeover={props.onCloseTakeover} historical={props.historical} />
91 </Suspense> : null}
92 </>
93 );
94 }
95
95 lines Plain Text