Keep 告警详情侧边栏(AlertSidebar)集成指南:统一 Incident Alerts 页面告警交互体验
2026/9/15 16:45:22 网站建设 项目流程

Keep 告警详情侧边栏(AlertSidebar)集成指南:统一 Incident Alerts 页面告警交互体验

【免费下载链接】keepThe open-source AIOps and alert management platform项目地址: https://gitcode.com/GitHub_Trending/kee/keep

Keep(开源 AIOps 与告警管理平台)在前端keep-ui中通过将事件(Incident)详情页的告警表格从ViewAlertModal弹窗模式切换为AlertSidebar侧边抽屉模式,实现了全应用统一的告警详情查看与操作体验。本文以该集成实现为线索,结合源码讲解组件替换、状态管理、交互入口、侧边栏功能与测试覆盖,帮助你在 Keep 前端中理解、复现并扩展这套侧边栏方案。

集成背景:为什么用 AlertSidebar 替换 ViewAlertModal

在 Keep 的告警工作流中,告警详情通常有两种查看形态:弹窗(Modal)与侧边抽屉(Sidebar)。ViewAlertModal作为独立弹窗组件存在,而主告警表格(alert-table.tsx)早已使用AlertSidebar。本次集成把事件(Incident)详情页的告警列表也切换到同一侧边栏组件,核心动机是:

  • 一致性:无论从告警流(Alert Feed)还是事件(Incident)上下文进入,看到的都是同一套侧边栏交互;
  • 功能对齐:侧边栏自带告警菜单(AlertMenu)、时间线、相关服务拓扑等能力,事件上下文同样受益;
  • 可维护性:只维护一个侧边栏组件,替代多个弹窗组件,降低 UI 代码的重复与分叉。

该决策记录于 ALERT_SIDEBAR_INTEGRATION.md/incidents/[id]/alerts/ALERT_SIDEBAR_INTEGRATION.md),实现集中在事件告警页组件incident-alerts.tsx中。

组件集成实现剖析(incident-alerts.tsx)

核心改动位于 incident-alerts.tsx/incidents/[id]/alerts/incident-alerts.tsx)。该文件是事件详情页“Alerts”标签页的入口组件,接收incident: IncidentDto作为 props,负责拉取该事件关联的告警列表、渲染表格并处理行级交互。

导入变更:移除弹窗、引入侧边栏

原实现仅依赖ViewAlertModal,集成后同时引入两个组件:

import { AlertSidebar } from "@/features/alerts/alert-detail-sidebar"; import { ViewAlertModal } from "@/features/alerts/view-raw-alert";

其中AlertSidebar通过 alert-detail-sidebar/index.ts 统一导出,实际实现在 ui/alert-sidebar.tsx。保留ViewAlertModal是因为“查看按钮”路径仍走弹窗(详见下文交互入口),两类组件按需共存。

状态管理重构

集成将原先单一的viewAlertModal状态拆分为三个独立状态,职责更清晰:

// State for ViewAlertModal (opened by view button) const [viewAlertModal, setViewAlertModal] = useState<AlertDto | null>(null); // State for AlertSidebar (opened by row click) const [selectedAlert, setSelectedAlert] = useState<AlertDto | null>(null); const [isSidebarOpen, setIsSidebarOpen] = useState(false); // Add state for incident selector modal (needed by AlertSidebar) const [isIncidentSelectorOpen, setIsIncidentSelectorOpen] = useState(false);
  • selectedAlert:记录当前在侧边栏中展示的告警对象;
  • isSidebarOpen:控制侧边栏开关;
  • isIncidentSelectorOpen:供AlertSidebar内部“关联事件(Correlate Incident)”动作使用——侧边栏内部菜单通过该状态打开事件选择器弹窗。

侧边栏关闭统一走handleSidebarClose,同时复位两个状态,避免关闭后再操作残留旧数据:

const handleSidebarClose = () => { setIsSidebarOpen(false); setSelectedAlert(null); };

侧边栏挂载与可选 props

在 JSX 中,侧边栏通过 Headless UI 的Dialog渲染为右侧抽屉,挂载于表格之后:

<AlertSidebar isOpen={isSidebarOpen} toggle={handleSidebarClose} alert={selectedAlert} // These optional props are passed to maintain feature parity with the main alerts table setRunWorkflowModalAlert={undefined} setDismissModalAlert={undefined} setChangeStatusAlert={undefined} setIsIncidentSelectorOpen={setIsIncidentSelectorOpen} />

对照AlertSidebar的完整 props 定义(alert-sidebar.tsx):

Prop类型必填作用
isOpenboolean控制侧边栏显示
toggleVoidFunction关闭回调(点击遮罩/关闭按钮触发)
alertAlertDto \| null当前展示的告警
setRunWorkflowModalAlert(alert) => void可选打开“运行工作流”弹窗
setDismissModalAlert(alerts[]) => void可选打开“忽略(Dismiss)”弹窗
setChangeStatusAlert(alert) => void可选打开“变更状态”弹窗
setIsIncidentSelectorOpen(open: boolean) => void必填打开“关联事件”选择器

从源码结构看,事件页目前只接通了setIsIncidentSelectorOpen,其余三个动作 handler 传undefined,侧边栏菜单对应入口即按条件隐藏;而在主告警表格(alert-table.tsx)中,这些 props 全部接通,这也是下文“功能对齐”设计的关键——同一组件在不同页面通过 props 开放不同能力。

两种用户交互入口

文档描述了侧边栏的两种打开方式,结合源码与测试(incident-alerts-sidebar.test.tsx/incidents/[id]/alerts/tests/incident-alerts-sidebar.test.tsx))核验后的真实行为如下:

  1. 行点击(打开 AlertSidebar):点击告警表格中的任意一行,触发AlertsTableBodyonRowClick回调,设置selectedAlert并打开侧边栏:

    <AlertsTableBody table={table} showSkeleton={false} theme={theme} onRowClick={(alert) => { setSelectedAlert(alert); setIsSidebarOpen(true); }} lastViewedAlert={null} presetName={"incident-alerts"} />

    表格由 TanStack Table 构建,行 ID 使用alert.fingerprint,且对 API 偶发返回重复 ID 的情况做了“追加行下标”的去重兜底处理。

  2. View Details 按钮(打开 ViewAlertModal):行尾操作托盘IncidentAlertActionTray中的“查看详情”按钮实际打开的是ViewAlertModal(源码注释// Open the ViewAlertModal when clicking the view button),而非侧边栏。测试用例should open ViewAlertModal when clicking view button in action tray也明确断言了这一点:点击 view 按钮后view-alert-modal可见、alert-sidebar不可见。因此严格来说,事件页的侧边栏唯一入口是行点击,两个组件按“行点击 vs 视图按钮”分工并存。

  3. 关闭方式:点击右上角关闭按钮、点击遮罩区域(Dialog onClose={toggle})都会调用handleSidebarClose。测试专门覆盖了关闭后isOpen=falsealert=null,防止出现 “Cannot read properties of null (reading 'fingerprint')” 之类的空指针回归。

AlertSidebar 核心能力与源码级讲解

侧边栏本体是一个固定右侧、宽度 2/4 的抽屉面板(Dialog.Panel,带 300ms 滑入/淡出过渡),自上而下包含:标题区(严重级别徽标 + 告警名)、告警菜单(AlertMenu)、可配置字段区、关联事件列表、告警时间线、相关服务拓扑。

告警菜单(AlertMenu)与动作体系

侧边栏头部内嵌AlertMenu(alert-menu.tsx),isInSidebar={true}时展示完整动作集合,动作项通过item.show条件按 props 是否传入决定显隐:

  • Run Workflow:回调setRunWorkflowModalAlert?.(alert)打开工作流运行弹窗;
  • Dismiss / RestoreonDismiss回调setDismissModalAlert?.([alert])
  • Change StatussetChangeStatusAlert?.(alert)
  • Correlate IncidentsetIsIncidentSelectorOpen?.(true)(仅当传入该回调时显示);
  • 查看原始 PayloadopenAlertPayloadModal
  • Provider 方法调用openMethodModal(method),可对已安装 provider 执行自定义方法;
  • Assign 分派callAssignEndpoint()

这解释了事件页集成时为何必须新增isIncidentSelectorOpen状态——事件上下文里“关联事件”是高频操作,但运行工作流/忽略/改状态等弹窗入口在事件页暂以undefined关闭,形成与主告警流有差异、面向事件场景的能力子集。

可配置字段渲染(ALERT_SIDEBAR_FIELDS)

侧边栏主体按config.ALERT_SIDEBAR_FIELDS(来自 useConfig)渲染字段,字段注册表定义在 alertSidebarFields.tsx:

export type AlertSidebarFieldName = | "service" | "source" | "description" | "message" | "fingerprint" | "url" | "incidents" | "timeline" | "relatedServices";
  • 标准字段servicesourcedescriptionmessagefingerprinturl等,每个字段都带shouldRender(alert)守卫(如无 URL 时不渲染 URL 行),fingerprinturl支持一键复制(handleCopyFingerprint/handleCopyUrl,失败时通过showErrorToast提示并给出文档链接);
  • 特殊字段incidentstimelinerelatedServices在字段循环外单独渲染(见下文);
  • 自定义字段getCustomFields解析ALERT_SIDEBAR_FIELDS中非标准字段,按点分路径取值,支持labels.alertnameannotations.description,甚至数组下标incident_dto.0.assignee(见getNestedValue实现),字段名自动由 snake_case/camelCase 转成 Title Case。

关联事件、时间线与相关服务拓扑

  • Incidents:当配置包含incidentsalert.incident_dto存在时,渲染可折叠的CollapsibleIncidentsList,展示该告警所属的事件列表;
  • Alert Timeline:通过useAlerts().useAlertAudit(alert.fingerprint)拉取审计历史,展示状态变更与操作记录,key随审计数据长度变化以便刷新后重挂载,支持手动刷新(handleRefresh调用mutate());
  • Related Services:当配置包含relatedServices时,渲染TopologyMap(复用 拓扑地图/topology/ui/map) 组件),以alert.providerIdalert.service定位相关服务拓扑,帮助在事件排障时快速看清告警影响的上下游服务。

测试覆盖与运行方式

集成配套的测试文件为 incident-alerts-sidebar.test.tsx/incidents/[id]/alerts/tests/incident-alerts-sidebar.test.tsx),采用 Jest + Testing Library,通过 mock 掉next/navigation、数据 hooks(useIncidentAlertsusePollIncidentAlerts)、provider/config hooks 及AlertSidebar本身来隔离测试目标组件。覆盖点:

用例断言内容
渲染告警列表正确展示(名称、严重级别),初始侧边栏关闭
行点击打开点击alert-row-*后侧边栏出现且内容为对应告警
关闭点击关闭按钮后侧边栏消失、状态复位
无异常关闭关闭后isOpen=falsealert=null,无空指针异常
告警切换从告警 A 切到告警 B,侧边栏内容随selectedAlert更新
空状态无告警时渲染EmptyStateCard(“No alerts yet”)
加载状态数据拉取中渲染IncidentAlertsTableBodySkeleton骨架屏
双组件共存View 按钮打开ViewAlertModal,行点击打开AlertSidebar,两者可同时存在

运行测试(文档给出的命令,需在keep-ui目录下):

cd keep-ui npm test -- --testPathPattern="incident-alerts-sidebar.test.tsx"

若只跑事件告警相关的全部用例,可将 pattern 替换为incident-alerts.*

收益与未来扩展

收益总结:全应用统一的侧边栏交互;事件上下文中告警动作能力与主告警流对齐;单组件多页面复用,显著降低 UI 维护成本;对用户而言,熟悉的行点击-抽屉模式降低了学习成本。

未来扩展方向:文档指出侧边栏已具备工作流执行、状态变更等能力,当前事件页以undefined关闭这些入口;后续如需在事件上下文中启用,只需把对应 handler 从父组件传入:

<AlertSidebar isOpen={isSidebarOpen} toggle={handleSidebarClose} alert={selectedAlert} setRunWorkflowModalAlert={setRunWorkflowModalAlert} // 传入后菜单项自动显示 setDismissModalAlert={setDismissModalAlert} setChangeStatusAlert={setChangeStatusAlert} setIsIncidentSelectorOpen={setIsIncidentSelectorOpen} />

由于AlertMenu依据 props 是否存在控制菜单项显隐,接入无需改动侧边栏本体,体现了该组件面向需求演进的扩展性设计。若需进一步定制展示字段,可通过后端配置ALERT_SIDEBAR_FIELDS(含标准字段与点分路径自定义字段)动态调整侧边栏内容,实现“一套组件、多处配置”的灵活布局。

【免费下载链接】keepThe open-source AIOps and alert management platform项目地址: https://gitcode.com/GitHub_Trending/kee/keep

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询