Skip to main content

目录定制

Backstage 软件目录带有一个默认的CatalogIndexPage的默认设置。@backstage/create-app.

如果您想更改默认索引页面,例如在目录中添加自定义过滤器,您可以创建自己的CatalogIndexPage.

注意:目录索引页的设计只占用了最少的代码,以 > 支持简便的定制,但创建一个副本确实有可能 > 随着时间的推移而过时。 请务必定期检查目录 > CHANGELOG>。

例如,假设我想允许通过添加到实体中的自定义注释进行过滤、company.com/security-tier首先,我将复制默认目录页面的代码并创建一个组件。

// imports, etc omitted for brevity. for full source see:
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
export const CustomCatalogPage = ({
columns,
actions,
initiallySelectedFilter = 'owned',
}: CatalogPageProps) => {
const createComponentLink = useRouteRef(
catalogPlugin.externalRoutes.createComponent,
);
return (
<PageWithHeader title={`${orgName} Catalog`} themeId="home">
<EntityListProvider>
<Content>
<ContentHeader titleComponent={<CatalogKindHeader />}>
<CreateButton title="Create Component" to={createComponentLink()} />
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<CatalogFilterLayout>
<CatalogFilterLayout.Filters>
<EntityTypePicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntityTagPicker />
</CatalogFilterLayout.Filters>
<CatalogFilterLayout.Content>
<CatalogTable columns={columns} actions={actions} />
</CatalogFilterLayout.Content>
</CatalogFilterLayout>
</Content>
</EntityListProvider>
</PageWithHeader>
);
};

EntityListProvider中的实体列表。catalog-backend以及连接过滤器的方法。

现在,我们可以创建一个新的过滤器来实现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-backend- 或前端过滤器,在从后端加载实体后应用。

我们将使用此过滤器以类型安全的方式扩展默认过滤器。 让我们创建自定义过滤器形状,并在此过滤器旁边的某个地方扩展默认过滤器:

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

为了控制该过滤器,我们可以创建一个 React 组件,用于显示安全层级的复选框。 该组件将利用useEntityList钩子,该钩子接受该扩展过滤器类型作为非专利参数:

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>
);
};

现在我们可以将组件添加到CustomCatalogPage:

export const CustomCatalogPage = ({
columns,
actions,
initiallySelectedFilter = 'owned',
}: CatalogPageProps) => {
return (
{/* ... */}
<EntityListProvider>
<CatalogFilterLayout>
<CatalogFilterLayout.Filters>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntitySecurityTierPicker />
<EntityTagPicker />
<CatalogFilterLayout.Filters>
<CatalogFilterLayout.Content>
<CatalogTable columns={columns} actions={actions} />
</CatalogFilterLayout.Content>
</CatalogFilterLayout>
</EntityListProvider>
{/* ... */}
};

最后,我们可以将新的CustomCatalogPage.

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

同样的方法也可以用来定制_默认_在这种情况下,不需要使用通用参数,因为过滤器的形状与默认值相同。