Unify the Agent history extension with the header acrylic surface, preserve the full conversation body, and consolidate shared control and status styling. Restore map flow and SCADA controller behavior, remove obsolete rendering paths, and extend regression coverage. Button press coverage now releases outside the target so state assertions cannot accidentally toggle the control.
139 lines
3.2 KiB
TypeScript
139 lines
3.2 KiB
TypeScript
import { useEffect } from "react";
|
|
import { Toaster } from "sonner";
|
|
import { dismissMapNotice, showMapNotice } from "./notice-actions";
|
|
import type { MapNoticeTone } from "./notice-types";
|
|
|
|
export type { MapNoticeOptions, MapNoticePosition, MapNoticeTone } from "./notice-types";
|
|
|
|
export function MapToaster() {
|
|
return (
|
|
<Toaster
|
|
closeButton={false}
|
|
expand
|
|
visibleToasts={4}
|
|
position="top-center"
|
|
toastOptions={{
|
|
unstyled: true,
|
|
classNames: {
|
|
toast: "group pointer-events-auto",
|
|
closeButton:
|
|
"absolute right-2 top-2 grid h-8 w-8 place-items-center rounded-lg border border-transparent text-slate-400 after:absolute after:-inset-1 after:content-[''] hover:bg-white/70 hover:text-slate-700"
|
|
}
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function MapErrorNotice({ message, id = "map-error" }: { message: string; id?: string | number }) {
|
|
useEffect(() => {
|
|
showMapNotice({
|
|
id,
|
|
tone: "error",
|
|
title: "地图异常",
|
|
message,
|
|
duration: Infinity
|
|
});
|
|
|
|
return () => dismissMapNotice(id);
|
|
}, [id, message]);
|
|
|
|
return null;
|
|
}
|
|
|
|
export function MapLoadingNotice({
|
|
message = "正在初始化地图...",
|
|
title = "地图加载中",
|
|
id = "map-loading"
|
|
}: {
|
|
message?: string;
|
|
title?: string;
|
|
id?: string | number;
|
|
}) {
|
|
useEffect(() => {
|
|
showMapNotice({
|
|
id,
|
|
tone: "loading",
|
|
title,
|
|
message,
|
|
duration: Infinity,
|
|
dismissible: false
|
|
});
|
|
|
|
return () => dismissMapNotice(id);
|
|
}, [id, message, title]);
|
|
|
|
return null;
|
|
}
|
|
|
|
export type MapSourceStatus = "online" | "degraded" | "offline";
|
|
|
|
export type MapSourceStatusNoticeProps = {
|
|
sourceName: string;
|
|
status: MapSourceStatus;
|
|
message?: string;
|
|
id?: string | number;
|
|
actionLabel?: string;
|
|
onAction?: () => void;
|
|
};
|
|
|
|
export function MapSourceStatusNotice({
|
|
sourceName,
|
|
status,
|
|
message,
|
|
id = `map-source-${sourceName}`,
|
|
actionLabel,
|
|
onAction
|
|
}: MapSourceStatusNoticeProps) {
|
|
useEffect(() => {
|
|
showMapNotice({
|
|
id,
|
|
tone: getSourceStatusTone(status),
|
|
title: getSourceStatusTitle(sourceName, status),
|
|
message: message ?? getSourceStatusMessage(status),
|
|
duration: status === "online" ? 2600 : Infinity,
|
|
actionLabel,
|
|
onAction
|
|
});
|
|
|
|
return () => dismissMapNotice(id);
|
|
}, [actionLabel, id, message, onAction, sourceName, status]);
|
|
|
|
return null;
|
|
}
|
|
|
|
function getSourceStatusTone(status: MapSourceStatus): MapNoticeTone {
|
|
if (status === "online") {
|
|
return "success";
|
|
}
|
|
|
|
if (status === "degraded") {
|
|
return "warning";
|
|
}
|
|
|
|
return "error";
|
|
}
|
|
|
|
function getSourceStatusTitle(sourceName: string, status: MapSourceStatus) {
|
|
if (status === "online") {
|
|
return `${sourceName} 已连接`;
|
|
}
|
|
|
|
if (status === "degraded") {
|
|
return `${sourceName} 降级运行`;
|
|
}
|
|
|
|
return `${sourceName} 不可用`;
|
|
}
|
|
|
|
function getSourceStatusMessage(status: MapSourceStatus) {
|
|
if (status === "online") {
|
|
return "地图数据源已恢复正常。";
|
|
}
|
|
|
|
if (status === "degraded") {
|
|
return "部分地图能力不可用,系统已使用可用替代方案。";
|
|
}
|
|
|
|
return "地图数据源请求失败,请检查网络或稍后重试。";
|
|
}
|