feat: enhance catalog-plugin table with label column
Signed-off-by: Ankit Luthra <ankitluthra06@gmail.com>
This commit is contained in:
committed by
Ankit Luthra
parent
7b81f5dcc0
commit
d558f41d3a
@@ -0,0 +1,40 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
This change would allow consumers of plugin catalog to make use of labels just like tags from metadata.
|
||||
|
||||
The intent of change is to show customised columns based on selected label with which entity is associated.
|
||||
For example: In example below category and visibility are type of labels associated with API entity.
|
||||
YAML for API entity
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: API
|
||||
metadata:
|
||||
name: sample-api
|
||||
description: API for sample
|
||||
links:
|
||||
- url: http://localhost:8080/swagger-ui.html
|
||||
title: Swagger UI
|
||||
tags:
|
||||
- http
|
||||
labels:
|
||||
category: legacy
|
||||
visibility: protected
|
||||
```
|
||||
|
||||
Consumers can customise columns to include label column and show in api-docs list
|
||||
|
||||
```typescript
|
||||
const columns = [
|
||||
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
|
||||
CatalogTable.columns.createLabelColumn('category', { title: 'Category' }),
|
||||
CatalogTable.columns.createLabelColumn('visibility', {
|
||||
title: 'Visibility',
|
||||
defaultValue: 'public',
|
||||
}),
|
||||
];
|
||||
```
|
||||
@@ -148,6 +148,15 @@ export const CatalogTable: {
|
||||
}
|
||||
| undefined,
|
||||
): TableColumn<CatalogTableRow>;
|
||||
createLabelColumn(
|
||||
key: string,
|
||||
options?:
|
||||
| {
|
||||
title?: string | undefined;
|
||||
defaultValue?: string | undefined;
|
||||
}
|
||||
| undefined,
|
||||
): TableColumn<CatalogTableRow>;
|
||||
}>;
|
||||
};
|
||||
|
||||
|
||||
@@ -331,4 +331,42 @@ describe('CatalogTable component', () => {
|
||||
|
||||
expect(getByText('Should be rendered')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the label column with customised title and value as specified', async () => {
|
||||
const columns = [
|
||||
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
|
||||
CatalogTable.columns.createLabelColumn('category', { title: 'Category' }),
|
||||
];
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'APIWithLabel',
|
||||
labels: { category: 'generic' },
|
||||
},
|
||||
};
|
||||
const expectedColumns = ['Name', 'Category', 'Actions'];
|
||||
|
||||
const { getAllByRole, getByText } = await renderInTestApp(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<MockEntityListContextProvider value={{ entities: [entity] }}>
|
||||
<CatalogTable columns={columns} />
|
||||
</MockEntityListContextProvider>
|
||||
</ApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const columnHeader = getAllByRole('button').filter(
|
||||
c => c.tagName === 'SPAN',
|
||||
);
|
||||
const columnHeaderLabels = columnHeader.map(c => c.textContent);
|
||||
expect(columnHeaderLabels).toEqual(expectedColumns);
|
||||
|
||||
const labelCellValue = getByText('generic');
|
||||
expect(labelCellValue).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,6 +25,31 @@ import { OverflowTooltip, TableColumn } from '@backstage/core-components';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { JsonArray } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* Renders label if exists in entities or default
|
||||
* @param labels - Key value pairs of labels specified in entity metadata
|
||||
* @param key - specified label key to be extracted from all labels
|
||||
* @param defaultValue - shows default in case label key does not exist
|
||||
* @returns Chip style component when label value exists undefined otherwise.
|
||||
*/
|
||||
const renderLabel = (
|
||||
labels: Record<string, string> | undefined,
|
||||
key: string,
|
||||
defaultValue?: string,
|
||||
) => {
|
||||
const specifiedLabelValue = (labels && labels[key]) || defaultValue;
|
||||
return (
|
||||
specifiedLabelValue && (
|
||||
<Chip
|
||||
key={specifiedLabelValue}
|
||||
label={specifiedLabelValue}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// The columnFactories symbol is not directly exported, but through the
|
||||
// CatalogTable.columns field.
|
||||
/** @public */
|
||||
@@ -162,4 +187,20 @@ export const columnFactories = Object.freeze({
|
||||
searchable: true,
|
||||
};
|
||||
},
|
||||
createLabelColumn(
|
||||
key: string,
|
||||
options?: { title?: string; defaultValue?: string },
|
||||
): TableColumn<CatalogTableRow> {
|
||||
return {
|
||||
title: options?.title || 'Label',
|
||||
field: 'entity.metadata.labels',
|
||||
cellStyle: {
|
||||
padding: '0px 16px 0px 20px',
|
||||
},
|
||||
render: ({ entity }: { entity: Entity }) => (
|
||||
<>{renderLabel(entity.metadata?.labels, key, options?.defaultValue)}</>
|
||||
),
|
||||
width: 'auto',
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user