catalog: clean up api reports

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2022-02-16 09:48:39 +01:00
parent c412ddbeac
commit 0a033351be
61 changed files with 786 additions and 586 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-catalog': minor
---
**BREAKING**:
- The `CatalogResultListItem` `result` prop is now of the more narrow and correct type `IndexableDocument`, rather than `any`.
- The individual table column factories (e.g. `createNameColumn`) are now no longer available directly, but only through `CatalogTable.columns`.
+248 -221
View File
@@ -11,11 +11,10 @@ import { Entity } from '@backstage/catalog-model';
import { EntityName } from '@backstage/catalog-model';
import { ExternalRouteRef } from '@backstage/core-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
import { IndexableDocument } from '@backstage/search-common';
import { InfoCardVariants } from '@backstage/core-components';
import { Overrides } from '@material-ui/core/styles/overrides';
import { PropsWithChildren } from 'react';
import { default as React_2 } from 'react';
import { ReactNode } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { StyleRules } from '@material-ui/core/styles/withStyles';
import { TableColumn } from '@backstage/core-components';
@@ -23,28 +22,40 @@ import { TableProps } from '@backstage/core-components';
import { TabProps } from '@material-ui/core';
import { UserListFilterKind } from '@backstage/plugin-catalog-react';
// Warning: (ae-forgotten-export) The symbol "AboutCardProps" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "AboutCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function AboutCard({ variant }: AboutCardProps): JSX.Element;
export function AboutCard(props: AboutCardProps): JSX.Element;
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "AboutContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const AboutContent: ({ entity }: Props) => JSX.Element;
// @public
export interface AboutCardProps {
// @deprecated (undocumented)
entity?: Entity;
// (undocumented)
variant?: InfoCardVariants;
}
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "AboutField" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const AboutField: ({
label,
value,
gridSizes,
children,
}: Props_2) => JSX.Element;
export function AboutContent(props: AboutContentProps): JSX.Element;
// @public
export interface AboutContentProps {
// (undocumented)
entity: Entity;
}
// @public (undocumented)
export function AboutField(props: AboutFieldProps): JSX.Element;
// @public
export interface AboutFieldProps {
// (undocumented)
children?: React_2.ReactNode;
// (undocumented)
gridSizes?: Record<string, number>;
// (undocumented)
label: string;
// (undocumented)
value?: string;
}
// @public (undocumented)
export type BackstageOverrides = Overrides & {
@@ -53,26 +64,21 @@ export type BackstageOverrides = Overrides & {
>;
};
// Warning: (ae-missing-release-tag) "CatalogEntityPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const CatalogEntityPage: () => JSX.Element;
// Warning: (ae-missing-release-tag) "CatalogIndexPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element;
// Warning: (ae-forgotten-export) The symbol "CatalogKindHeaderProps" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "CatalogKindHeader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const CatalogKindHeader: ({
initialFilter,
}: CatalogKindHeaderProps) => JSX.Element;
export function CatalogKindHeader(props: CatalogKindHeaderProps): JSX.Element;
// @public
export interface CatalogKindHeaderProps {
// (undocumented)
initialFilter?: string;
}
// Warning: (ae-missing-release-tag) "catalogPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
const catalogPlugin: BackstagePlugin<
{
@@ -98,24 +104,50 @@ const catalogPlugin: BackstagePlugin<
export { catalogPlugin };
export { catalogPlugin as plugin };
// Warning: (ae-missing-release-tag) "CatalogResultListItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const CatalogResultListItem: ({ result }: any) => JSX.Element;
export function CatalogResultListItem(
props: CatalogResultListItemProps,
): JSX.Element;
// @public
export interface CatalogResultListItemProps {
// (undocumented)
result: IndexableDocument;
}
// Warning: (ae-missing-release-tag) "CatalogTable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const CatalogTable: {
({ columns, actions }: CatalogTableProps): JSX.Element;
columns: typeof columnFactories;
(props: CatalogTableProps): JSX.Element;
columns: Readonly<{
createNameColumn(
options?:
| {
defaultKind?: string | undefined;
}
| undefined,
): TableColumn<CatalogTableRow>;
createSystemColumn(): TableColumn<CatalogTableRow>;
createOwnerColumn(): TableColumn<CatalogTableRow>;
createSpecTypeColumn(): TableColumn<CatalogTableRow>;
createSpecLifecycleColumn(): TableColumn<CatalogTableRow>;
createMetadataDescriptionColumn(): TableColumn<CatalogTableRow>;
createTagsColumn(): TableColumn<CatalogTableRow>;
}>;
};
// Warning: (ae-missing-release-tag) "EntityRow" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export interface CatalogTableProps {
// (undocumented)
actions?: TableProps<CatalogTableRow>['actions'];
// (undocumented)
columns?: TableColumn<CatalogTableRow>[];
}
// @public (undocumented)
export type CatalogTableRow = {
export interface CatalogTableRow {
// (undocumented)
entity: Entity;
// (undocumented)
resolved: {
name: string;
partOfSystemRelationTitle?: string;
@@ -123,230 +155,230 @@ export type CatalogTableRow = {
ownedByRelationsTitle?: string;
ownedByRelations: EntityName[];
};
};
}
// Warning: (ae-missing-release-tag) "createMetadataDescriptionColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createMetadataDescriptionColumn(): TableColumn<CatalogTableRow>;
// Warning: (ae-forgotten-export) The symbol "NameColumnProps" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "createNameColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createNameColumn(
props?: NameColumnProps,
): TableColumn<CatalogTableRow>;
// Warning: (ae-missing-release-tag) "createOwnerColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createOwnerColumn(): TableColumn<CatalogTableRow>;
// Warning: (ae-missing-release-tag) "createSpecLifecycleColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createSpecLifecycleColumn(): TableColumn<CatalogTableRow>;
// Warning: (ae-missing-release-tag) "createSpecTypeColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createSpecTypeColumn(): TableColumn<CatalogTableRow>;
// Warning: (ae-missing-release-tag) "createSystemColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createSystemColumn(): TableColumn<CatalogTableRow>;
// Warning: (ae-missing-release-tag) "createTagsColumn" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createTagsColumn(): TableColumn<CatalogTableRow>;
export const columnFactories: Readonly<{
createNameColumn(
options?:
| {
defaultKind?: string | undefined;
}
| undefined,
): TableColumn<CatalogTableRow>;
createSystemColumn(): TableColumn<CatalogTableRow>;
createOwnerColumn(): TableColumn<CatalogTableRow>;
createSpecTypeColumn(): TableColumn<CatalogTableRow>;
createSpecLifecycleColumn(): TableColumn<CatalogTableRow>;
createMetadataDescriptionColumn(): TableColumn<CatalogTableRow>;
createTagsColumn(): TableColumn<CatalogTableRow>;
}>;
// @public
export type DefaultCatalogPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<CatalogTableRow>[];
export interface DefaultCatalogPageProps {
// (undocumented)
actions?: TableProps<CatalogTableRow>['actions'];
};
// (undocumented)
columns?: TableColumn<CatalogTableRow>[];
// (undocumented)
initiallySelectedFilter?: UserListFilterKind;
}
// Warning: (ae-missing-release-tag) "EntityAboutCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityAboutCard: AboutCard;
export interface DependencyOfComponentsCardProps {
// (undocumented)
title?: string;
// (undocumented)
variant?: 'gridItem';
}
// Warning: (ae-missing-release-tag) "EntityDependencyOfComponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityDependencyOfComponentsCard: ({
variant,
title,
}: {
variant?: 'gridItem' | undefined;
title?: string | undefined;
}) => JSX.Element;
export interface DependsOnComponentsCardProps {
// (undocumented)
title?: string;
// (undocumented)
variant?: 'gridItem';
}
// Warning: (ae-missing-release-tag) "EntityDependsOnComponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityDependsOnComponentsCard: ({
variant,
title,
}: {
variant?: 'gridItem' | undefined;
title?: string | undefined;
}) => JSX.Element;
export interface DependsOnResourcesCardProps {
// (undocumented)
variant?: 'gridItem';
}
// Warning: (ae-missing-release-tag) "EntityDependsOnResourcesCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityDependsOnResourcesCard: ({
variant,
}: {
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityAboutCard: (props: AboutCardProps) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityHasComponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityHasComponentsCard: ({
variant,
}: {
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityDependencyOfComponentsCard: (
props: DependencyOfComponentsCardProps,
) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityHasResourcesCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityHasResourcesCard: ({
variant,
}: {
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityDependsOnComponentsCard: (
props: DependsOnComponentsCardProps,
) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityHasSubcomponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityHasSubcomponentsCard: ({
variant,
}: {
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityDependsOnResourcesCard: (
props: DependsOnResourcesCardProps,
) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityHasSystemsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityHasSystemsCard: ({
variant,
}: {
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityHasComponentsCard: (
props: HasComponentsCardProps,
) => JSX.Element;
// @public (undocumented)
export const EntityHasResourcesCard: (
props: HasResourcesCardProps,
) => JSX.Element;
// @public (undocumented)
export const EntityHasSubcomponentsCard: (
props: HasSubcomponentsCardProps,
) => JSX.Element;
// @public (undocumented)
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element;
// Warning: (ae-missing-release-tag) "EntityLayout" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export const EntityLayout: {
({
UNSTABLE_extraContextMenuItems,
UNSTABLE_contextMenuOptions,
children,
}: EntityLayoutProps): JSX.Element;
Route: (props: SubRoute) => null;
(props: EntityLayoutProps): JSX.Element;
Route: (props: EntityLayoutRouteProps) => null;
};
// Warning: (ae-missing-release-tag) "EntityLinksCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// @public (undocumented)
export interface EntityLayoutProps {
// (undocumented)
children?: React_2.ReactNode;
// Warning: (ae-forgotten-export) The symbol "contextMenuOptions" needs to be exported by the entry point index.d.ts
//
// (undocumented)
UNSTABLE_contextMenuOptions?: contextMenuOptions;
// Warning: (ae-forgotten-export) The symbol "ExtraContextMenuItem" needs to be exported by the entry point index.d.ts
//
// (undocumented)
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
}
// @public (undocumented)
export type EntityLayoutRouteProps = {
path: string;
title: string;
children: JSX.Element;
if?: (entity: Entity) => boolean;
tabProps?: TabProps<
React_2.ElementType,
{
component?: React_2.ElementType;
}
>;
};
// Warning: (ae-forgotten-export) The symbol "EntityLinksCard" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export const EntityLinksCard: ({
cols,
variant,
}: {
entity?: Entity | undefined;
cols?: number | ColumnBreakpoints | undefined;
variant?: 'gridItem' | undefined;
}) => JSX.Element;
export const EntityLinksCard: EntityLinksCard_2;
// @public (undocumented)
export interface EntityLinksCardProps {
// Warning: (ae-forgotten-export) The symbol "ColumnBreakpoints" needs to be exported by the entry point index.d.ts
//
// (undocumented)
cols?: ColumnBreakpoints | number;
// @deprecated (undocumented)
entity?: Entity;
// (undocumented)
variant?: 'gridItem';
}
// @public (undocumented)
export type EntityLinksEmptyStateClassKey = 'code';
// Warning: (ae-missing-release-tag) "EntityListContainer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntityListContainer: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
export function EntityListContainer(props: {
children: React_2.ReactNode;
}): JSX.Element;
// Warning: (ae-missing-release-tag) "EntityOrphanWarning" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export const EntityOrphanWarning: () => JSX.Element;
export function EntityOrphanWarning(): JSX.Element;
// Warning: (ae-missing-release-tag) "EntityProcessingErrorsPanel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export const EntityProcessingErrorsPanel: () => JSX.Element | null;
export function EntityProcessingErrorsPanel(): JSX.Element | null;
// Warning: (ae-missing-release-tag) "EntitySwitch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const EntitySwitch: {
({ children }: PropsWithChildren<{}>): JSX.Element | null;
Case: (_: {
if?:
| ((
entity: Entity,
context: {
apis: ApiHolder;
},
) => boolean | Promise<boolean>)
| undefined;
children: ReactNode;
}) => null;
(props: { children: React_2.ReactNode }): JSX.Element | null;
Case: (_props: EntitySwitchCaseProps) => null;
};
// Warning: (ae-missing-release-tag) "FilterContainer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const FilterContainer: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
export interface EntitySwitchCaseProps {
// (undocumented)
children: React_2.ReactNode;
// (undocumented)
if?: (
entity: Entity,
context: {
apis: ApiHolder;
},
) => boolean | Promise<boolean>;
}
// Warning: (ae-missing-release-tag) "FilteredEntityLayout" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const FilteredEntityLayout: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
export function FilterContainer(props: {
children: React_2.ReactNode;
}): JSX.Element;
// Warning: (ae-missing-release-tag) "hasCatalogProcessingErrors" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const hasCatalogProcessingErrors: (
export function FilteredEntityLayout(props: {
children: React_2.ReactNode;
}): JSX.Element;
// @public
export function hasCatalogProcessingErrors(
entity: Entity,
context: {
apis: ApiHolder;
},
) => Promise<boolean>;
): Promise<boolean>;
// Warning: (ae-missing-release-tag) "isComponentType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export interface HasComponentsCardProps {
// (undocumented)
variant?: 'gridItem';
}
// @public (undocumented)
export interface HasResourcesCardProps {
// (undocumented)
variant?: 'gridItem';
}
// @public (undocumented)
export interface HasSubcomponentsCardProps {
// (undocumented)
variant?: 'gridItem';
}
// @public (undocumented)
export interface HasSystemsCardProps {
// (undocumented)
variant?: 'gridItem';
}
// @public
export function isComponentType(type: string): (entity: Entity) => boolean;
// Warning: (ae-missing-release-tag) "isKind" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export function isKind(kind: string): (entity: Entity) => boolean;
// Warning: (ae-missing-release-tag) "isNamespace" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export function isNamespace(namespace: string): (entity: Entity) => boolean;
// Warning: (ae-missing-release-tag) "isOrphan" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const isOrphan: (entity: Entity) => boolean;
// @public
export function isOrphan(entity: Entity): boolean;
// @public (undocumented)
export type PluginCatalogComponentsNameToClassKey = {
@@ -354,19 +386,22 @@ export type PluginCatalogComponentsNameToClassKey = {
PluginCatalogSystemDiagramCard: SystemDiagramCardClassKey;
};
// Warning: (ae-missing-release-tag) "RelatedEntitiesCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const RelatedEntitiesCard: <T extends Entity>(props: {
variant?: 'gridItem' | undefined;
export const RelatedEntitiesCard: <T extends Entity>(
props: RelatedEntitiesCardProps<T>,
) => JSX.Element;
// @public (undocumented)
export type RelatedEntitiesCardProps<T extends Entity> = {
variant?: 'gridItem';
title: string;
columns: TableColumn<T>[];
entityKind?: string | undefined;
entityKind?: string;
relationType: string;
emptyMessage: string;
emptyHelpLink: string;
asRenderableEntities: (entities: Entity[]) => T[];
}) => JSX.Element;
};
// @public (undocumented)
export type SystemDiagramCardClassKey =
@@ -375,12 +410,4 @@ export type SystemDiagramCardClassKey =
| 'componentNode'
| 'apiNode'
| 'resourceNode';
// Warnings were encountered during analysis:
//
// src/components/CatalogTable/CatalogTable.d.ts:10:5 - (ae-forgotten-export) The symbol "CatalogTableProps" needs to be exported by the entry point index.d.ts
// src/components/CatalogTable/CatalogTable.d.ts:11:5 - (ae-forgotten-export) The symbol "columnFactories" needs to be exported by the entry point index.d.ts
// src/components/EntityLayout/EntityLayout.d.ts:43:5 - (ae-forgotten-export) The symbol "EntityLayoutProps" needs to be exported by the entry point index.d.ts
// src/components/EntityLayout/EntityLayout.d.ts:44:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts
// src/plugin.d.ts:22:5 - (ae-forgotten-export) The symbol "ColumnBreakpoints" needs to be exported by the entry point index.d.ts
```
+1
View File
@@ -39,6 +39,7 @@
"@backstage/integration-react": "^0.1.21",
"@backstage/plugin-catalog-common": "^0.1.2",
"@backstage/plugin-catalog-react": "^0.6.14",
"@backstage/search-common": "^0.2.2",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -72,13 +72,20 @@ const useStyles = makeStyles({
},
});
type AboutCardProps = {
/**
* Props for {@link AboutCard}.
*
* @public
*/
export interface AboutCardProps {
/** @deprecated The entity is now grabbed from context instead */
entity?: Entity;
variant?: InfoCardVariants;
};
}
export function AboutCard({ variant }: AboutCardProps) {
/** @public */
export function AboutCard(props: AboutCardProps) {
const { variant } = props;
const classes = useStyles();
const { entity } = useEntity();
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
@@ -33,11 +33,18 @@ const useStyles = makeStyles({
},
});
type Props = {
/**
* Props for {@link AboutContent}.
*
* @public
*/
export interface AboutContentProps {
entity: Entity;
};
}
export const AboutContent = ({ entity }: Props) => {
/** @public */
export function AboutContent(props: AboutContentProps) {
const { entity } = props;
const classes = useStyles();
const isSystem = entity.kind.toLocaleLowerCase('en-US') === 'system';
const isResource = entity.kind.toLocaleLowerCase('en-US') === 'resource';
@@ -154,4 +161,4 @@ export const AboutContent = ({ entity }: Props) => {
</AboutField>
</Grid>
);
};
}
@@ -36,14 +36,21 @@ const useStyles = makeStyles(theme => ({
},
}));
type Props = {
/**
* Props for {@link AboutField}.
*
* @public
*/
export interface AboutFieldProps {
label: string;
value?: string;
gridSizes?: Record<string, number>;
children?: React.ReactNode;
};
}
export const AboutField = ({ label, value, gridSizes, children }: Props) => {
/** @public */
export function AboutField(props: AboutFieldProps) {
const { label, value, gridSizes, children } = props;
const classes = useStyles();
const childElements = useElementFilter(children, c => c.getElements());
@@ -65,4 +72,4 @@ export const AboutField = ({ label, value, gridSizes, children }: Props) => {
{content}
</Grid>
);
};
}
@@ -15,5 +15,8 @@
*/
export { AboutCard } from './AboutCard';
export type { AboutCardProps } from './AboutCard';
export { AboutContent } from './AboutContent';
export type { AboutContentProps } from './AboutContent';
export { AboutField } from './AboutField';
export type { AboutFieldProps } from './AboutField';
@@ -21,8 +21,11 @@ import {
AsyncEntityProvider,
} from '@backstage/plugin-catalog-react';
export const CatalogEntityPage = () => (
<AsyncEntityProvider {...useEntityFromUrl()}>
<Outlet />
</AsyncEntityProvider>
);
/** @public */
export function CatalogEntityPage() {
return (
<AsyncEntityProvider {...useEntityFromUrl()}>
<Outlet />
</AsyncEntityProvider>
);
}
@@ -13,4 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CatalogEntityPage } from './CatalogEntityPage';
@@ -38,13 +38,18 @@ const useStyles = makeStyles((theme: Theme) =>
}),
);
type CatalogKindHeaderProps = {
/**
* Props for {@link CatalogKindHeader}.
*
* @public
*/
export interface CatalogKindHeaderProps {
initialFilter?: string;
};
}
export const CatalogKindHeader = ({
initialFilter = 'component',
}: CatalogKindHeaderProps) => {
/** @public */
export function CatalogKindHeader(props: CatalogKindHeaderProps) {
const { initialFilter = 'component' } = props;
const classes = useStyles();
const { kinds: allKinds = [] } = useEntityKinds();
const { updateFilters, queryParameters } = useEntityListProvider();
@@ -88,4 +93,4 @@ export const CatalogKindHeader = ({
))}
</Select>
);
};
}
@@ -13,4 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CatalogKindHeader } from './CatalogKindHeader';
export type { CatalogKindHeaderProps } from './CatalogKindHeader';
@@ -21,8 +21,8 @@ import {
DefaultCatalogPageProps,
} from './DefaultCatalogPage';
export const CatalogPage = (props: DefaultCatalogPageProps) => {
export function CatalogPage(props: DefaultCatalogPageProps) {
const outlet = useOutlet();
return outlet || <DefaultCatalogPage {...props} />;
};
}
@@ -44,7 +44,7 @@ import DashboardIcon from '@material-ui/icons/Dashboard';
import { fireEvent, screen } from '@testing-library/react';
import React from 'react';
import { createComponentRouteRef } from '../../routes';
import { EntityRow } from '../CatalogTable';
import { CatalogTableRow } from '../CatalogTable';
import { DefaultCatalogPage } from './DefaultCatalogPage';
describe('DefaultCatalogPage', () => {
@@ -180,7 +180,7 @@ describe('DefaultCatalogPage', () => {
}, 20_000);
it('should render the custom column passed as prop', async () => {
const columns: TableColumn<EntityRow>[] = [
const columns: TableColumn<CatalogTableRow>[] = [
{ title: 'Foo', field: 'entity.foo' },
{ title: 'Bar', field: 'entity.bar' },
{ title: 'Baz', field: 'entity.spec.lifecycle' },
@@ -208,7 +208,7 @@ describe('DefaultCatalogPage', () => {
}, 20_000);
it('should render the custom actions of an item passed as prop', async () => {
const actions: TableProps<EntityRow>['actions'] = [
const actions: TableProps<CatalogTableRow>['actions'] = [
() => {
return {
icon: () => <DashboardIcon fontSize="small" />,
@@ -35,8 +35,7 @@ import {
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { createComponentRouteRef } from '../../routes';
import { CatalogTable } from '../CatalogTable';
import { EntityRow } from '../CatalogTable/types';
import { CatalogTable, CatalogTableRow } from '../CatalogTable';
import {
FilteredEntityLayout,
EntityListContainer,
@@ -45,20 +44,18 @@ import {
import { CatalogKindHeader } from '../CatalogKindHeader';
/**
* DefaultCatalogPageProps
* Props for root catalog pages.
*
* @public
*/
export type DefaultCatalogPageProps = {
export interface DefaultCatalogPageProps {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<EntityRow>[];
actions?: TableProps<EntityRow>['actions'];
};
columns?: TableColumn<CatalogTableRow>[];
actions?: TableProps<CatalogTableRow>['actions'];
}
export const DefaultCatalogPage = ({
columns,
actions,
initiallySelectedFilter = 'owned',
}: DefaultCatalogPageProps) => {
export function DefaultCatalogPage(props: DefaultCatalogPageProps) {
const { columns, actions, initiallySelectedFilter = 'owned' } = props;
const orgName =
useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage';
const createComponentLink = useRouteRef(createComponentRouteRef);
@@ -90,4 +87,4 @@ export const DefaultCatalogPage = ({
</EntityListProvider>
</PageWithHeader>
);
};
}
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CatalogPage } from './CatalogPage';
export { DefaultCatalogPage } from './DefaultCatalogPage';
export type { DefaultCatalogPageProps } from './DefaultCatalogPage';
@@ -24,6 +24,7 @@ import {
makeStyles,
} from '@material-ui/core';
import { Link } from '@backstage/core-components';
import { IndexableDocument } from '@backstage/search-common';
const useStyles = makeStyles({
flexContainer: {
@@ -36,7 +37,19 @@ const useStyles = makeStyles({
},
});
export const CatalogResultListItem = ({ result }: any) => {
/**
* Props for {@link CatalogResultListItem}.
*
* @public
*/
export interface CatalogResultListItemProps {
result: IndexableDocument;
}
/** @public */
export function CatalogResultListItem(props: CatalogResultListItemProps) {
const result = props.result as any;
const classes = useStyles();
return (
<Link to={result.location}>
@@ -57,4 +70,4 @@ export const CatalogResultListItem = ({ result }: any) => {
<Divider component="li" />
</Link>
);
};
}
@@ -15,3 +15,4 @@
*/
export { CatalogResultListItem } from './CatalogResultListItem';
export type { CatalogResultListItemProps } from './CatalogResultListItem';
@@ -28,8 +28,8 @@ import Edit from '@material-ui/icons/Edit';
import OpenInNew from '@material-ui/icons/OpenInNew';
import { capitalize } from 'lodash';
import React, { useMemo } from 'react';
import * as columnFactories from './columns';
import { EntityRow } from './types';
import { columnFactories } from './columns';
import { CatalogTableRow } from './types';
import {
CodeSnippet,
Table,
@@ -38,16 +38,23 @@ import {
WarningPanel,
} from '@backstage/core-components';
type CatalogTableProps = {
columns?: TableColumn<EntityRow>[];
actions?: TableProps<EntityRow>['actions'];
};
/**
* Props for {@link CatalogTable}.
*
* @public
*/
export interface CatalogTableProps {
columns?: TableColumn<CatalogTableRow>[];
actions?: TableProps<CatalogTableRow>['actions'];
}
export const CatalogTable = ({ columns, actions }: CatalogTableProps) => {
/** @public */
export const CatalogTable = (props: CatalogTableProps) => {
const { columns, actions } = props;
const { isStarredEntity, toggleStarredEntity } = useStarredEntities();
const { loading, error, entities, filters } = useEntityListProvider();
const defaultColumns: TableColumn<EntityRow>[] = useMemo(
const defaultColumns: TableColumn<CatalogTableRow>[] = useMemo(
() => [
columnFactories.createNameColumn({ defaultKind: filters.kind?.value }),
columnFactories.createSystemColumn(),
@@ -77,7 +84,7 @@ export const CatalogTable = ({ columns, actions }: CatalogTableProps) => {
);
}
const defaultActions: TableProps<EntityRow>['actions'] = [
const defaultActions: TableProps<CatalogTableRow>['actions'] = [
({ entity }) => {
const url = getEntityMetadataViewUrl(entity);
return {
@@ -148,7 +155,7 @@ export const CatalogTable = ({ columns, actions }: CatalogTableProps) => {
const showPagination = rows.length > 20;
return (
<Table<EntityRow>
<Table<CatalogTableRow>
isLoading={loading}
columns={columns || defaultColumns}
options={{
@@ -20,120 +20,115 @@ import {
EntityRefLinks,
} from '@backstage/plugin-catalog-react';
import { Chip } from '@material-ui/core';
import { EntityRow } from './types';
import { CatalogTableRow } from './types';
import { OverflowTooltip, TableColumn } from '@backstage/core-components';
import { Entity } from '@backstage/catalog-model';
type NameColumnProps = {
defaultKind?: string;
};
// The columnFactories symbol is not directly exported, but through the
// CatalogTable.columns field.
/** @public */
export const columnFactories = Object.freeze({
createNameColumn(options?: {
defaultKind?: string;
}): TableColumn<CatalogTableRow> {
function formatContent(entity: Entity): string {
return (
entity.metadata?.title ||
formatEntityRefTitle(entity, {
defaultKind: options?.defaultKind,
})
);
}
export function createNameColumn(
props?: NameColumnProps,
): TableColumn<EntityRow> {
function formatContent(entity: Entity): string {
return (
entity.metadata?.title ||
formatEntityRefTitle(entity, {
defaultKind: props?.defaultKind,
})
);
}
return {
title: 'Name',
field: 'resolved.name',
highlight: true,
customSort({ entity: entity1 }, { entity: entity2 }) {
// TODO: We could implement this more efficiently by comparing field by field.
// This has similar issues as above.
return formatContent(entity1).localeCompare(formatContent(entity2));
},
render: ({ entity }) => (
<EntityRefLink
entityRef={entity}
defaultKind={props?.defaultKind || 'Component'}
title={entity.metadata?.title}
/>
),
};
}
export function createSystemColumn(): TableColumn<EntityRow> {
return {
title: 'System',
field: 'resolved.partOfSystemRelationTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.partOfSystemRelations}
defaultKind="system"
/>
),
};
}
export function createOwnerColumn(): TableColumn<EntityRow> {
return {
title: 'Owner',
field: 'resolved.ownedByRelationsTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.ownedByRelations}
defaultKind="group"
/>
),
};
}
export function createSpecTypeColumn(): TableColumn<EntityRow> {
return {
title: 'Type',
field: 'entity.spec.type',
hidden: true,
};
}
export function createSpecLifecycleColumn(): TableColumn<EntityRow> {
return {
title: 'Lifecycle',
field: 'entity.spec.lifecycle',
};
}
export function createMetadataDescriptionColumn(): TableColumn<EntityRow> {
return {
title: 'Description',
field: 'entity.metadata.description',
render: ({ entity }) => (
<OverflowTooltip
text={entity.metadata.description}
placement="bottom-start"
/>
),
width: 'auto',
};
}
export function createTagsColumn(): TableColumn<EntityRow> {
return {
title: 'Tags',
field: 'entity.metadata.tags',
cellStyle: {
padding: '0px 16px 0px 20px',
},
render: ({ entity }) => (
<>
{entity.metadata.tags &&
entity.metadata.tags.map(t => (
<Chip
key={t}
label={t}
size="small"
variant="outlined"
style={{ marginBottom: '0px' }}
/>
))}
</>
),
};
}
return {
title: 'Name',
field: 'resolved.name',
highlight: true,
customSort({ entity: entity1 }, { entity: entity2 }) {
// TODO: We could implement this more efficiently by comparing field by field.
// This has similar issues as above.
return formatContent(entity1).localeCompare(formatContent(entity2));
},
render: ({ entity }) => (
<EntityRefLink
entityRef={entity}
defaultKind={options?.defaultKind || 'Component'}
title={entity.metadata?.title}
/>
),
};
},
createSystemColumn(): TableColumn<CatalogTableRow> {
return {
title: 'System',
field: 'resolved.partOfSystemRelationTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.partOfSystemRelations}
defaultKind="system"
/>
),
};
},
createOwnerColumn(): TableColumn<CatalogTableRow> {
return {
title: 'Owner',
field: 'resolved.ownedByRelationsTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.ownedByRelations}
defaultKind="group"
/>
),
};
},
createSpecTypeColumn(): TableColumn<CatalogTableRow> {
return {
title: 'Type',
field: 'entity.spec.type',
hidden: true,
};
},
createSpecLifecycleColumn(): TableColumn<CatalogTableRow> {
return {
title: 'Lifecycle',
field: 'entity.spec.lifecycle',
};
},
createMetadataDescriptionColumn(): TableColumn<CatalogTableRow> {
return {
title: 'Description',
field: 'entity.metadata.description',
render: ({ entity }) => (
<OverflowTooltip
text={entity.metadata.description}
placement="bottom-start"
/>
),
width: 'auto',
};
},
createTagsColumn(): TableColumn<CatalogTableRow> {
return {
title: 'Tags',
field: 'entity.metadata.tags',
cellStyle: {
padding: '0px 16px 0px 20px',
},
render: ({ entity }) => (
<>
{entity.metadata.tags &&
entity.metadata.tags.map(t => (
<Chip
key={t}
label={t}
size="small"
variant="outlined"
style={{ marginBottom: '0px' }}
/>
))}
</>
),
};
},
});
@@ -15,4 +15,5 @@
*/
export { CatalogTable } from './CatalogTable';
export type { EntityRow } from './types';
export type { CatalogTableProps } from './CatalogTable';
export type { CatalogTableRow } from './types';
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity, EntityName } from '@backstage/catalog-model';
export type EntityRow = {
/** @public */
export interface CatalogTableRow {
entity: Entity;
resolved: {
name: string;
@@ -24,4 +26,4 @@ export type EntityRow = {
ownedByRelationsTitle?: string;
ownedByRelations: EntityName[];
};
};
}
@@ -23,15 +23,16 @@ import {
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface DependencyOfComponentsCardProps {
variant?: 'gridItem';
title?: string;
};
}
export const DependencyOfComponentsCard = ({
variant = 'gridItem',
title = 'Dependency of components',
}: Props) => {
export function DependencyOfComponentsCard(
props: DependencyOfComponentsCardProps,
) {
const { variant = 'gridItem', title = 'Dependency of components' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -44,4 +45,4 @@ export const DependencyOfComponentsCard = ({
asRenderableEntities={asComponentEntities}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { DependencyOfComponentsCard } from './DependencyOfComponentsCard';
export type { DependencyOfComponentsCardProps } from './DependencyOfComponentsCard';
@@ -23,15 +23,14 @@ import {
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface DependsOnComponentsCardProps {
variant?: 'gridItem';
title?: string;
};
}
export const DependsOnComponentsCard = ({
variant = 'gridItem',
title = 'Depends on components',
}: Props) => {
export function DependsOnComponentsCard(props: DependsOnComponentsCardProps) {
const { variant = 'gridItem', title = 'Depends on components' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -44,4 +43,4 @@ export const DependsOnComponentsCard = ({
asRenderableEntities={asComponentEntities}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { DependsOnComponentsCard } from './DependsOnComponentsCard';
export type { DependsOnComponentsCardProps } from './DependsOnComponentsCard';
@@ -23,11 +23,13 @@ import {
resourceEntityColumns,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface DependsOnResourcesCardProps {
variant?: 'gridItem';
};
}
export const DependsOnResourcesCard = ({ variant = 'gridItem' }: Props) => {
export function DependsOnResourcesCard(props: DependsOnResourcesCardProps) {
const { variant = 'gridItem' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -40,4 +42,4 @@ export const DependsOnResourcesCard = ({ variant = 'gridItem' }: Props) => {
asRenderableEntities={asResourceEntities}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { DependsOnResourcesCard } from './DependsOnResourcesCard';
export type { DependsOnResourcesCardProps } from './DependsOnResourcesCard';
@@ -41,30 +41,31 @@ const useStyles = makeStyles({
// NOTE(freben): Intentionally not exported at this point, since it's part of
// the unstable extra context menu items concept below
type ExtraContextMenuItem = {
interface ExtraContextMenuItem {
title: string;
Icon: IconComponent;
onClick: () => void;
};
}
// unstable context menu option, eg: disable the unregister entity menu
type contextMenuOptions = {
interface contextMenuOptions {
disableUnregister: boolean;
};
}
type Props = {
interface EntityContextMenuProps {
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
UNSTABLE_contextMenuOptions?: contextMenuOptions;
onUnregisterEntity: () => void;
onInspectEntity: () => void;
};
}
export const EntityContextMenu = ({
UNSTABLE_extraContextMenuItems,
UNSTABLE_contextMenuOptions,
onUnregisterEntity,
onInspectEntity,
}: Props) => {
export function EntityContextMenu(props: EntityContextMenuProps) {
const {
UNSTABLE_extraContextMenuItems,
UNSTABLE_contextMenuOptions,
onUnregisterEntity,
onInspectEntity,
} = props;
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();
const classes = useStyles();
const unregisterPermission = useEntityPermission(
@@ -150,4 +151,4 @@ export const EntityContextMenu = ({
</Popover>
</>
);
};
}
@@ -49,7 +49,8 @@ import React, { useContext, useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router';
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
type SubRoute = {
/** @public */
export type EntityLayoutRouteProps = {
path: string;
title: string;
children: JSX.Element;
@@ -59,19 +60,15 @@ type SubRoute = {
const dataKey = 'plugin.catalog.entityLayoutRoute';
const Route: (props: SubRoute) => null = () => null;
const Route: (props: EntityLayoutRouteProps) => null = () => null;
attachComponentData(Route, dataKey, true);
attachComponentData(Route, 'core.gatherMountPoints', true); // This causes all mount points that are discovered within this route to use the path of the route itself
// This causes all mount points that are discovered within this route to use the path of the route itself
attachComponentData(Route, 'core.gatherMountPoints', true);
const EntityLayoutTitle = ({
entity,
title,
}: {
function EntityLayoutTitle(props: {
title: string;
entity: Entity | undefined;
}) => {
}) {
const { entity, title } = props;
return (
<Box display="inline-flex" alignItems="center" height="1em" maxWidth="100%">
<Box
@@ -85,14 +82,14 @@ const EntityLayoutTitle = ({
{entity && <FavoriteEntity entity={entity} />}
</Box>
);
};
}
const headerProps = (
function headerProps(
paramKind: string | undefined,
paramNamespace: string | undefined,
paramName: string | undefined,
entity: Entity | undefined,
): { headerTitle: string; headerType: string } => {
): { headerTitle: string; headerType: string } {
const kind = paramKind ?? entity?.kind ?? '';
const namespace = paramNamespace ?? entity?.metadata.namespace ?? '';
const name =
@@ -110,9 +107,10 @@ const headerProps = (
return t;
})(),
};
};
}
const EntityLabels = ({ entity }: { entity: Entity }) => {
function EntityLabels(props: { entity: Entity }) {
const { entity } = props;
const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);
return (
<>
@@ -133,26 +131,27 @@ const EntityLabels = ({ entity }: { entity: Entity }) => {
)}
</>
);
};
}
// NOTE(freben): Intentionally not exported at this point, since it's part of
// the unstable extra context menu items concept below
type ExtraContextMenuItem = {
interface ExtraContextMenuItem {
title: string;
Icon: IconComponent;
onClick: () => void;
};
}
// unstable context menu option, eg: disable the unregister entity menu
type contextMenuOptions = {
interface contextMenuOptions {
disableUnregister: boolean;
};
}
type EntityLayoutProps = {
/** @public */
export interface EntityLayoutProps {
UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];
UNSTABLE_contextMenuOptions?: contextMenuOptions;
children?: React.ReactNode;
};
}
/**
* EntityLayout is a compound component, which allows you to define a layout for
@@ -168,12 +167,15 @@ type EntityLayoutProps = {
* </EntityLayout.Route>
* </EntityLayout>
* ```
*
* @public
*/
export const EntityLayout = ({
UNSTABLE_extraContextMenuItems,
UNSTABLE_contextMenuOptions,
children,
}: EntityLayoutProps) => {
export const EntityLayout = (props: EntityLayoutProps) => {
const {
UNSTABLE_extraContextMenuItems,
UNSTABLE_contextMenuOptions,
children,
} = props;
const { kind, namespace, name } = useEntityCompoundName();
const { entity, loading, error } = useContext(EntityContext);
const location = useLocation();
@@ -186,18 +188,18 @@ export const EntityLayout = ({
withStrictError:
'Child of EntityLayout must be an EntityLayout.Route',
})
.getElements<SubRoute>() // all nodes, element data, maintain structure or not?
.flatMap(({ props }) => {
if (props.if && entity && !props.if(entity)) {
.getElements<EntityLayoutRouteProps>() // all nodes, element data, maintain structure or not?
.flatMap(({ props: elementProps }) => {
if (elementProps.if && entity && !elementProps.if(entity)) {
return [];
}
return [
{
path: props.path,
title: props.title,
children: props.children,
tabProps: props.tabProps,
path: elementProps.path,
title: elementProps.title,
children: elementProps.children,
tabProps: elementProps.tabProps,
},
];
}),
@@ -13,4 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { EntityLayout } from './EntityLayout';
export type { EntityLayoutProps, EntityLayoutRouteProps } from './EntityLayout';
@@ -21,18 +21,19 @@ import React from 'react';
import { EntityLinksEmptyState } from './EntityLinksEmptyState';
import { LinksGridList } from './LinksGridList';
import { ColumnBreakpoints } from './types';
import { IconComponent, useApp } from '@backstage/core-plugin-api';
import { InfoCard } from '@backstage/core-components';
type Props = {
/** @public */
export interface EntityLinksCardProps {
/** @deprecated The entity is now grabbed from context instead */
entity?: Entity;
cols?: ColumnBreakpoints | number;
variant?: 'gridItem';
};
}
export const EntityLinksCard = ({ cols = undefined, variant }: Props) => {
export function EntityLinksCard(props: EntityLinksCardProps) {
const { cols = undefined, variant } = props;
const { entity } = useEntity();
const app = useApp();
@@ -57,4 +58,4 @@ export const EntityLinksCard = ({ cols = undefined, variant }: Props) => {
)}
</InfoCard>
);
};
}
@@ -40,7 +40,7 @@ const useStyles = makeStyles<BackstageTheme>(
{ name: 'PluginCatalogEntityLinksEmptyState' },
);
export const EntityLinksEmptyState = () => {
export function EntityLinksEmptyState() {
const classes = useStyles();
return (
@@ -68,4 +68,4 @@ export const EntityLinksEmptyState = () => {
</Button>
</>
);
};
}
@@ -17,7 +17,6 @@
import { makeStyles, Box, Typography } from '@material-ui/core';
import LanguageIcon from '@material-ui/icons/Language';
import React from 'react';
import { Link } from '@backstage/core-components';
import { IconComponent } from '@backstage/core-plugin-api';
@@ -32,15 +31,12 @@ const useStyles = makeStyles({
},
});
export const IconLink = ({
href,
text,
Icon,
}: {
export function IconLink(props: {
href: string;
text?: string;
Icon?: IconComponent;
}) => {
}) {
const { href, text, Icon } = props;
const classes = useStyles();
return (
@@ -57,4 +53,4 @@ export const IconLink = ({
</Box>
</Box>
);
};
}
@@ -21,18 +21,19 @@ import { ColumnBreakpoints } from './types';
import { useDynamicColumns } from './useDynamicColumns';
import { IconComponent } from '@backstage/core-plugin-api';
export type LinksGridListItem = {
export interface LinksGridListItem {
href: string;
text?: string;
Icon?: IconComponent;
};
}
type Props = {
interface LinksGridListProps {
items: LinksGridListItem[];
cols?: ColumnBreakpoints | number;
};
}
export const LinksGridList = ({ items, cols = undefined }: Props) => {
export function LinksGridList(props: LinksGridListProps) {
const { items, cols = undefined } = props;
const numOfCols = useDynamicColumns(cols);
return (
@@ -44,4 +45,4 @@ export const LinksGridList = ({ items, cols = undefined }: Props) => {
))}
</ImageList>
);
};
}
@@ -15,4 +15,5 @@
*/
export { EntityLinksCard } from './EntityLinksCard';
export type { EntityLinksCardProps } from './EntityLinksCard';
export type { EntityLinksEmptyStateClassKey } from './EntityLinksEmptyState';
@@ -16,7 +16,6 @@
import React from 'react';
import { renderInTestApp } from '@backstage/test-utils';
import { EntityNotFound } from './EntityNotFound';
describe('<EntityNotFound />', () => {
@@ -18,7 +18,6 @@ import React from 'react';
import { Grid, Button, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import { Illo } from './Illo';
const useStyles = makeStyles<BackstageTheme>(theme => ({
@@ -43,7 +42,7 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
},
}));
export const EntityNotFound = () => {
export function EntityNotFound() {
const classes = useStyles();
return (
@@ -67,4 +66,4 @@ export const EntityNotFound = () => {
</Grid>
</Grid>
);
};
}
@@ -34,7 +34,7 @@ const useStyles = makeStyles(theme => ({
},
}));
export const Illo = () => {
export function Illo() {
const classes = useStyles();
return (
<img
@@ -43,4 +43,4 @@ export const Illo = () => {
alt="Illustration on entity not found page"
/>
);
};
}
@@ -13,4 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { EntityNotFound } from './EntityNotFound';
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import userEvent from '@testing-library/user-event';
import React from 'react';
import { DeleteEntityDialog } from './DeleteEntityDialog';
@@ -21,7 +22,6 @@ import { CatalogApi } from '@backstage/catalog-client';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { screen, waitFor } from '@testing-library/react';
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
import { AlertApi, alertApiRef } from '@backstage/core-plugin-api';
describe('DeleteEntityDialog', () => {
@@ -21,19 +21,15 @@ import React, { useState } from 'react';
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
import { assertError } from '@backstage/errors';
type Props = {
interface DeleteEntityDialogProps {
open: boolean;
onClose: () => any;
onConfirm: () => any;
entity: Entity;
};
}
export const DeleteEntityDialog = ({
open,
onClose,
onConfirm,
entity,
}: Props) => {
export function DeleteEntityDialog(props: DeleteEntityDialogProps) {
const { open, onClose, onConfirm, entity } = props;
const [busy, setBusy] = useState(false);
const catalogApi = useApi(catalogApiRef);
const alertApi = useApi(alertApiRef);
@@ -72,4 +68,4 @@ export const DeleteEntityDialog = ({
</DialogActions>
</Dialog>
);
};
}
@@ -22,13 +22,23 @@ import { useNavigate } from 'react-router';
import { DeleteEntityDialog } from './DeleteEntityDialog';
import { useRouteRef } from '@backstage/core-plugin-api';
export const isOrphan = (entity: Entity) =>
entity?.metadata?.annotations?.['backstage.io/orphan'] === 'true';
/**
* Returns true if the given entity has the orphan annotation given by the
* catalog.
*
* @public
*/
export function isOrphan(entity: Entity): boolean {
return entity?.metadata?.annotations?.['backstage.io/orphan'] === 'true';
}
/**
* Displays a warning alert if the entity is marked as orphan with the ability to delete said entity.
* Displays a warning alert if the entity is marked as orphan with the ability
* to delete said entity.
*
* @public
*/
export const EntityOrphanWarning = () => {
export function EntityOrphanWarning() {
const navigate = useNavigate();
const catalogLink = useRouteRef(catalogRouteRef);
const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
@@ -53,4 +63,4 @@ export const EntityOrphanWarning = () => {
/>
</>
);
};
}
@@ -41,12 +41,12 @@ const errorFilter = (i: EntityStatusItem) =>
i.level === 'error' &&
i.type === ENTITY_STATUS_CATALOG_PROCESSING_TYPE;
type GetOwnAndAncestorsErrorsResponse = {
interface GetOwnAndAncestorsErrorsResponse {
items: {
errors: SerializedError[];
entity: Entity;
}[];
};
}
async function getOwnAndAncestorsErrors(
entityRef: string,
@@ -66,10 +66,15 @@ async function getOwnAndAncestorsErrors(
return { items };
}
export const hasCatalogProcessingErrors = async (
/**
* Returns true if the given entity has any processing errors on it.
*
* @public
*/
export async function hasCatalogProcessingErrors(
entity: Entity,
context: { apis: ApiHolder },
) => {
) {
const catalogApi = context.apis.get(catalogApiRef);
if (!catalogApi) {
throw new Error(`No implementation available for ${catalogApiRef}`);
@@ -80,12 +85,14 @@ export const hasCatalogProcessingErrors = async (
catalogApi,
);
return errors.items.length > 0;
};
}
/**
* Displays a list of errors from the ancestors of the current entity.
*
* @public
*/
export const EntityProcessingErrorsPanel = () => {
export function EntityProcessingErrorsPanel() {
const { entity } = useEntity();
const entityRef = stringifyEntityRef(entity);
const catalogApi = useApi(catalogApiRef);
@@ -123,4 +130,4 @@ export const EntityProcessingErrorsPanel = () => {
))}
</>
);
};
}
@@ -16,7 +16,7 @@
import { Entity } from '@backstage/catalog-model';
import { useEntity } from '@backstage/plugin-catalog-react';
import React, { PropsWithChildren, ReactNode } from 'react';
import React from 'react';
import {
attachComponentData,
useApiHolder,
@@ -27,34 +27,38 @@ import useAsync from 'react-use/lib/useAsync';
const ENTITY_SWITCH_KEY = 'core.backstage.entitySwitch';
const EntitySwitchCase = (_: {
/** @public */
export interface EntitySwitchCaseProps {
if?: (
entity: Entity,
context: { apis: ApiHolder },
) => boolean | Promise<boolean>;
children: ReactNode;
}) => null;
children: React.ReactNode;
}
attachComponentData(EntitySwitchCase, ENTITY_SWITCH_KEY, true);
const EntitySwitchCaseComponent = (_props: EntitySwitchCaseProps) => null;
type SwitchCase = {
attachComponentData(EntitySwitchCaseComponent, ENTITY_SWITCH_KEY, true);
interface EntitySwitchCase {
if?: (
entity: Entity,
context: { apis: ApiHolder },
) => boolean | Promise<boolean>;
children: JSX.Element;
};
}
type SwitchCaseResult = {
if: boolean | Promise<boolean>;
children: JSX.Element;
};
export const EntitySwitch = ({ children }: PropsWithChildren<{}>) => {
/** @public */
export const EntitySwitch = (props: { children: React.ReactNode }) => {
const { entity } = useEntity();
const apis = useApiHolder();
const results = useElementFilter(
children,
props.children,
collection =>
collection
.selectByComponentData({
@@ -64,7 +68,7 @@ export const EntitySwitch = ({ children }: PropsWithChildren<{}>) => {
.getElements()
.flatMap<SwitchCaseResult>((element: React.ReactElement) => {
const { if: condition, children: elementsChildren } =
element.props as SwitchCase;
element.props as EntitySwitchCase;
return [
{
if: condition?.(entity, { apis }) ?? true,
@@ -110,4 +114,4 @@ function AsyncEntitySwitch({ results }: { results: SwitchCaseResult[] }) {
return value;
}
EntitySwitch.Case = EntitySwitchCase;
EntitySwitch.Case = EntitySwitchCaseComponent;
@@ -22,10 +22,18 @@ function strCmp(a: string | undefined, b: string | undefined): boolean {
);
}
/**
* For use in EntitySwitch.Case. Matches if the entity is of a given kind.
* @public
*/
export function isKind(kind: string) {
return (entity: Entity) => strCmp(entity?.kind, kind);
}
/**
* For use in EntitySwitch.Case. Matches if the entity is a Component of a given spec.type.
* @public
*/
export function isComponentType(type: string) {
return (entity: Entity) => {
if (!strCmp(entity?.kind, 'component')) {
@@ -36,6 +44,10 @@ export function isComponentType(type: string) {
};
}
/**
* For use in EntitySwitch.Case. Matches if the entity is in a given namespace.
* @public
*/
export function isNamespace(namespace: string) {
return (entity: Entity) => strCmp(entity?.metadata?.namespace, namespace);
}
@@ -15,4 +15,5 @@
*/
export { EntitySwitch } from './EntitySwitch';
export type { EntitySwitchCaseProps } from './EntitySwitch';
export { isKind, isNamespace, isComponentType } from './conditions';
@@ -15,10 +15,13 @@
*/
import { Grid } from '@material-ui/core';
import React, { PropsWithChildren } from 'react';
import React from 'react';
export const EntityListContainer = ({ children }: PropsWithChildren<{}>) => (
<Grid item xs={12} lg={10}>
{children}
</Grid>
);
/** @public */
export function EntityListContainer(props: { children: React.ReactNode }) {
return (
<Grid item xs={12} lg={10}>
{props.children}
</Grid>
);
}
@@ -25,9 +25,10 @@ import {
useTheme,
} from '@material-ui/core';
import FilterListIcon from '@material-ui/icons/FilterList';
import React, { useState, PropsWithChildren } from 'react';
import React, { useState } from 'react';
export const FilterContainer = ({ children }: PropsWithChildren<{}>) => {
/** @public */
export function FilterContainer(props: { children: React.ReactNode }) {
const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>
theme.breakpoints.down('md'),
);
@@ -59,13 +60,13 @@ export const FilterContainer = ({ children }: PropsWithChildren<{}>) => {
>
Filters
</Typography>
{children}
{props.children}
</Box>
</Drawer>
</>
) : (
<Grid item lg={2}>
{children}
{props.children}
</Grid>
);
};
}
@@ -15,10 +15,13 @@
*/
import { Grid } from '@material-ui/core';
import React, { PropsWithChildren } from 'react';
import React from 'react';
export const FilteredEntityLayout = ({ children }: PropsWithChildren<{}>) => (
<Grid container style={{ position: 'relative' }}>
{children}
</Grid>
);
/** @public */
export function FilteredEntityLayout(props: { children: React.ReactNode }) {
return (
<Grid container style={{ position: 'relative' }}>
{props.children}
</Grid>
);
}
@@ -23,11 +23,13 @@ import {
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface HasComponentsCardProps {
variant?: 'gridItem';
};
}
export const HasComponentsCard = ({ variant = 'gridItem' }: Props) => {
export function HasComponentsCard(props: HasComponentsCardProps) {
const { variant = 'gridItem' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -40,4 +42,4 @@ export const HasComponentsCard = ({ variant = 'gridItem' }: Props) => {
asRenderableEntities={asComponentEntities}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { HasComponentsCard } from './HasComponentsCard';
export type { HasComponentsCardProps } from './HasComponentsCard';
@@ -23,11 +23,13 @@ import {
resourceEntityHelpLink,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface HasResourcesCardProps {
variant?: 'gridItem';
};
}
export const HasResourcesCard = ({ variant = 'gridItem' }: Props) => {
export function HasResourcesCard(props: HasResourcesCardProps) {
const { variant = 'gridItem' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -40,4 +42,4 @@ export const HasResourcesCard = ({ variant = 'gridItem' }: Props) => {
emptyHelpLink={resourceEntityHelpLink}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { HasResourcesCard } from './HasResourcesCard';
export type { HasResourcesCardProps } from './HasResourcesCard';
@@ -22,11 +22,13 @@ import {
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface HasSubcomponentsCardProps {
variant?: 'gridItem';
};
}
export const HasSubcomponentsCard = ({ variant = 'gridItem' }: Props) => {
export function HasSubcomponentsCard(props: HasSubcomponentsCardProps) {
const { variant = 'gridItem' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -39,4 +41,4 @@ export const HasSubcomponentsCard = ({ variant = 'gridItem' }: Props) => {
emptyHelpLink="https://backstage.io/docs/features/software-catalog/descriptor-format#specsubcomponentof-optional"
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { HasSubcomponentsCard } from './HasSubcomponentsCard';
export type { HasSubcomponentsCardProps } from './HasSubcomponentsCard';
@@ -23,11 +23,13 @@ import {
systemEntityHelpLink,
} from '../RelatedEntitiesCard';
type Props = {
/** @public */
export interface HasSystemsCardProps {
variant?: 'gridItem';
};
}
export const HasSystemsCard = ({ variant = 'gridItem' }: Props) => {
export function HasSystemsCard(props: HasSystemsCardProps) {
const { variant = 'gridItem' } = props;
return (
<RelatedEntitiesCard
variant={variant}
@@ -40,4 +42,4 @@ export const HasSystemsCard = ({ variant = 'gridItem' }: Props) => {
emptyHelpLink={systemEntityHelpLink}
/>
);
};
}
@@ -15,3 +15,4 @@
*/
export { HasSystemsCard } from './HasSystemsCard';
export type { HasSystemsCardProps } from './HasSystemsCard';
@@ -30,7 +30,8 @@ import {
TableColumn,
} from '@backstage/core-components';
type Props<T extends Entity> = {
/** @public */
export type RelatedEntitiesCardProps<T extends Entity> = {
variant?: 'gridItem';
title: string;
columns: TableColumn<T>[];
@@ -53,7 +54,9 @@ type Props<T extends Entity> = {
*
* @public
*/
export const RelatedEntitiesCard = <T extends Entity>(props: Props<T>) => {
export function RelatedEntitiesCard<T extends Entity>(
props: RelatedEntitiesCardProps<T>,
) {
const {
variant = 'gridItem',
title,
@@ -103,4 +106,4 @@ export const RelatedEntitiesCard = <T extends Entity>(props: Props<T>) => {
entities={asRenderableEntities(entities || [])}
/>
);
};
}
@@ -15,4 +15,5 @@
*/
export { RelatedEntitiesCard } from './RelatedEntitiesCard';
export type { RelatedEntitiesCardProps } from './RelatedEntitiesCard';
export * from './presets';
+13 -3
View File
@@ -23,8 +23,7 @@
export * from './components/AboutCard';
export * from './components/CatalogKindHeader';
export * from './components/CatalogResultListItem';
export { CatalogTable } from './components/CatalogTable';
export type { EntityRow as CatalogTableRow } from './components/CatalogTable';
export * from './components/CatalogTable';
export * from './components/CatalogTable/columns';
export * from './components/EntityLayout';
export * from './components/EntityOrphanWarning';
@@ -49,6 +48,17 @@ export {
RelatedEntitiesCard,
} from './plugin';
export type { EntityLinksEmptyStateClassKey } from './components/EntityLinksCard';
export type { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard';
export type { DependsOnComponentsCardProps } from './components/DependsOnComponentsCard';
export type { DependsOnResourcesCardProps } from './components/DependsOnResourcesCard';
export type {
EntityLinksEmptyStateClassKey,
EntityLinksCardProps,
} from './components/EntityLinksCard';
export type { SystemDiagramCardClassKey } from './components/SystemDiagramCard';
export type { DefaultCatalogPageProps } from './components/CatalogPage';
export type { HasComponentsCardProps } from './components/HasComponentsCard';
export type { HasResourcesCardProps } from './components/HasResourcesCard';
export type { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard';
export type { HasSystemsCardProps } from './components/HasSystemsCard';
export type { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard';
+74 -33
View File
@@ -15,6 +15,7 @@
*/
import { CatalogClient } from '@backstage/catalog-client';
import { Entity } from '@backstage/catalog-model';
import {
catalogApiRef,
catalogRouteRef,
@@ -32,7 +33,18 @@ import {
fetchApiRef,
storageApiRef,
} from '@backstage/core-plugin-api';
import { AboutCardProps } from './components/AboutCard';
import { DefaultCatalogPageProps } from './components/CatalogPage';
import { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard';
import { DependsOnComponentsCardProps } from './components/DependsOnComponentsCard';
import { DependsOnResourcesCardProps } from './components/DependsOnResourcesCard';
import { HasComponentsCardProps } from './components/HasComponentsCard';
import { HasResourcesCardProps } from './components/HasResourcesCard';
import { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard';
import { HasSystemsCardProps } from './components/HasSystemsCard';
import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard';
/** @public */
export const catalogPlugin = createPlugin({
id: 'catalog',
apis: [
@@ -62,16 +74,19 @@ export const catalogPlugin = createPlugin({
},
});
export const CatalogIndexPage = catalogPlugin.provide(
createRoutableExtension({
name: 'CatalogIndexPage',
component: () =>
import('./components/CatalogPage').then(m => m.CatalogPage),
mountPoint: catalogRouteRef,
}),
);
/** @public */
export const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element =
catalogPlugin.provide(
createRoutableExtension({
name: 'CatalogIndexPage',
component: () =>
import('./components/CatalogPage').then(m => m.CatalogPage),
mountPoint: catalogRouteRef,
}),
);
export const CatalogEntityPage = catalogPlugin.provide(
/** @public */
export const CatalogEntityPage: () => JSX.Element = catalogPlugin.provide(
createRoutableExtension({
name: 'CatalogEntityPage',
component: () =>
@@ -80,15 +95,18 @@ export const CatalogEntityPage = catalogPlugin.provide(
}),
);
export const EntityAboutCard = catalogPlugin.provide(
createComponentExtension({
name: 'EntityAboutCard',
component: {
lazy: () => import('./components/AboutCard').then(m => m.AboutCard),
},
}),
);
/** @public */
export const EntityAboutCard: (props: AboutCardProps) => JSX.Element =
catalogPlugin.provide(
createComponentExtension({
name: 'EntityAboutCard',
component: {
lazy: () => import('./components/AboutCard').then(m => m.AboutCard),
},
}),
);
/** @public */
export const EntityLinksCard = catalogPlugin.provide(
createComponentExtension({
name: 'EntityLinksCard',
@@ -99,17 +117,22 @@ export const EntityLinksCard = catalogPlugin.provide(
}),
);
export const EntityHasSystemsCard = catalogPlugin.provide(
createComponentExtension({
name: 'EntityHasSystemsCard',
component: {
lazy: () =>
import('./components/HasSystemsCard').then(m => m.HasSystemsCard),
},
}),
);
/** @public */
export const EntityHasSystemsCard: (props: HasSystemsCardProps) => JSX.Element =
catalogPlugin.provide(
createComponentExtension({
name: 'EntityHasSystemsCard',
component: {
lazy: () =>
import('./components/HasSystemsCard').then(m => m.HasSystemsCard),
},
}),
);
export const EntityHasComponentsCard = catalogPlugin.provide(
/** @public */
export const EntityHasComponentsCard: (
props: HasComponentsCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityHasComponentsCard',
component: {
@@ -119,7 +142,10 @@ export const EntityHasComponentsCard = catalogPlugin.provide(
}),
);
export const EntityHasSubcomponentsCard = catalogPlugin.provide(
/** @public */
export const EntityHasSubcomponentsCard: (
props: HasSubcomponentsCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityHasSubcomponentsCard',
component: {
@@ -131,7 +157,10 @@ export const EntityHasSubcomponentsCard = catalogPlugin.provide(
}),
);
export const EntityHasResourcesCard = catalogPlugin.provide(
/** @public */
export const EntityHasResourcesCard: (
props: HasResourcesCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityHasResourcesCard',
component: {
@@ -141,7 +170,10 @@ export const EntityHasResourcesCard = catalogPlugin.provide(
}),
);
export const EntityDependsOnComponentsCard = catalogPlugin.provide(
/** @public */
export const EntityDependsOnComponentsCard: (
props: DependsOnComponentsCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityDependsOnComponentsCard',
component: {
@@ -153,7 +185,10 @@ export const EntityDependsOnComponentsCard = catalogPlugin.provide(
}),
);
export const EntityDependencyOfComponentsCard = catalogPlugin.provide(
/** @public */
export const EntityDependencyOfComponentsCard: (
props: DependencyOfComponentsCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityDependencyOfComponentsCard',
component: {
@@ -165,7 +200,10 @@ export const EntityDependencyOfComponentsCard = catalogPlugin.provide(
}),
);
export const EntityDependsOnResourcesCard = catalogPlugin.provide(
/** @public */
export const EntityDependsOnResourcesCard: (
props: DependsOnResourcesCardProps,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'EntityDependsOnResourcesCard',
component: {
@@ -177,7 +215,10 @@ export const EntityDependsOnResourcesCard = catalogPlugin.provide(
}),
);
export const RelatedEntitiesCard = catalogPlugin.provide(
/** @public */
export const RelatedEntitiesCard: <T extends Entity>(
props: RelatedEntitiesCardProps<T>,
) => JSX.Element = catalogPlugin.provide(
createComponentExtension({
name: 'RelatedEntitiesCard',
component: {