diff --git a/plugins/catalog-react/src/components/EntityTable/EntityTable.tsx b/plugins/catalog-react/src/components/EntityTable/EntityTable.tsx new file mode 100644 index 0000000000..a96f10fe2b --- /dev/null +++ b/plugins/catalog-react/src/components/EntityTable/EntityTable.tsx @@ -0,0 +1,79 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity } from '@backstage/catalog-model'; +import { Table, TableColumn } from '@backstage/core'; +import { makeStyles } from '@material-ui/core'; +import React from 'react'; +import * as columnFactories from './columns'; +import { systemEntityColumns } from './presets'; + +type Props = { + title: string; + variant?: string; + entities: T[]; + emptyComponent?: JSX.Element; + columns: TableColumn[]; +}; + +const useStyles = makeStyles(theme => ({ + empty: { + padding: theme.spacing(2), + display: 'flex', + justifyContent: 'center', + }, +})); + +export function EntityTable({ + entities, + title, + emptyComponent, + variant = 'gridItem', + columns, +}: Props) { + const classes = useStyles(); + const tableStyle: React.CSSProperties = { + minWidth: '0', + width: '100%', + }; + + if (variant === 'gridItem') { + tableStyle.height = 'calc(100% - 10px)'; + } + + return ( + + columns={columns} + title={title} + style={tableStyle} + emptyComponent={ + emptyComponent &&
{emptyComponent}
+ } + options={{ + // TODO: Toolbar padding if off compared to other cards, should be: padding: 16px 24px; + search: false, + paging: false, + actionsColumnIndex: -1, + padding: 'dense', + }} + data={entities} + /> + ); +} + +EntityTable.columns = columnFactories; + +EntityTable.systemEntityColumns = systemEntityColumns; diff --git a/plugins/catalog-react/src/components/EntityTable/columns.tsx b/plugins/catalog-react/src/components/EntityTable/columns.tsx new file mode 100644 index 0000000000..011ba66d59 --- /dev/null +++ b/plugins/catalog-react/src/components/EntityTable/columns.tsx @@ -0,0 +1,128 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Entity, + RELATION_OWNED_BY, + RELATION_PART_OF, +} from '@backstage/catalog-model'; +import { TableColumn } from '@backstage/core'; +import React from 'react'; +import { getEntityRelations } from '../../utils'; +import { + EntityRefLink, + EntityRefLinks, + formatEntityRefTitle, +} from '../EntityRefLink'; + +export function createEntityRefColumn({ + defaultKind, +}: { + defaultKind?: string; +}): TableColumn { + function formatContent(entity: T): string { + return formatEntityRefTitle(entity, { + defaultKind, + }); + } + + return { + title: 'Name', + highlight: true, + customFilterAndSearch(filter, entity) { + // TODO: We could implement this more efficiently, like searching over each field individually, but that migth confuse the user + return formatContent(entity).includes(filter); + }, + customSort(entity1, entity2) { + // TODO: We could implement this more efficiently by comparing field by field. + return formatContent(entity1).localeCompare(formatContent(entity2)); + }, + render: entity => ( + + ), + }; +} + +export function createOwnerColumn(): TableColumn { + function formatContent(entity: T): string { + const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + return ownedByRelations + .map(r => formatEntityRefTitle(r, { defaultKind: 'group' })) + .join(', '); + } + + return { + title: 'Owner', + customFilterAndSearch(filter, entity) { + return formatContent(entity).includes(filter); + }, + customSort(entity1, entity2) { + return formatContent(entity1).localeCompare(formatContent(entity2)); + }, + render: entity => { + const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + return ( + + ); + }, + }; +} + +export function createDomainColumn(): TableColumn { + function formatContent(entity: T): string { + const partOfDomainRelations = getEntityRelations(entity, RELATION_PART_OF, { + kind: 'domain', + }); + return partOfDomainRelations + .map(r => formatEntityRefTitle(r, { defaultKind: 'domain' })) + .join(', '); + } + + return { + title: 'Domain', + customFilterAndSearch(filter, entity) { + return formatContent(entity).includes(filter); + }, + customSort(entity1, entity2) { + return formatContent(entity1).localeCompare(formatContent(entity2)); + }, + render: entity => { + const partOfDomainRelations = getEntityRelations( + entity, + RELATION_PART_OF, + { + kind: 'domain', + }, + ); + return ( + + ); + }, + }; +} + +export function createMetadataDescriptionColumn< + T extends Entity +>(): TableColumn { + return { + title: 'Description', + field: 'metadata.description', + width: 'auto', + }; +} diff --git a/plugins/catalog-react/src/components/EntityTable/index.ts b/plugins/catalog-react/src/components/EntityTable/index.ts new file mode 100644 index 0000000000..8a01b9baae --- /dev/null +++ b/plugins/catalog-react/src/components/EntityTable/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { EntityTable } from './EntityTable'; diff --git a/plugins/catalog-react/src/components/EntityTable/presets.tsx b/plugins/catalog-react/src/components/EntityTable/presets.tsx new file mode 100644 index 0000000000..e898185e5e --- /dev/null +++ b/plugins/catalog-react/src/components/EntityTable/presets.tsx @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SystemEntity } from '@backstage/catalog-model'; +import { TableColumn } from '@backstage/core'; +import { + createEntityRefColumn, + createMetadataDescriptionColumn, + createOwnerColumn, + createDomainColumn, +} from './columns'; + +export const systemEntityColumns: TableColumn[] = [ + createEntityRefColumn({ defaultKind: 'system' }), + createOwnerColumn(), + createDomainColumn(), + createMetadataDescriptionColumn(), +]; diff --git a/plugins/catalog-react/src/components/index.ts b/plugins/catalog-react/src/components/index.ts index 463aeb6250..8508935dd6 100644 --- a/plugins/catalog-react/src/components/index.ts +++ b/plugins/catalog-react/src/components/index.ts @@ -15,4 +15,5 @@ */ export * from './EntityProvider'; export * from './EntityRefLink'; +export * from './EntityTable'; export * from './EntityTables'; diff --git a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx index 0af5f1747d..339f83c624 100644 --- a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx +++ b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.tsx @@ -23,7 +23,7 @@ import { WarningPanel, } from '@backstage/core'; import { - SystemsTable, + EntityTable, useEntity, useRelatedEntities, } from '@backstage/plugin-catalog-react'; @@ -71,7 +71,7 @@ export const HasSystemsCard = ({ variant = 'gridItem' }: Props) => { } return ( - { } + columns={EntityTable.systemEntityColumns} entities={entities as SystemEntity[]} /> );