多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Graylog Web 前端 ControlledTableList 组件实战:从示例到源码级解析

Graylog Web 前端 ControlledTableList 组件实战:从示例到源码级解析 日志分析运维观测【免费下载链接】graylog2-serverFree and open log management项目地址https://gitcode.com/gh_mirrors/gr/graylog2-server点击查看免费下载本文以 ControlledTableList.md 中的官方示例为骨架深入讲解 Graylog Web 界面中ControlledTableList通用组件的工作原理、子组件划分与真实项目用法。读完你将掌握如何用ControlledTableList组装带表头、可空态提示的分组列表理解其基于 BootstrapListGroup的渲染机制并能参考 Sidecar 管理与 Content Packs 两个真实场景写出可落地的代码。ControlledTableList是 Graylog Web 前端graylog2-web-interface中一个轻量级的通用列表容器组件。它不像DataTable那样强调单元格与列的概念而是把每一条数据渲染成一个占满宽度的行式条目基于 Bootstrap 的ListGroup非常适合展示标题 摘要 附属信息这种卡片化的实体列表。本文档正文以官方示例ControlledTableList.md为起点再结合源码与两个真实业务页面把它的 API、行为和最佳实践一次讲透。一、官方示例5 分钟上手官方示例以类组件React.Component形式演示了最基础的用法用 Immutable 列表存放 5 个数字条目英文名 西班牙语秘钥 描述再通过一个formatItems方法把每条数据映射为ControlledTableList.Item最后整体放入ControlledTableList容器并配一个Header。import Immutable from immutable; import { Col, Row } from components/bootstrap; class ControlledTableListExample extends React.Component { constructor(props) { super(props); this.state { items: Immutable.List([ { id: 1, title: One, secret_key: uno, description: First number }, { id: 2, title: Two, secret_key: dos, description: Second number }, { id: 3, title: Three, secret_key: tres, description: Third number }, { id: 4, title: Four, secret_key: cuatro, description: Fourth number }, { id: 5, title: Five, secret_key: cinco, description: Fifth number }, ]), }; this.formatItems this.formatItems.bind(this); } formatItems(items) { return items.map((item) { return ( ControlledTableList.Item key{item.id} Row classNamerow-sm Col md{12} h5 {item.title} small{item.description}/small /h5 /Col /Row Row classNamerow-sm Col md{12}#{item.id}/Col /Row /ControlledTableList.Item ); }); } render() { const { items } this.state; return ( ControlledTableList ControlledTableList.HeaderNumbers/ControlledTableList.Header {this.formatItems(items)} /ControlledTableList ); } }拆解这段示例可以提炼出三条核心 API 规则容器 命名子组件ControlledTableList本身不接收数据数组作为 prop而是通过children接收已经格式化好的ControlledTableList.Item。Header与Item是挂在容器静态属性上的子组件详见下文源码解析写法上ControlledTableList.Header/ControlledTableList.Item与ControlledTableList天然形成语义层级。每行一个key在formatItems中用items.map生成条目时必须在Item上传递 React 要求的key示例中直接使用item.id这里 id 是字符串与真实业务中node_id、pack.id的用法一致。内部布局自由组合Item内的内容完全由调用方掌控官方示例用Row/ColBootstrap 栅格把标题 描述和编号分成两个紧凑行row-sm你完全可以换成其他布局或直接放任意 React 节点。需要说明的是示例里的组件用了Immutable.List保存数据这是 Graylog 前端长期使用的不可变数据实践在现代函数组件中直接用普通数组Array.map同样适用真实业务代码里两种写法都大量存在。二、源码剖析三个文件、各司其职ControlledTableList由三个源码文件组成全部位于graylog2-web-interface/src/components/common/目录下并通过 common/index.tsx 统一导出。2.1 容器组件ControlledTableList.tsxControlledTableList.tsx 的逻辑非常短核心行为只有一个空态兜底。const ControlledTableList ({ children }: { children: ArrayReact.ReactNode }) { let effectiveChildren; if (children.length 0) { effectiveChildren ControlledTableListItemNo items to display/ControlledTableListItem; } else { effectiveChildren children; } return ( div ListGroup{effectiveChildren}/ListGroup /div ); }; ControlledTableList.Header ControlledTableListHeader; ControlledTableList.Item ControlledTableListItem;从源码可以得到以下确切结论当没有任何children即列表为空时容器会自动渲染一个内容为No items to display的Item保证页面不会出现空白列表这是官方示例没有显式体现的隐藏行为所有条目被包裹在 Bootstrap 的ListGroup组件中来自components/bootstrap因此视觉上是垂直排列的圆角分组列表条目之间由ListGroupItem的分隔线自然隔开组件挂载了两个静态属性Header和Item分别指向下方两个子组件文件这就是为什么调用方可以写ControlledTableList.Header与ControlledTableList.Item从children的类型声明ArrayReact.ReactNode可以看出容器渲染的是由调用方决定顺序的子节点数组它本身不负责排序、筛选或分页——这些工作由上层业务组件完成见第三、四节的真实案例。2.2 条目组件ControlledTableListItem.tsxControlledTableListItem.tsx 是对 BootstrapListGroupItem的一层极薄封装仅透传一个可选classNameconst ControlledTableListItem ({ className undefined, children, }: { className?: string; children: React.ReactNode; }) ListGroupItem className{className}{children}/ListGroupItem;它没有任何业务逻辑。className的透传意味着你可以在真实项目中通过 styled-components 二次定制条目的样式例如CollectorsAdministration中用于置灰不可用 Collector 的样式包装见下文而children可以是任意组合的行内布局。2.3 表头组件ControlledTableListHeader.tsxControlledTableListHeader.tsx 是三个文件中样式逻辑最丰富的一个。它同样渲染为一个ListGroupItem但通过 styled-components 定制了背景色、内边距与字号const StyledListGroupItem styled(ListGroupItem)( ({ theme }) css background-color: ${theme.colors.variant.lightest.default}; padding: 0 15px; font-size: ${theme.fonts.size.body}; color: ${theme.utils.contrastingColor(theme.colors.variant.lightest.default)}; .form-group { margin: 0; } , ); const HeaderWrapper styled.div padding: 10px 0; min-height: 40px; ; const ControlledTableListHeader ({ children }: { children?: React.ReactNode }) { const wrapStringChildren (text: string) HeaderWrapper{text}/HeaderWrapper; const header typeof children string ? wrapStringChildren(children) : children; return StyledListGroupItem{header}/StyledListGroupItem; };值得注意的细节字符串子节点自动包裹如果children是字符串例如示例中的Numbers组件会把它包进带min-height: 40px、padding: 10px 0的HeaderWrapper保证表头在空内容时也有稳定的占位高度非字符串子节点原样透传如果children是 React 元素例如CollectorsAdministration中的全选复选框架则直接渲染而不再包裹主题联动背景色使用theme.colors.variant.lightest.default文字颜色通过theme.utils.contrastingColor依据背景自动计算因此表头与正文条目在明暗主题下都有正确的对比度font-size取自theme.fonts.size.body表头也透传了 BootstrapListGroupItem因此它作为列表的第一个条目参与整体分组样式视觉上既是标题行又与条目保持一致的圆角/分隔风格。2.4 组件关系小结文件角色渲染基础关键行为ControlledTableList.tsx容器ListGroup空态显示 No items to display挂载Header/Item静态子组件ControlledTableListItem.tsx条目ListGroupItem透传className与childrenControlledTableListHeader.tsx表头ListGroupItemstyled字符串子节点自动包裹主题化背景与对比色三、真实场景一Sidecar 管理中的可选中分组列表ControlledTableList最复杂的真实应用之一是 CollectorsAdministration.tsx它是 Graylog Sidecar 管理界面中展示Sidecar × Collector配对列表的核心组件。这段代码展示了表头如何承载交互控件、条目如何承载多行栅格布局。3.1 表头承载全选控件在formatHeader方法中ControlledTableList.Header的children被传入了两块内容右侧的操作区HeaderComponentsWrapper与左侧的全选复选框架Input typecheckboxreturn ( ControlledTableList.Header HeaderComponentsWrapper{headerMenu}/HeaderComponentsWrapper Input ref{selectAllInput} idselect-all-checkbox typecheckbox label{selectedItems 0 ? Select all : ${selectedItems} selected} disabled{enabledCollectors.length 0} checked{isAllSelected(enabledCollectors, selected)} onChange{toggleSelectAll} wrapperClassNameform-group-inline / /ControlledTableList.Header );由于children是 React 元素而非字符串ControlledTableListHeader会原样透传不会做自动包裹。这里还能看到一个与源码呼应的细节ControlledTableListHeader.tsx中的 CSS 规则.form-group { margin: 0; }正是为了压缩这类嵌入表单控件的间距使表头与条目高度对齐。3.2 条目承载多行栅格与状态信息每个 Sidecar 被渲染为一个ControlledTableList.Item内部再用Row/Col划分标题区与 Collector 明细区ControlledTableList.Item key{sidecar-${sidecar.node_id}} CollectorEntry Row Col md{12} AlignedInformation className{list-group-item-heading ${!sidecar.active commonStyle.greyedOut}} {sidecar.node_name} OperatingSystemIcon operatingSystem{sidecar.node_details.operating_system} / emsp; small {sidecar.node_id} {!sidecar.active bmdash; inactive/b} /small /AlignedInformation /Col /Row {_collectors.map((collector) formatCollector(sidecar, collector, _configurations))} /CollectorEntry /ControlledTableList.Item注意这里key使用sidecar-${sidecar.node_id}保证跨页面切换handlePageChange会清空已选条目时 React 能稳定复用/销毁节点。而formatCollector返回的则是普通Row不包Item说明一个条目内部可以继续嵌套多行明细——这正是ControlledTableList与严格一行一数据表格的区别条目是自由容器粒度由业务决定。3.3 空态与筛选结果当sidecarCollectorPairs.length 0时页面直接渲染一个内容为There are no collectors to display或Filters do not match any collectors的ControlledTableList.Item这与容器组件内置的 No items to display 兜底互为补充如果完全不给 children容器兜底如果业务想自定义空态文案就自己传一个 Item。这个模式在分页 筛选场景中尤其重要因为筛选后的空结果文案往往需要与数据真不存在区分。四、真实场景二Content Packs 列表中的头部 分页切片另一个典型的轻量用法在 ContentPacksList.tsx。它展示了ControlledTableList与分页切片、TypeAheadDataFilter组合的模式const formatItems (items: ArrayContentPackInstallation) { const { perPage, page } paginationOption; const begin perPage * (page - 1); const end begin perPage; const shownItems items.slice(begin, end); return shownItems.map((item) ( ContentPackListItem key{item.id} pack{item} contentPackMetadata{contentPackMetadata} onDeletePack{onDeletePack} onInstall{onInstall} / )); };渲染时ControlledTableList ControlledTableList.Header / {formatItems(filteredContentPacks)} /ControlledTableList此处有两个值得照抄的细节空表头ControlledTableList.Header /不传任何children由于默认值是空字符串组件仍会渲染出一个占位高度为 40px 的表头行用于和下方条目形成视觉分隔——这正是HeaderWrapper设置min-height的意义所在Item 由子组件产出这里并没有直接写ControlledTableList.Item而是由 ContentPackListItem.tsx 在内部使用ControlledTableListItem直接从components/common/ControlledTableListItem导入包裹自己的卡片内容标题 摘要 Install/More Actions 按钮组。这说明是否经由ControlledTableList容器渲染并不影响 Item 的使用——容器负责分组外观与空态Item 是独立可复用的行容器。五、常见用法模式与实现建议结合示例源码与两个真实页面可以总结出四种高频组合纯展示列表示例模式容器 Header字符串标题 若干Item自由栅格布局适合实体卡片列表类页面交互式表头Header内放复选框、筛选器、批量操作按钮Item内放对应行的复选/状态控件见 CollectorsAdministration.tsx分页切片Item不直接写在列表组件里而是由独立的ListItem组件产出列表组件只负责slice与map见 ContentPacksList.tsx空态自定义容器内置 No items to display 兜底业务需要区分无数据与筛选无结果时自行传入内容为自定义文案的Item。六、FAQ 与易踩的坑Q为什么示例里要用Immutable.ListA这是 Graylog 前端历史上普遍使用的不可变数据实践便于配合shouldComponentUpdate/引用比较做渲染优化功能上普通数组完全等价。Qkey放哪里A必须放在ControlledTableList.Item或其包装组件ContentPackListItem上而不是内部的Row上否则 React 的 diff 会警告或错乱。Q容器会自动做分页/筛选吗A不会。从 ControlledTableList.tsx 的实现看容器只负责ListGroup包裹与空态兜底排序、筛选、分页全部由上层组件完成Sidecar 用PaginatedListContent Packs 用PaginationTypeAheadDataFilter。QHeader 传字符串和传组件有什么区别A字符串会被自动包进带min-height: 40px的HeaderWrapperReact 组件则原样渲染。需要精细布局如全选框 按钮时传组件纯标题时直接传字符串即可。结语ControlledTableList是 Graylog Web 前端中最常见的低成本列表容器三个源码文件加起来不到百行却通过容器 静态子组件 Bootstrap ListGroup styled-components 主题的组合覆盖了实体列表的大多数展示需求。官方示例ControlledTableList.md展示了最小可用形态而 Sidecar 管理与 Content Packs 两个页面则证明了它在交互、分页、空态等复杂场景下的扩展能力。在 Graylog 前端开发中当你的需求是竖排卡片式列表 可选表头 空态兜底而非严格的数据表格时ControlledTableList就是最合适的选择。赞分享日志分析运维观测【免费下载链接】graylog2-serverFree and open log management项目地址https://gitcode.com/gh_mirrors/gr/graylog2-server点击查看免费下载相关推荐如何用 context-compression 技能的探针式提问评估智能体上下文压缩质量如何用 context compression 技能的探针式提问评估智能体上下文压缩质量 长会话智能体做上下文压缩后最常见的担忧是文件路径、报错信息和关键日志分析运维观测React Native Elements Tile 组件实战从 Snack 示例到源码级解析React Native Elements Tile 组件实战从 Snack 示例到源码级解析 Tile磁贴是 React Native ElementsUI组件移动开发前端WinApps 安装程序检测不到 libvirt 虚拟机设置 LIBVIRT_DEFAULT_URI 的排查方法WinApps 安装程序检测不到 libvirt 虚拟机设置 LIBVIRT_DEFAULT_URI 的排查方法 按 docs/libvirt.md http日志分析运维观测上一篇Adobe-GenP 3.0专业级Adobe全家桶激活技术深度解析下一篇PacketSender10分钟掌握网络测试工具的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表