From 2ea14f0bcfff9a23f6d19fa57524311ab9de9033 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Fri, 1 Oct 2021 13:32:22 +0200 Subject: [PATCH] Display errors from ancestors Signed-off-by: Johan Haals --- .../src/next/NextEntitiesCatalog.ts | 1 - .../EntityProcessingErrorsPanel.tsx | 115 +++++++++++++----- 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/plugins/catalog-backend/src/next/NextEntitiesCatalog.ts b/plugins/catalog-backend/src/next/NextEntitiesCatalog.ts index 14fda4ea24..f8c244cbfd 100644 --- a/plugins/catalog-backend/src/next/NextEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/next/NextEntitiesCatalog.ts @@ -189,7 +189,6 @@ export class NextEntitiesCatalog implements EntitiesCatalog { current = todo.pop() ) { const currentRef = stringifyEntityRef(current); - seenEntityRefs.add(currentRef); const parentRows = await this.database( 'refresh_state_references', diff --git a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx index a5adde3c9a..f4636f26db 100644 --- a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx +++ b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx @@ -16,7 +16,9 @@ import { Entity, + EntityName, getEntityName, + stringifyEntityRef, UNSTABLE_EntityStatusItem, } from '@backstage/catalog-model'; import { catalogApiRef, useEntity } from '@backstage/plugin-catalog-react'; @@ -24,34 +26,96 @@ import { Box } from '@material-ui/core'; import React from 'react'; import { ResponseErrorPanel } from '@backstage/core-components'; import { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client'; -import { useApi } from '@backstage/core-plugin-api'; +import { useApi, ApiHolder } from '@backstage/core-plugin-api'; import { useAsync } from 'react-use'; +import { CatalogApi } from '@backstage/catalog-client'; +import { SerializedError } from '@backstage/errors'; const errorFilter = (i: UNSTABLE_EntityStatusItem) => i.error && i.level === 'error' && i.type === ENTITY_STATUS_CATALOG_PROCESSING_TYPE; -export const hasCatalogProcessingErrors = async (entity: Entity) => { - // go grab ancestors and check all items, not just the current entity - return entity?.status?.items?.filter(errorFilter).length! > 0; +async function getOwnAndAncestorsErrors( + entityName: EntityName, + catalogApi: CatalogApi, +): Promise { + const ancestors = await catalogApi.getEntityAncestors({ entityName }); + return ancestors.items.flatMap(item => { + const statuses = item.entity.status?.items ?? []; + return statuses + .filter(errorFilter) + .map(e => e.error) + .filter((e): e is SerializedError => Boolean(e)); + }); +} + +export const hasCatalogProcessingErrors = async ( + entity: Entity, + context: { apiRegistry: ApiHolder }, +) => { + const catalogApi = context.apiRegistry.get(catalogApiRef); + if (!catalogApi) { + throw new Error(`No implementation available for ${catalogApiRef}`); + } + + const errors = await getOwnAndAncestorsErrors( + getEntityName(entity), + catalogApi, + ); + return errors.length > 0; }; /** * Displays a list of errors if the entity is invalid. */ export const EntityProcessingErrorsPanel = () => { + /* const { entity } = useEntity(); const catalogProcessingErrors = (entity?.status?.items?.filter( errorFilter, ) as Required[]) || []; - return catalogProcessingErrors.map(({ error }, index) => ( - - - - )); + return ( + <> + {catalogProcessingErrors.map(({ error }, index) => ( + + + + ))} + + ); + */ + // move this logic into the existing component + const { entity } = useEntity(); + const catalogApi = useApi(catalogApiRef); + + const { loading, error, value } = useAsync(() => { + return getOwnAndAncestorsErrors(getEntityName(entity), catalogApi); + }, [stringifyEntityRef(entity), catalogApi]); + + if (error) { + return ( + + + + ); + } + + if (loading || !value?.length) { + return null; + } + + return ( + <> + {value.map((ancestorError, index) => ( + + + + ))} + + ); }; /** @@ -62,13 +126,9 @@ export const EntityAncestorsProcessingErrorsPanel = () => { const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); - const { loading, value, error } = useAsync(() => - catalogApi.getEntityAncestors({ entityName: getEntityName(entity) }), - ); - - if (loading) { - return null; - } + const { loading, error, value } = useAsync(() => { + return getOwnAndAncestorsErrors(getEntityName(entity), catalogApi); + }, [stringifyEntityRef(entity), catalogApi]); if (error) { return ( @@ -78,22 +138,17 @@ export const EntityAncestorsProcessingErrorsPanel = () => { ); } - const ancestorErrors = - value?.items.flatMap(({ entity: ancestor }) => - ancestor?.status?.items?.filter?.(errorFilter), - ) ?? []; - - if (ancestorErrors.length === 0) { + if (loading || !value?.length) { return null; } - const filteredAncestors = ancestorErrors.filter( - (e): e is UNSTABLE_EntityStatusItem => Boolean(e), + return ( + <> + {value.map((ancestorError, index) => ( + + + + ))} + ); - - return filteredAncestors.map(({ error: ancestorError }, index) => ( - - - - )); };