From 77fa01477140d8b6997c39a68672d5a40715d97f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 6 Oct 2026 07:33:03 +0000 Subject: [PATCH] =?UTF-8?q?feat(desktop):=20=E7=82=B9=E5=87=BB=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E5=AE=9A=E4=BD=8D=E5=88=B0=E5=AF=B9=E5=BA=94=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 总览、标题栏和右侧动态栏中的告警点击后打开日志控制台,滚动到该行并高亮。 Co-authored-by: Shiroha --- .changeset/desktop-alert-log-jump.md | 5 ++ packages/desktop/src/renderer/app/App.tsx | 5 +- packages/desktop/src/renderer/app/desktop.tsx | 22 +++++++- .../src/renderer/components/RightRail.tsx | 4 +- .../src/renderer/components/TitleBar.tsx | 6 +-- .../desktop/src/renderer/components/feeds.tsx | 4 +- packages/desktop/src/renderer/lib/alerts.ts | 11 ++++ .../src/renderer/pages/ConsolePage.tsx | 53 +++++++++++++++---- .../src/renderer/pages/OverviewPage.tsx | 4 +- .../desktop/src/renderer/styles/pages.css | 11 ++++ 10 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 .changeset/desktop-alert-log-jump.md diff --git a/.changeset/desktop-alert-log-jump.md b/.changeset/desktop-alert-log-jump.md new file mode 100644 index 00000000..92617dd2 --- /dev/null +++ b/.changeset/desktop-alert-log-jump.md @@ -0,0 +1,5 @@ +--- +"@sfmc-bds/desktop": minor +--- + +点击告警后打开日志控制台,并定位到对应行高亮。 diff --git a/packages/desktop/src/renderer/app/App.tsx b/packages/desktop/src/renderer/app/App.tsx index 618a9dd5..7d41af4f 100644 --- a/packages/desktop/src/renderer/app/App.tsx +++ b/packages/desktop/src/renderer/app/App.tsx @@ -139,7 +139,7 @@ function Workspace() { /** 外壳:三栏布局、快捷键与全局对话框 */ function Shell() { - const { selected, model, page, setPage, appInfo } = useDesktop(); + const { selected, model, page, setPage, appInfo, logFocus } = useDesktop(); const [layout, setLayout] = useState(readLayout); const narrow = useMediaQuery(NARROW_QUERY); /** 窄窗口下右侧栏以浮层打开(不持久化) */ @@ -163,6 +163,9 @@ function Shell() { } }, [model.handshake, page, setPage]); useEffect(() => setRailOverlay(false), [narrow]); + useEffect(() => { + if (logFocus) setRailOverlay(false); + }, [logFocus]); const railOpen = narrow ? railOverlay : layout.rail; const toggleSidebar = useCallback(() => setLayout((value) => ({ ...value, sidebar: !value.sidebar })), []); diff --git a/packages/desktop/src/renderer/app/desktop.tsx b/packages/desktop/src/renderer/app/desktop.tsx index 8ef0b792..1ae1ab7a 100644 --- a/packages/desktop/src/renderer/app/desktop.tsx +++ b/packages/desktop/src/renderer/app/desktop.tsx @@ -82,6 +82,10 @@ interface DesktopValue { model: Model; page: PageKey; setPage: (page: PageKey) => void; + /** 打开日志控制台并定位到这一条 */ + logFocus: { entry: LogEntryWire; nonce: number } | null; + openLog: (entry: LogEntryWire) => void; + clearLogFocus: () => void; busy: boolean; /** 包裹异步操作:显示全局进度、捕获错误并提示 */ guarded: (action: () => Promise) => Promise; @@ -148,7 +152,17 @@ export function DesktopProvider({ children }: { children: ReactNode }) { const [profiles, setProfiles] = useState([]); const [current, setCurrentState] = useState(""); const [models, setModels] = useState>({}); - const [page, setPage] = useState("overview"); + const [page, setPageState] = useState("overview"); + const [logFocus, setLogFocus] = useState<{ entry: LogEntryWire; nonce: number } | null>(null); + const setPage = useCallback((next: PageKey) => { + if (next !== "logs") setLogFocus(null); + setPageState(next); + }, []); + const openLog = useCallback((entry: LogEntryWire) => { + setLogFocus({ entry, nonce: Date.now() }); + setPageState("logs"); + }, []); + const clearLogFocus = useCallback(() => setLogFocus(null), []); const [busyCount, setBusyCount] = useState(0); const [flow, setFlow] = useState(null); const [profileDialog, setProfileDialog] = useState({ open: false, editing: null }); @@ -167,6 +181,7 @@ export function DesktopProvider({ children }: { children: ReactNode }) { const model = models[current] ?? blank(); const setCurrent = useCallback((id: string) => { setCurrentState(id); + setLogFocus(null); if (id) localStorage.setItem(LAST_INSTANCE_KEY, id); }, []); @@ -526,6 +541,9 @@ export function DesktopProvider({ children }: { children: ReactNode }) { model, page, setPage, + logFocus, + openLog, + clearLogFocus, busy: busyCount > 0, guarded, patch, @@ -549,7 +567,7 @@ export function DesktopProvider({ children }: { children: ReactNode }) { appInfo, desktopUpdate, }), - [ready, profiles, current, setCurrent, selected, models, model, page, busyCount, guarded, patch, refresh, request, submit, editable, connect, disconnect, startAttach, createDeployment, applyAttachment, confirmHost, flow, profileDialog, saveProfile, removeProfile, appInfo, desktopUpdate] + [ready, profiles, current, setCurrent, selected, models, model, page, setPage, logFocus, openLog, clearLogFocus, busyCount, guarded, patch, refresh, request, submit, editable, connect, disconnect, startAttach, createDeployment, applyAttachment, confirmHost, flow, profileDialog, saveProfile, removeProfile, appInfo, desktopUpdate] ); return {children}; } diff --git a/packages/desktop/src/renderer/components/RightRail.tsx b/packages/desktop/src/renderer/components/RightRail.tsx index 653fb111..5f6ffb6a 100644 --- a/packages/desktop/src/renderer/components/RightRail.tsx +++ b/packages/desktop/src/renderer/components/RightRail.tsx @@ -24,7 +24,7 @@ function RailSection({ title, action, onAction, children }: { title: string; act /** 右侧动态栏 */ export function RightRail() { - const { model, selected, setPage, page } = useDesktop(); + const { model, selected, setPage, page, openLog } = useDesktop(); const [now, setNow] = useState(Date.now()); useEffect(() => { const timer = setInterval(() => setNow(Date.now()), 30_000); @@ -42,7 +42,7 @@ export function RightRail() { ) : ( <> setPage("logs")}> - setPage("logs")} /> + setPage("tasks")}> setPage("tasks")} /> diff --git a/packages/desktop/src/renderer/components/TitleBar.tsx b/packages/desktop/src/renderer/components/TitleBar.tsx index 0b2bf65b..1a5fd178 100644 --- a/packages/desktop/src/renderer/components/TitleBar.tsx +++ b/packages/desktop/src/renderer/components/TitleBar.tsx @@ -111,7 +111,7 @@ function ConnectionDetails() { /** 告警按钮:角标为"上次打开后新增"的警告/错误数,打开弹层即视为已读(按实例分别记录) */ function AlertsButton() { - const { model, current, setPage } = useDesktop(); + const { model, current, openLog } = useDesktop(); const [seen, setSeen] = useState>({}); const [open, setOpen] = useState(false); const seenAt = seen[current] ?? 0; @@ -143,9 +143,9 @@ function AlertsButton() { logs={model.logs} now={Date.now()} limit={8} - onSelect={() => { + onSelect={(log) => { setOpen(false); - setPage("logs"); + openLog(log); }} /> diff --git a/packages/desktop/src/renderer/components/feeds.tsx b/packages/desktop/src/renderer/components/feeds.tsx index d575d04b..0f47d755 100644 --- a/packages/desktop/src/renderer/components/feeds.tsx +++ b/packages/desktop/src/renderer/components/feeds.tsx @@ -33,14 +33,14 @@ export function serviceState(row: ServiceStatusRow): { tone: Tone; label: string } /** 告警列表:错误用红色色块、警告用琥珀色块,正文取日志首行 */ -export function AlertFeed({ logs, now, limit = 6, onSelect, emptyText = "已加载日志中没有警告或错误" }: { logs: LogEntryWire[]; now: number; limit?: number; onSelect?: () => void; emptyText?: string }) { +export function AlertFeed({ logs, now, limit = 6, onSelect, emptyText = "已加载日志中没有警告或错误" }: { logs: LogEntryWire[]; now: number; limit?: number; onSelect?: (log: LogEntryWire) => void; emptyText?: string }) { const alerts = groupAlerts(logs, limit); if (!alerts.length) return ; return (
    {alerts.map(({ log, count, firstTime }, index) => (
  • - } > - setPage("logs")} /> +