Backstage 软件目录(Software Catalog)定制指南:从分页、导出到自定义过滤器与完全自建 CatalogIndexPage
2026/9/10 7:27:10 网站建设 项目流程

Backstage 软件目录(Software Catalog)定制指南:从分页、导出到自定义过滤器与完全自建 CatalogIndexPage

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

本文面向仍在使用**旧版前端系统(old frontend system)**的 Backstage 应用,系统讲解如何围绕默认的CatalogIndexPage组件进行深度定制:启用分页与目录导出、调整默认筛选器与初始 Kind、增删表格列、扩展行操作(actions),乃至基于EntityFilter接口与useEntityListHook 编写全新过滤器,最终完全自建一个属于你自己的目录首页。读完本文,你将掌握@backstage/plugin-catalog@backstage/plugin-catalog-react中绝大多数目录页定制入口,并能直接套用到packages/app工程中。

注意:本文档面向仍在使用旧前端系统的 Backstage 应用。如果你的应用已经迁移到新前端系统,请阅读当前版本指南(Catalog Customization)。

定制前必读:默认 CatalogIndexPage 与 props 全景

Backstage 软件目录自带一个默认的CatalogIndexPage页面,用于筛选和查找目录实体(Entity),该页面由@backstage/create-app默认搭建完成。它提供了开箱即用的目录浏览体验,但如果你需要修改默认首页行为——例如设置初始选中的筛选器、调整表格列、增删行操作、或者为目录添加自定义过滤器——就需要了解这个组件暴露的全部定制入口。

从源码可以看到,DefaultCatalogPageProps完整定义了这些 props(见 DefaultCatalogPage.tsx):

Prop类型默认值用途
initiallySelectedFilterUserListFilterKind'owned'初始选中的用户列表筛选(owned / starred / all)
initialKindstring'component'初始选中的实体 Kind
columnsTableColumn[] \| CatalogTableColumnsFunc内置默认列覆盖表格列
actionsTableProps['actions']view / edit / star覆盖表格行操作
tableOptionsTableProps['options']{}透传到底层表格的选项
emptyContentReactNode空列表占位内容
ownerPickerModeEntityOwnerPickerProps['mode']'owners-only'属主选择器模式
filtersReactNodeDefaultFilters自定义筛选器集合
initiallySelectedNamespacesstring[]初始选中的命名空间
paginationEntityListPagination分页配置(v1.21.0+)
exportSettingsCatalogExportSettings目录导出配置

下文将围绕这些 props 逐一展开,并深入其对应的源码实现。

启用分页(Pagination)

目录首页的分页支持在 Backstagev1.21.0中加入,使用该特性前请确保你的版本不低于此。启用方式非常简单:给CatalogIndexPage传入paginationprop:

<Route path="/catalog" element={<CatalogIndexPage pagination />} />

从源码实现看,pagination会被传递给EntityListProvider(见 DefaultCatalogPage.tsx),底层支持两种分页模式:offset(基于偏移量)与cursor(基于游标)。同时插件内部提供了OffsetPaginatedCatalogTableCursorPaginatedCatalogTable两种表格实现(见 CatalogTable 目录)。pagination还可以传入对象形式,例如在自定义列一节中出现的pagination={{ mode: 'offset', limit: 20 }},用于指定分页模式与每页条数。

目录导出(Export)

目录导出功能允许用户将目录表格中的数据一键导出。启用方式是为CatalogIndexPage传入带enabled: trueexportSettingsprop:

<Route path="/catalog" element={<CatalogIndexPage exportSettings={{ enabled: true }} />} />

启用后,页面头部会出现一个导出按钮。点击后会打开一个对话框,用户可以:

  • 选择导出格式(默认提供CSVJSON两种);
  • 以复选框形式勾选/取消勾选要包含的列(默认全部预选)。

从源码看,导出功能由 CatalogExportButton.tsx 组件实现,它负责弹窗、格式下拉、列复选与导出触发;当exportSettings?.enabled为真时,该按钮会被渲染到页头(见 DefaultCatalogPage.tsx)。按钮默认展示在目录页右上角,带下载图标与文字标题。

导出配置接口:CatalogExportSettings

导出行为可以通过exportSettings配置CatalogExportSettings接口中的各种选项。该接口的源码定义位于 CatalogExportButton.tsx:

export interface CatalogExportSettings { enabled?: boolean; /** * Array of columns to include in the export. * * Each column requires an `entityFilterKey` (dot-separated path into the entity object that is returned by the catalog api) and an optional `title` for display. * When `title` is omitted, `entityFilterKey` is used as the display title. * * Default columns are: name, type, owner and description. **/ columns?: CatalogExportSettingsColumn[]; /** * Map of custom export format handlers. * * Each map entry provides an exporter function and an optional display label. * Custom formats appear in the export dialog alongside built-in CSV and JSON options. **/ exporters?: Record<string, CatalogExporterConfig>; /** Callback function invoked after successful export completion. Useful for displaying notifications or triggering post-export actions. */ onSuccess?: () => void; /** Callback function invoked if export fails. Receives an object containing the Error for error handling and user notification. */ onError?: (options: { error: Error }) => void; /** When true, hides the built-in CSV and JSON export options. Useful when only custom exporters should be available. */ disableBuiltinExporters?: boolean; }

各字段说明:

  • enabled:是否显示导出按钮,默认false
  • columns:自定义导出列,不配置时使用默认列metadata.name(Name)、spec.type(Type)、spec.owner(Owner)、metadata.description(Description)。默认列定义在源码 CatalogExportButton.tsx 的DEFAULT_EXPORT_COLUMNS中;
  • exporters:自定义导出格式处理器的映射表,键为格式名(如'xml''yaml'),值为{ exporter, label? }label缺省时,格式下拉中会以键名大写显示;
  • onSuccess/onError:导出成功/失败回调,可用于弹通知或执行后续动作。若未提供,组件内部会通过toastApi弹出默认的成功/失败提示(见 CatalogExportButton.tsx);
  • disableBuiltinExporters:为true时隐藏内置的 CSV、JSON 选项,适合只希望暴露自定义导出格式的场景。

自定义导出列

默认导出包含 name、type、owner、description 四列。导出对话框打开时,所有已配置的列都会以复选框形式展示并处于预选状态,用户可以取消勾选不想导出的列再确认导出。

你可以自定义可用列:

import { CatalogIndexPage } from '@backstage/plugin-catalog'; const customColumns = [ { entityFilterKey: 'metadata.name', title: 'Name' }, { entityFilterKey: 'metadata.namespace', title: 'Namespace' }, { entityFilterKey: 'spec.owner', title: 'Owner' }, ]; <CatalogIndexPage exportSettings={{ enabled: true, columns: customColumns, }} />;

列定义使用CatalogExportSettingsColumn结构:entityFilterKey是实体对象中的点分路径(dot-separated path),title是导出文件中的表头,缺省时直接用entityFilterKey作为表头。其源码定义见 serializeEntities.ts。实际取值时,代码通过getByPath按点分路径逐级解引用实体字段(见同文件 serializeEntities.ts);而在序列化 CSV 时,还会对以=+-@开头的值加单引号前缀,防止 CSV/公式注入(见 serializeEntities.ts),这说明导出功能在实现层面就已考虑了安全细节。

自定义导出格式

除 CSV 和 JSON 外,你还可以通过提供自定义导出函数来增加新的导出格式。自定义导出器使用 async generator(异步生成器)实现流式下载:数据边生成边写入磁盘,在支持的浏览器中不会把整个导出内容缓存在内存里。

import { CatalogIndexPage, CatalogExporter, CatalogExporterConfig, } from '@backstage/plugin-catalog'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; // Custom exporter using async generator for streaming const xmlExporter: CatalogExporter = ({ apis, columns, streamRequest }) => { const catalogApi = apis.get(catalogApiRef); // Return an async generator that yields XML chunks async function* generateXml() { yield '<?xml version="1.0" encoding="UTF-8"?>\n<entities>\n'; for await (const page of catalogApi.streamEntities(streamRequest)) { for (const entity of page) { // Serialize each entity to XML and yield immediately yield serializeEntityToXml(entity, columns); } } yield '</entities>'; } return { generator: generateXml(), contentType: 'application/xml', }; }; const yamlExporter: CatalogExporter = ({ apis, columns, streamRequest }) => { const catalogApi = apis.get(catalogApiRef); async function* generateYaml() { for await (const page of catalogApi.streamEntities(streamRequest)) { for (const entity of page) { yield serializeEntityToYaml(entity, columns); yield '---\n'; // YAML document separator } } } return { generator: generateYaml(), contentType: 'application/x-yaml', }; }; const exporters: Record<string, CatalogExporterConfig> = { xml: { exporter: xmlExporter, label: 'XML' }, yaml: { exporter: yamlExporter, label: 'YAML' }, }; <CatalogIndexPage exportSettings={{ enabled: true, exporters, }} />;

提供自定义格式后,它们会与内置的 CSV、JSON 选项一起出现在导出对话框中(若同时设置了disableBuiltinExporters: true,则只会显示自定义格式)。

从源码层面理解这一机制:CatalogExporter类型要求导出函数返回一个{ generator: AsyncGenerator<string, void, unknown>; contentType: string }结构(见 useStreamingExport.ts)。执行导出时,useStreamingExportHook 会把生成器通过createStreamFromAsyncGenerator包装成流并调用streamDownload触发浏览器下载(见 useStreamingExport.ts)。内置的 CSV/JSON 导出同样是基于 async generator 实现的——streamEntitiesCsvGenerator逐页调用catalogApi.streamEntities并立即yield序列化结果,JSON 导出器还会先yield '['再在结尾yield '\n]'以保持合法 JSON 结构(见 useStreamingExport.ts)。

值得一提的细节是:如果调用方没有显式提供streamRequest,导出会通过toStreamRequest(filters)从当前EntityList的筛选状态推导请求参数(见 useStreamingExport.ts),这意味着导出的数据与用户当前在目录页上的筛选视图保持一致,而不是导出全量数据。

成功/失败回调

你还可以提供回调来处理导出成功或失败的情况:

<CatalogIndexPage exportSettings={{ enabled: true, onSuccess: () => { // Handle successful export notificationApi.success({ message: 'Export completed!' }); }, onError: ({ error }) => { // Handle export error notificationApi.error({ message: `Export failed: ${error.message}`, }); }, }} />

onSuccess在导出流程成功结束后被调用;onError接收{ error: Error },便于你自定义错误提示或上报。从源码看,导出完成/失败后组件会依次触发这两个回调,若未提供则回退到内置 toast 提示(见 CatalogExportButton.tsx)。

组合示例

以下示例组合了全部自定义选项:

<CatalogIndexPage exportSettings={{ enabled: true, columns: [ { entityFilterKey: 'metadata.name', title: 'Name' }, { entityFilterKey: 'spec.type', title: 'Type' }, { entityFilterKey: 'spec.owner', title: 'Owner' }, { entityFilterKey: 'metadata.namespace', title: 'Namespace' }, ], exporters: { xml: { exporter: xmlExporter, label: 'XML' }, yaml: { exporter: yamlExporter, label: 'YAML' }, }, onSuccess: () => { notificationApi.success({ message: 'Export completed!' }); }, onError: ({ error }) => { notificationApi.error({ message: `Export failed: ${error.message}`, }); }, }} />

设置初始选中的筛选器(Initially Selected Filter)

默认情况下,目录页初始选中的筛选器是Owned。如果你的目录还在建设初期、实体不多,这可能导致首页一开始显示空列表。如果你希望默认显示All,可以这样修改:

<Route path="/catalog" element={<CatalogIndexPage initiallySelectedFilter="all" />} />

可选值为:ownedstarredall。从源码看,该 prop 的默认值为'owned',并会被透传给DefaultFilters中的UserListPicker(见 DefaultCatalogPage.tsx 与 DefaultFilters.tsx)。

设置初始选中的 Kind(Initially Selected Kind)

默认情况下,进入目录页时初始选中的 Kind 是Component,但你的组织可能有不同的需求——例如希望始终默认选中Domain,可以这样配置:

<Route path="/catalog" element={<CatalogIndexPage initialKind="domain" />} />

可选值包括系统模型中的所有默认 Kind,以及你自定义添加的任何 Kind。源码中该 prop 默认值为'component'(见 DefaultCatalogPage.tsx),并最终传递到EntityKindPickerinitialFilter(见 DefaultFilters.tsx)。

属主选择器模式(Owner Picker Mode)

Owner(属主)筛选器默认只包含实际拥有目录中实体的用户和/或用户组。如果你需要显示全部用户/组,可以这样配置:

<Route path="/catalog" element={<CatalogIndexPage ownerPickerMode="all" />} />

可选值为:owners-only(默认)或all。该值会作为EntityOwnerPickermodeprop 传入(见 DefaultFilters.tsx)。

表格选项(Table Options)

Backstage 中的表格基于@material-table/core构建,CatalogIndexPage提供了tableOptionsprop 让你在一定程度上定制底层表格,但部分 Backstage 硬编码的设置无法修改。下面示例展示了如何用该 prop 禁用表格表头的搜索框:

<Route path="/catalog" element={<CatalogIndexPage tableOptions={{ search: false }} />} />

tableOptions可设置大量选项,其完整列表对应@material-table/coreOptions接口(Backstage 当前使用的版本为v3.1.0)。实际使用时建议以该接口的类型定义为准,CatalogIndexPage会把它原样透传给CatalogTable(见 DefaultCatalogPage.tsx)。

自定义表格列(Customize Columns)

CatalogIndexPage中看到的列是面向大多数场景精选的起点,但你完全可能希望为已有或自定义 Kind 增删列。

为已有 Kind 添加列

假设我们想为UserKind 添加一列 "User Email"。做法是覆盖传入CatalogIndexPagecolumns。首先,匹配要覆盖的实体 Kind,并定义要展示的列:

const myColumnsFunc: CatalogTableColumnsFunc = entityListContext => { if (entityListContext.filters.kind?.value === 'user') { return [ // Render existing columns ...CatalogTable.defaultColumnsFunc(entityListContext), // Add new columns here ]; } return CatalogTable.defaultColumnsFunc(entityListContext); };

然后实现createUserEmailColumn函数并把它加入列列表。field用于从实体中取数据,render则允许你自定义数据的展示方式:

const createUserEmailColumn = (): TableColumn<CatalogTableRow> => ({ title: 'User Email', field: 'entity.spec.profile.email', render: ({ entity }) => ( <OverflowTooltip text={entity.spec?.profile?.['email'] || 'N/A'} placement="bottom-start" /> ), }); const myColumnsFunc: CatalogTableColumnsFunc = entityListContext => { if (entityListContext.filters.kind?.value === 'user') { return [ // Render existing columns ...CatalogTable.defaultColumnsFunc(entityListContext), // Add new columns here createUserEmailColumn(), ]; } return CatalogTable.defaultColumnsFunc(entityListContext); };

最后,把myColumnsFunc传给CatalogIndexPage

const routes = ( <FlatRoutes> <Route path="/catalog" element={ <CatalogIndexPage pagination={{ mode: 'offset', limit: 20 }} columns={myColumnsFunc} /> } /> {/* Other routes */} </FlatRoutes> )

这里涉及两个关键类型(见 CatalogTable/types.ts):

  • CatalogTableRow:表格行的数据结构,包含entity(完整实体)与resolved(预解析的 name、entityRef、所属关系等信息,见 types.ts);
  • CatalogTableColumnsFunc:接收entityListContext(含当前筛选状态filters)并返回列数组的函数类型(见 types.ts)。

为自定义或特定 Kind 添加列

另一个典型场景是为自定义Kind添加列,该能力在 Backstagev1.23.0及以上可用。例如:

import { CatalogEntityPage, CatalogIndexPage, catalogPlugin, CatalogTable, CatalogTableColumnsFunc, } from '@backstage/plugin-catalog'; const myColumnsFunc: CatalogTableColumnsFunc = entityListContext => { if (entityListContext.filters.kind?.value === 'MyKind') { return [ CatalogTable.columns.createNameColumn(), CatalogTable.columns.createOwnerColumn(), ]; } return CatalogTable.defaultColumnsFunc(entityListContext); }; <Route path="/catalog" element={<CatalogIndexPage columns={myColumnsFunc} />} />

CatalogTable.columns提供了如createNameColumncreateOwnerColumn等可复用的内置列工厂,方便你为特定 Kind 快速组装列集合。

:::note 以上示例中的文件内容为便于说明均做了精简。 :::

自定义行操作(Customize Actions)

CatalogIndexPage默认带三个行操作:view(查看)、edit(编辑)和star(收藏)。你可能会想添加更多。

首先,需要把@mui/utils添加到packages/app/package.json

yarn --cwd packages/app add @mui/utils

然后进行如下修改:

import { AlertDisplay, OAuthRequestDialog, SignInPage, TableProps, } from '@backstage/core-components'; import { CatalogEntityPage, CatalogIndexPage, CatalogTableRow, catalogPlugin, } from '@backstage/plugin-catalog'; import { Typography } from '@material-ui/core'; import OpenInNew from '@material-ui/icons/OpenInNew'; import { visuallyHidden } from '@mui/utils'; const customActions: TableProps<CatalogTableRow>['actions'] = [ ({ entity }) => { const url = 'https://backstage.io/'; const title = `View - ${entity.metadata.name}`; return { icon: () => ( <> <Typography style={visuallyHidden}>{title}</Typography> <OpenInNew fontSize="small" /> </> ), tooltip: title, disabled: !url, onClick: () => { if (!url) return; window.open(url, '_blank'); }, }; }, ]; <Route path="/catalog" element={<CatalogIndexPage actions={customActions} />} />

:::note 以上App.tsx示例内容为便于说明做了精简。 :::

需要特别说明:上述自定义会覆盖现有操作。目前,如果想保留默认操作并添加自己的操作,唯一的办法是把默认操作(defaultActions,即 view / edit / star 的实现)也复制到你的操作数组中。默认操作的源码位于 CatalogTable.tsx 的defaultActions定义处,可直接参考其实现来保留原有行为。

自定义筛选器(Customize Filters)

自定义筛选器有多种方式:通过 props 调整现有筛选器、增删默认筛选器、创建全新的自定义筛选器。下面分情况说明。

默认筛选器 Props(Default Filters)

@backstage/plugin-catalog-react提供了一组默认筛选器DefaultFilters,它聚合了前文提到的各种 props。用法如下:

import { DefaultFilters } from '@backstage/plugin-catalog-react'; <Route path="/catalog" element={ <CatalogIndexPage filters={ <> <DefaultFilters initialKind="Domain" initiallySelectedFilter="all" ownerPickerMode="all" /> </> } /> } />;

从源码看,DefaultFilters实际渲染了 8 个筛选器组件:EntityKindPickerEntityTypePickerUserListPickerEntityOwnerPickerEntityLifecyclePickerEntityTagPickerEntityProcessingStatusPickerEntityNamespacePicker(见 DefaultFilters.tsx)。

移除默认筛选器

如果你不想使用 Lifecycle(生命周期)、Tag(标签)和 Processing Status(处理状态)筛选器,可以这样移除:

import { EntityKindPicker, EntityTypePicker, UserListPicker, EntityOwnerPicker, EntityNamespacePicker, } from '@backstage/plugin-catalog-react'; <Route path="/catalog" element={ <CatalogIndexPage filters={ <> <EntityKindPicker /> <EntityTypePicker /> <UserListPicker /> <EntityOwnerPicker /> <EntityNamespacePicker /> </> } /> } />;

当你显式传入filters时,DefaultCatalogPage会使用你提供的筛选器集合替换默认的DefaultFilters(见 DefaultCatalogPage.tsx),因此只保留你列出的筛选器即可。

自定义筛选器

你可以添加自定义筛选器。例如,假设我们想按实体上的自定义注解company.com/security-tier进行筛选,可以按以下步骤构建筛选器。

首先,创建一个实现EntityFilter接口的新筛选器:

import { EntityFilter } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; class EntitySecurityTierFilter implements EntityFilter { constructor(readonly values: string[]) {} filterEntity(entity: Entity): boolean { const tier = entity.metadata.annotations?.['company.com/security-tier']; return tier !== undefined && this.values.includes(tier); } }

EntityFilter接口支持两类实现方式(见 catalog-react 的 types.ts):

  • 后端筛选(backend filter):通过实现getCatalogFilters()返回查询参数,筛选条件会被下推到catalog-backend,在查询阶段完成过滤;
  • 前端筛选(frontend filter):通过实现filterEntity(entity)在实体从后端加载后于前端过滤。

上面的EntitySecurityTierFilter使用了前端过滤方式(只实现filterEntity)。仓库中内置筛选器则提供了两种方式的参考:例如EntityTagFilter同时实现了filterEntitygetCatalogFilters(见 catalog-react 的 filters.ts),既可在后端过滤也可在前端兜底;而EntityKindFilterEntityTypeFilter只实现getCatalogFilters,属于纯后端筛选(见 filters.ts)。

接下来,以类型安全的方式用这个筛选器扩展默认筛选器集合。在筛选器旁边创建扩展默认结构的自定义筛选器类型:

export type CustomFilters = DefaultEntityFilters & { securityTiers?: EntitySecurityTierFilter; };

为了控制这个筛选器,可以创建一个显示安全等级复选框的 React 组件。该组件会用到useEntityListHook,并把扩展后的筛选器类型作为泛型参数传入:

export const EntitySecurityTierPicker = () => { // The securityTiers key is recognized due to the CustomFilter generic const { filters: { securityTiers }, updateFilters, } = useEntityList<CustomFilters>(); // Toggles the value, depending on whether it's already selected function onChange(value: string) { const newTiers = securityTiers?.values.includes(value) ? securityTiers.values.filter(tier => tier !== value) : [...(securityTiers?.values ?? []), value]; updateFilters({ securityTiers: newTiers.length ? new EntitySecurityTierFilter(newTiers) : undefined, }); } const tierOptions = ['1', '2', '3']; return ( <FormControl component="fieldset"> <Typography variant="button">Security Tier</Typography> <FormGroup> {tierOptions.map(tier => ( <FormControlLabel key={tier} control={ <Checkbox checked={securityTiers?.values.includes(tier)} onChange={() => onChange(tier)} /> } label={`Tier ${tier}`} /> ))} </FormGroup> </FormControl> ); };

现在把该组件加入CatalogIndexPage

import { DefaultFilters } from '@backstage/plugin-catalog-react'; const routes = ( <FlatRoutes> <Navigate key="/" to="catalog" /> <Route path="/catalog" element={ <CatalogIndexPage filters={ <> <DefaultFilters /> <EntitySecurityTierPicker /> </> } /> } /> {/* ... */} </FlatRoutes> );

同样的方法也可以用来以不同接口定制_默认_筛选器——此时无需泛型参数,因为筛选器结构与默认结构保持一致(例如直接使用useEntityList<DefaultEntityFilters>()并覆盖默认筛选键即可)。

高级定制:完全自建 CatalogIndexPage

如果以上方案都无法满足你的需求,你还可以选择创建完全自定义的CatalogIndexPage

import { PageWithHeader, Content, ContentHeader, SupportButton, } from '@backstage/core-components'; import { useApi, configApiRef } from '@backstage/core-plugin-api'; import { CatalogTable } from '@backstage/plugin-catalog'; import { EntityListProvider, CatalogFilterLayout, EntityKindPicker, EntityLifecyclePicker, EntityNamespacePicker, EntityOwnerPicker, EntityProcessingStatusPicker, EntityTagPicker, EntityTypePicker, UserListPicker, } from '@backstage/plugin-catalog-react'; export const CustomCatalogPage = () => { const orgName = useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; return ( <PageWithHeader title={orgName} themeId="home"> <Content> <ContentHeader title=""> <SupportButton>All your software catalog entities</SupportButton> </ContentHeader> <EntityListProvider pagination> <CatalogFilterLayout> <CatalogFilterLayout.Filters> <EntityKindPicker /> <EntityTypePicker /> <UserListPicker /> <EntityOwnerPicker /> <EntityLifecyclePicker /> <EntityTagPicker /> <EntityProcessingStatusPicker /> <EntityNamespacePicker /> </CatalogFilterLayout.Filters> <CatalogFilterLayout.Content> <CatalogTable /> </CatalogFilterLayout.Content> </CatalogFilterLayout> </EntityListProvider> </Content> </PageWithHeader> ); };

上述是一个非常基础的全自定义CatalogIndexPage版本。这个示例建立在默认页面所使用的构建模块之上——即 DefaultCatalogPage.tsx 中的BaseCatalogPage实现。你可以深入探索各个组件的 props,看看还能做哪些事情(例如自定义EntityListProviderpagination、自定义CatalogTablecolumns/actions、在ContentHeader中追加导出按钮等)。

:::note 目录首页被设计为具有极小的代码足迹以便于定制,但复制一份页面也意味着存在随版本演进而逐渐过时的风险。建议定期查看 catalog 插件的 CHANGELOG,关注CatalogIndexPage相关 API 的变更。 :::

要使用这个名为CustomCatalogPage的自定义页面,需要修改路由:

const routes = ( <FlatRoutes> <Navigate key="/" to="catalog" /> <Route path="/catalog" element={<CatalogIndexPage />}> <CustomCatalogPage /> </Route> {/* ... */} </FlatRoutes> );

总结

围绕CatalogIndexPage,Backstage 提供了一条从「零配置开箱即用」到「完全自建页面」的平滑定制路径:

  1. 轻量调整:通过paginationinitiallySelectedFilterinitialKindownerPickerModetableOptions等 props 快速改变默认行为;
  2. 数据导出:通过exportSettings启用导出,并可自定义导出列、基于 async generator 的自定义格式(如 XML、YAML)、成功/失败回调,甚至禁用内置格式;
  3. 展示层定制:通过columns函数为已有或自定义 Kind 增删列,通过actions覆盖行操作;
  4. 筛选逻辑定制:使用DefaultFilters调整默认筛选器、移除不需要的筛选器,或基于EntityFilter接口 +useEntityListHook 编写完全自定义的筛选组件;
  5. 终极方案:以EntityListProviderCatalogFilterLayoutCatalogTable等构建模块为积木,自建一个完全属于你的目录首页。

所有 props 与类型的最终定义都可以在 DefaultCatalogPage.tsx、CatalogExportButton.tsx 与 CatalogTable/types.ts 中找到,配合这些源码可以更准确地理解每个配置项的实际影响。如果你的应用已迁移到新前端系统,请转而阅读新版指南以获取对应实现方式。

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

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

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

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

立即咨询