catalog,catalog-react,techdocs: extract experimental entity page implementation from app-next
Co-authored-by: Camila Belo <camilaibs@gmail.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
committed by
Camila Belo
parent
c82fc7e672
commit
0bf6ebda88
@@ -3,8 +3,73 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api';
|
||||
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Extension } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionInputValues } from '@backstage/frontend-plugin-api';
|
||||
import { PortableSchema } from '@backstage/frontend-plugin-api';
|
||||
import { ResourcePermission } from '@backstage/plugin-permission-common';
|
||||
import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export function createEntityCardExtension<
|
||||
TConfig,
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
>(options: {
|
||||
id: string;
|
||||
attachTo?: {
|
||||
id: string;
|
||||
input: string;
|
||||
};
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
configSchema?: PortableSchema<TConfig>;
|
||||
loader: (options: {
|
||||
config: TConfig;
|
||||
inputs: Expand<ExtensionInputValues<TInputs>>;
|
||||
}) => Promise<JSX.Element>;
|
||||
}): Extension<TConfig>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export function createEntityContentExtension<
|
||||
TConfig extends {
|
||||
path: string;
|
||||
title: string;
|
||||
},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
>(
|
||||
options: (
|
||||
| {
|
||||
defaultPath: string;
|
||||
defaultTitle: string;
|
||||
}
|
||||
| {
|
||||
configSchema: PortableSchema<TConfig>;
|
||||
}
|
||||
) & {
|
||||
id: string;
|
||||
attachTo?: {
|
||||
id: string;
|
||||
input: string;
|
||||
};
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
routeRef?: RouteRef;
|
||||
loader: (options: {
|
||||
config: TConfig;
|
||||
inputs: Expand<ExtensionInputValues<TInputs>>;
|
||||
}) => Promise<JSX.Element>;
|
||||
},
|
||||
): Extension<TConfig>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const entityContentTitleExtensionDataRef: ConfigurableExtensionDataRef<
|
||||
string,
|
||||
{}
|
||||
>;
|
||||
|
||||
// @alpha
|
||||
export function isOwnerOf(owner: Entity, entity: Entity): boolean;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./alpha": "./src/alpha.ts",
|
||||
"./alpha": "./src/alpha.tsx",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"alpha": [
|
||||
"src/alpha.ts"
|
||||
"src/alpha.tsx"
|
||||
],
|
||||
"package.json": [
|
||||
"package.json"
|
||||
@@ -51,6 +51,7 @@
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/integration": "workspace:^",
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import {
|
||||
AnyExtensionInputMap,
|
||||
Extension,
|
||||
ExtensionBoundary,
|
||||
ExtensionInputValues,
|
||||
PortableSchema,
|
||||
RouteRef,
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionDataRef,
|
||||
createSchemaFromZod,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { Expand } from '../../../packages/frontend-plugin-api/src/types';
|
||||
|
||||
export { isOwnerOf } from './utils';
|
||||
export { useEntityPermission } from './hooks/useEntityPermission';
|
||||
|
||||
/** @alpha */
|
||||
export const entityContentTitleExtensionDataRef =
|
||||
createExtensionDataRef<string>('plugin.catalog.entity.content.title');
|
||||
|
||||
/** @alpha */
|
||||
export function createEntityCardExtension<
|
||||
TConfig,
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
>(options: {
|
||||
id: string;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
configSchema?: PortableSchema<TConfig>;
|
||||
loader: (options: {
|
||||
config: TConfig;
|
||||
inputs: Expand<ExtensionInputValues<TInputs>>;
|
||||
}) => Promise<JSX.Element>;
|
||||
}): Extension<TConfig> {
|
||||
const id = `entity.cards.${options.id}`;
|
||||
|
||||
return createExtension({
|
||||
id,
|
||||
attachTo: options.attachTo ?? {
|
||||
id: 'entity.content.overview',
|
||||
input: 'cards',
|
||||
},
|
||||
disabled: options.disabled ?? true,
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
inputs: options.inputs,
|
||||
configSchema: options.configSchema,
|
||||
factory({ bind, config, inputs, source }) {
|
||||
const ExtensionComponent = React.lazy(() =>
|
||||
options
|
||||
.loader({ config, inputs })
|
||||
.then(element => ({ default: () => element })),
|
||||
);
|
||||
|
||||
bind({
|
||||
element: (
|
||||
<ExtensionBoundary id={id} source={source}>
|
||||
<ExtensionComponent />
|
||||
</ExtensionBoundary>
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** @alpha */
|
||||
export function createEntityContentExtension<
|
||||
TConfig extends { path: string; title: string },
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
>(
|
||||
options: (
|
||||
| {
|
||||
defaultPath: string;
|
||||
defaultTitle: string;
|
||||
}
|
||||
| {
|
||||
configSchema: PortableSchema<TConfig>;
|
||||
}
|
||||
) & {
|
||||
id: string;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
routeRef?: RouteRef;
|
||||
loader: (options: {
|
||||
config: TConfig;
|
||||
inputs: Expand<ExtensionInputValues<TInputs>>;
|
||||
}) => Promise<JSX.Element>;
|
||||
},
|
||||
): Extension<TConfig> {
|
||||
const id = `entity.content.${options.id}`;
|
||||
|
||||
const configSchema =
|
||||
'configSchema' in options
|
||||
? options.configSchema
|
||||
: (createSchemaFromZod(z =>
|
||||
z.object({
|
||||
path: z.string().default(options.defaultPath),
|
||||
title: z.string().default(options.defaultTitle),
|
||||
}),
|
||||
) as PortableSchema<TConfig>);
|
||||
|
||||
return createExtension({
|
||||
id,
|
||||
attachTo: options.attachTo ?? {
|
||||
id: 'plugin.catalog.page.entity',
|
||||
input: 'contents',
|
||||
},
|
||||
disabled: options.disabled ?? true,
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
path: coreExtensionData.routePath,
|
||||
routeRef: coreExtensionData.routeRef.optional(),
|
||||
title: entityContentTitleExtensionDataRef,
|
||||
},
|
||||
inputs: options.inputs,
|
||||
configSchema,
|
||||
factory({ bind, config, inputs, source }) {
|
||||
const LazyComponent = React.lazy(() =>
|
||||
options
|
||||
.loader({ config, inputs })
|
||||
.then(element => ({ default: () => element })),
|
||||
);
|
||||
|
||||
bind({
|
||||
path: config.path,
|
||||
element: (
|
||||
<ExtensionBoundary id={id} source={source}>
|
||||
<LazyComponent />
|
||||
</ExtensionBoundary>
|
||||
),
|
||||
routeRef: options.routeRef,
|
||||
title: config.title,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -12,14 +12,6 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { PortableSchema } from '@backstage/frontend-plugin-api';
|
||||
import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const CatalogApi: Extension<{}>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const CatalogSearchResultListItemExtension: Extension<{
|
||||
noTrack?: boolean | undefined;
|
||||
}>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export function createCatalogFilterExtension<
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -62,8 +54,5 @@ const _default: BackstagePlugin<
|
||||
>;
|
||||
export default _default;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const StarredEntitiesApi: Extension<{}>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./alpha": "./src/alpha/index.ts",
|
||||
"./alpha": "./src/alpha.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"alpha": [
|
||||
"src/alpha/index.ts"
|
||||
"src/alpha.ts"
|
||||
],
|
||||
"package.json": [
|
||||
"package.json"
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { isOwnerOf } from './utils';
|
||||
export { useEntityPermission } from './hooks/useEntityPermission';
|
||||
export * from './alpha/index';
|
||||
export { default } from './alpha/index';
|
||||
@@ -38,6 +38,11 @@ import {
|
||||
entityRouteRef,
|
||||
starredEntitiesApiRef,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
createEntityContentExtension,
|
||||
createEntityCardExtension,
|
||||
entityContentTitleExtensionDataRef,
|
||||
} from '@backstage/plugin-catalog-react/alpha';
|
||||
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha';
|
||||
import { DefaultStarredEntitiesApi } from '../apis';
|
||||
import {
|
||||
@@ -48,6 +53,7 @@ import {
|
||||
} from '../routes';
|
||||
import { builtInFilterExtensions } from './builtInFilterExtensions';
|
||||
import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
/** @alpha */
|
||||
export const CatalogApi = createApiExtension({
|
||||
@@ -102,11 +108,30 @@ const CatalogEntityPage = createPageExtension({
|
||||
id: 'plugin.catalog.page.entity',
|
||||
defaultPath: '/catalog/:namespace/:kind/:name',
|
||||
routeRef: convertLegacyRouteRef(entityRouteRef),
|
||||
loader: async () => {
|
||||
inputs: {
|
||||
contents: createExtensionInput({
|
||||
element: coreExtensionData.reactElement,
|
||||
path: coreExtensionData.routePath,
|
||||
routeRef: coreExtensionData.routeRef.optional(),
|
||||
title: entityContentTitleExtensionDataRef,
|
||||
}),
|
||||
},
|
||||
loader: async ({ inputs }) => {
|
||||
const { EntityLayout } = await import('../components/EntityLayout');
|
||||
const Component = () => {
|
||||
return (
|
||||
<AsyncEntityProvider {...useEntityFromUrl()}>
|
||||
<div>🚧 Work In Progress</div>
|
||||
<EntityLayout>
|
||||
{inputs.contents.map(content => (
|
||||
<EntityLayout.Route
|
||||
key={content.path}
|
||||
path={content.path}
|
||||
title={content.title}
|
||||
>
|
||||
{content.element}
|
||||
</EntityLayout.Route>
|
||||
))}
|
||||
</EntityLayout>
|
||||
</AsyncEntityProvider>
|
||||
);
|
||||
};
|
||||
@@ -114,6 +139,35 @@ const CatalogEntityPage = createPageExtension({
|
||||
},
|
||||
});
|
||||
|
||||
const EntityAboutCard = createEntityCardExtension({
|
||||
id: 'about',
|
||||
loader: async () =>
|
||||
import('../components/AboutCard').then(m => (
|
||||
<m.AboutCard variant="gridItem" />
|
||||
)),
|
||||
});
|
||||
|
||||
const OverviewEntityContent = createEntityContentExtension({
|
||||
id: 'overview',
|
||||
defaultPath: '/',
|
||||
defaultTitle: 'Overview',
|
||||
disabled: false,
|
||||
inputs: {
|
||||
cards: createExtensionInput({
|
||||
element: coreExtensionData.reactElement,
|
||||
}),
|
||||
},
|
||||
loader: async ({ inputs }) => (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
{inputs.cards.map(card => (
|
||||
<Grid item md={6} xs={12}>
|
||||
{card.element}
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
),
|
||||
});
|
||||
|
||||
const CatalogNavItem = createNavItemExtension({
|
||||
id: 'catalog.nav.index',
|
||||
routeRef: convertLegacyRouteRef(rootRouteRef),
|
||||
@@ -140,6 +194,8 @@ export default createPlugin({
|
||||
CatalogIndexPage,
|
||||
CatalogEntityPage,
|
||||
CatalogNavItem,
|
||||
OverviewEntityContent,
|
||||
EntityAboutCard,
|
||||
...builtInFilterExtensions,
|
||||
],
|
||||
});
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
rootDocsRouteRef,
|
||||
rootRouteRef,
|
||||
} from './routes';
|
||||
import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
|
||||
/** @alpha */
|
||||
const techDocsStorage = createApiExtension({
|
||||
@@ -141,6 +142,18 @@ const TechDocsReaderPage = createPageExtension({
|
||||
)),
|
||||
});
|
||||
|
||||
/**
|
||||
* Component responsible for rendering techdocs on entity pages
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
const TechDocsEntityContent = createEntityContentExtension({
|
||||
id: 'techdocs',
|
||||
defaultPath: 'docs',
|
||||
defaultTitle: 'TechDocs',
|
||||
loader: () => import('./Router').then(m => <m.EmbeddedDocsRouter />),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
const TechDocsNavItem = createNavItemExtension({
|
||||
id: 'plugin.techdocs.nav.index',
|
||||
@@ -158,6 +171,7 @@ export default createPlugin({
|
||||
TechDocsNavItem,
|
||||
TechDocsIndexPage,
|
||||
TechDocsReaderPage,
|
||||
TechDocsEntityContent,
|
||||
TechDocsSearchResultListItemExtension,
|
||||
],
|
||||
routes: {
|
||||
|
||||
Reference in New Issue
Block a user