feat: enhance catalog-plugin table with label column

Signed-off-by: Ankit Luthra <ankitluthra06@gmail.com>
This commit is contained in:
Ankit Luthra
2022-09-29 14:32:50 +05:30
committed by Ankit Luthra
parent 7b81f5dcc0
commit d558f41d3a
4 changed files with 128 additions and 0 deletions
+40
View File
@@ -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',
}),
];
```
+9
View File
@@ -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',
};
},
});