+2
-8
@@ -40,14 +40,8 @@ const baseOverrides = createExtensionOverrides({
|
||||
namespace: 'app',
|
||||
name: 'root',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory() {
|
||||
return {
|
||||
element: <div>root</div>,
|
||||
};
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: () => [coreExtensionData.reactElement(<div>root</div>)],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -18,51 +18,38 @@ import React from 'react';
|
||||
import {
|
||||
ExtensionBoundary,
|
||||
coreExtensionData,
|
||||
createApiExtension,
|
||||
createComponentExtension,
|
||||
createExtension,
|
||||
createExtensionInput,
|
||||
createThemeExtension,
|
||||
createTranslationExtension,
|
||||
IconBundleBlueprint,
|
||||
ThemeBlueprint,
|
||||
ApiBlueprint,
|
||||
TranslationBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const App = createExtension({
|
||||
namespace: 'app',
|
||||
attachTo: { id: 'root', input: 'default' }, // ignored
|
||||
inputs: {
|
||||
apis: createExtensionInput({
|
||||
api: createApiExtension.factoryDataRef,
|
||||
apis: createExtensionInput([ApiBlueprint.dataRefs.factory]),
|
||||
themes: createExtensionInput([ThemeBlueprint.dataRefs.theme]),
|
||||
components: createExtensionInput([
|
||||
createComponentExtension.componentDataRef,
|
||||
]),
|
||||
translations: createExtensionInput([
|
||||
TranslationBlueprint.dataRefs.translation,
|
||||
]),
|
||||
icons: createExtensionInput([IconBundleBlueprint.dataRefs.icons]),
|
||||
root: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
}),
|
||||
themes: createExtensionInput({
|
||||
theme: createThemeExtension.themeDataRef,
|
||||
}),
|
||||
components: createExtensionInput({
|
||||
component: createComponentExtension.componentDataRef,
|
||||
}),
|
||||
translations: createExtensionInput({
|
||||
translation: createTranslationExtension.translationDataRef,
|
||||
}),
|
||||
icons: createExtensionInput({
|
||||
icon: IconBundleBlueprint.dataRefs.icons,
|
||||
}),
|
||||
root: createExtensionInput(
|
||||
{
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
{ singleton: true },
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: ({ node, inputs }) => [
|
||||
coreExtensionData.reactElement(
|
||||
<ExtensionBoundary node={node}>
|
||||
{inputs.root.get(coreExtensionData.reactElement)}
|
||||
</ExtensionBoundary>,
|
||||
),
|
||||
},
|
||||
output: {
|
||||
root: coreExtensionData.reactElement,
|
||||
},
|
||||
factory({ node, inputs }) {
|
||||
return {
|
||||
root: (
|
||||
<ExtensionBoundary node={node}>
|
||||
{inputs.root.output.element}
|
||||
</ExtensionBoundary>
|
||||
),
|
||||
};
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -27,30 +27,20 @@ export const AppLayout = createExtension({
|
||||
name: 'layout',
|
||||
attachTo: { id: 'app/root', input: 'children' },
|
||||
inputs: {
|
||||
nav: createExtensionInput(
|
||||
{
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
{ singleton: true },
|
||||
nav: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
}),
|
||||
content: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
}),
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: ({ inputs }) => [
|
||||
coreExtensionData.reactElement(
|
||||
<SidebarPage>
|
||||
{inputs.nav.get(coreExtensionData.reactElement)}
|
||||
{inputs.content.get(coreExtensionData.reactElement)}
|
||||
</SidebarPage>,
|
||||
),
|
||||
content: createExtensionInput(
|
||||
{
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
{ singleton: true },
|
||||
),
|
||||
},
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory({ inputs }) {
|
||||
return {
|
||||
element: (
|
||||
<SidebarPage>
|
||||
{inputs.nav.output.element}
|
||||
{inputs.content.output.element}
|
||||
</SidebarPage>
|
||||
),
|
||||
};
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -86,33 +86,27 @@ export const AppNav = createExtension({
|
||||
name: 'nav',
|
||||
attachTo: { id: 'app/layout', input: 'nav' },
|
||||
inputs: {
|
||||
items: createExtensionInput({
|
||||
target: createNavItemExtension.targetDataRef,
|
||||
items: createExtensionInput([createNavItemExtension.targetDataRef]),
|
||||
logos: createExtensionInput([createNavLogoExtension.logoElementsDataRef], {
|
||||
singleton: true,
|
||||
optional: true,
|
||||
}),
|
||||
logos: createExtensionInput(
|
||||
{
|
||||
elements: createNavLogoExtension.logoElementsDataRef,
|
||||
},
|
||||
{
|
||||
singleton: true,
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: ({ inputs }) => [
|
||||
coreExtensionData.reactElement(
|
||||
<Sidebar>
|
||||
<SidebarLogo
|
||||
{...inputs.logos?.get(createNavLogoExtension.logoElementsDataRef)}
|
||||
/>
|
||||
<SidebarDivider />
|
||||
{inputs.items.map((item, index) => (
|
||||
<SidebarNavItem
|
||||
{...item.get(createNavItemExtension.targetDataRef)}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</Sidebar>,
|
||||
),
|
||||
},
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory({ inputs }) {
|
||||
return {
|
||||
element: (
|
||||
<Sidebar>
|
||||
<SidebarLogo {...inputs.logos?.output.elements} />
|
||||
<SidebarDivider />
|
||||
{inputs.items.map((item, index) => (
|
||||
<SidebarNavItem {...item.output.target} key={index} />
|
||||
))}
|
||||
</Sidebar>
|
||||
),
|
||||
};
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -23,12 +23,12 @@ import React, {
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
AppRootWrapperBlueprint,
|
||||
RouterBlueprint,
|
||||
SignInPageBlueprint,
|
||||
coreExtensionData,
|
||||
createAppRootWrapperExtension,
|
||||
createExtension,
|
||||
createExtensionInput,
|
||||
createRouterExtension,
|
||||
createSignInPageExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import {
|
||||
IdentityApi,
|
||||
@@ -48,52 +48,54 @@ export const AppRoot = createExtension({
|
||||
name: 'root',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
inputs: {
|
||||
router: createExtensionInput(
|
||||
{ component: createRouterExtension.componentDataRef },
|
||||
{ singleton: true, optional: true },
|
||||
),
|
||||
signInPage: createExtensionInput(
|
||||
{ component: createSignInPageExtension.componentDataRef },
|
||||
{ singleton: true, optional: true },
|
||||
),
|
||||
children: createExtensionInput(
|
||||
{ element: coreExtensionData.reactElement },
|
||||
{ singleton: true },
|
||||
),
|
||||
elements: createExtensionInput({
|
||||
element: coreExtensionData.reactElement,
|
||||
router: createExtensionInput([RouterBlueprint.dataRefs.component], {
|
||||
singleton: true,
|
||||
optional: true,
|
||||
}),
|
||||
wrappers: createExtensionInput({
|
||||
component: createAppRootWrapperExtension.componentDataRef,
|
||||
signInPage: createExtensionInput([SignInPageBlueprint.dataRefs.component], {
|
||||
singleton: true,
|
||||
optional: true,
|
||||
}),
|
||||
children: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
}),
|
||||
elements: createExtensionInput([coreExtensionData.reactElement]),
|
||||
wrappers: createExtensionInput([
|
||||
AppRootWrapperBlueprint.dataRefs.component,
|
||||
]),
|
||||
},
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory({ inputs }) {
|
||||
let content: React.ReactNode = (
|
||||
<>
|
||||
{inputs.elements.map(el => (
|
||||
<Fragment key={el.node.spec.id}>{el.output.element}</Fragment>
|
||||
<Fragment key={el.node.spec.id}>
|
||||
{el.get(coreExtensionData.reactElement)}
|
||||
</Fragment>
|
||||
))}
|
||||
{inputs.children.output.element}
|
||||
{inputs.children.get(coreExtensionData.reactElement)}
|
||||
</>
|
||||
);
|
||||
|
||||
for (const wrapper of inputs.wrappers) {
|
||||
content = <wrapper.output.component>{content}</wrapper.output.component>;
|
||||
const Component = wrapper.get(AppRootWrapperBlueprint.dataRefs.component);
|
||||
content = <Component>{content}</Component>;
|
||||
}
|
||||
|
||||
return {
|
||||
element: (
|
||||
return [
|
||||
coreExtensionData.reactElement(
|
||||
<AppRouter
|
||||
SignInPageComponent={inputs.signInPage?.output.component}
|
||||
RouterComponent={inputs.router?.output.component}
|
||||
SignInPageComponent={inputs.signInPage?.get(
|
||||
SignInPageBlueprint.dataRefs.component,
|
||||
)}
|
||||
RouterComponent={inputs.router?.get(
|
||||
RouterBlueprint.dataRefs.component,
|
||||
)}
|
||||
>
|
||||
{content}
|
||||
</AppRouter>
|
||||
</AppRouter>,
|
||||
),
|
||||
};
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -29,15 +29,13 @@ export const AppRoutes = createExtension({
|
||||
name: 'routes',
|
||||
attachTo: { id: 'app/layout', input: 'content' },
|
||||
inputs: {
|
||||
routes: createExtensionInput({
|
||||
path: coreExtensionData.routePath,
|
||||
ref: coreExtensionData.routeRef.optional(),
|
||||
element: coreExtensionData.reactElement,
|
||||
}),
|
||||
},
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
routes: createExtensionInput([
|
||||
coreExtensionData.routePath,
|
||||
coreExtensionData.routeRef.optional(),
|
||||
coreExtensionData.reactElement,
|
||||
]),
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory({ inputs }) {
|
||||
const Routes = () => {
|
||||
const NotFoundErrorPage = useComponentRef(
|
||||
@@ -46,8 +44,8 @@ export const AppRoutes = createExtension({
|
||||
|
||||
const element = useRoutes([
|
||||
...inputs.routes.map(route => ({
|
||||
path: `${route.output.path}/*`,
|
||||
element: route.output.element,
|
||||
path: `${route.get(coreExtensionData.routePath)}/*`,
|
||||
element: route.get(coreExtensionData.reactElement),
|
||||
})),
|
||||
{
|
||||
path: '*',
|
||||
@@ -58,8 +56,6 @@ export const AppRoutes = createExtension({
|
||||
return element;
|
||||
};
|
||||
|
||||
return {
|
||||
element: <Routes />,
|
||||
};
|
||||
return [coreExtensionData.reactElement(<Routes />)];
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,31 +15,36 @@
|
||||
*/
|
||||
|
||||
import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components';
|
||||
import {
|
||||
createAppRootElementExtension,
|
||||
createSchemaFromZod,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { AppRootElementBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import React from 'react';
|
||||
|
||||
export const oauthRequestDialogAppRootElement = createAppRootElementExtension({
|
||||
export const oauthRequestDialogAppRootElement = AppRootElementBlueprint.make({
|
||||
namespace: 'app',
|
||||
name: 'oauth-request-dialog',
|
||||
element: <OAuthRequestDialog />,
|
||||
params: {
|
||||
element: <OAuthRequestDialog />,
|
||||
},
|
||||
});
|
||||
|
||||
export const alertDisplayAppRootElement = createAppRootElementExtension({
|
||||
namespace: 'app',
|
||||
name: 'alert-display',
|
||||
configSchema: createSchemaFromZod(z =>
|
||||
z.object({
|
||||
transientTimeoutMs: z.number().default(5000),
|
||||
anchorOrigin: z
|
||||
.object({
|
||||
vertical: z.enum(['top', 'bottom']).default('top'),
|
||||
horizontal: z.enum(['left', 'center', 'right']).default('center'),
|
||||
})
|
||||
.default({}),
|
||||
}),
|
||||
),
|
||||
element: ({ config }) => <AlertDisplay {...config} />,
|
||||
});
|
||||
export const alertDisplayAppRootElement =
|
||||
AppRootElementBlueprint.makeWithOverrides({
|
||||
namespace: 'app',
|
||||
name: 'alert-display',
|
||||
config: {
|
||||
schema: {
|
||||
transientTimeoutMs: z => z.number().default(5000),
|
||||
anchorOrigin: z =>
|
||||
z
|
||||
.object({
|
||||
vertical: z.enum(['top', 'bottom']).default('top'),
|
||||
horizontal: z.enum(['left', 'center', 'right']).default('center'),
|
||||
})
|
||||
.default({}),
|
||||
},
|
||||
},
|
||||
factory: (originalFactory, { config }) => {
|
||||
return originalFactory({
|
||||
element: () => <AlertDisplay {...config} />,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -21,24 +21,34 @@ import {
|
||||
} from '@backstage/theme';
|
||||
import DarkIcon from '@material-ui/icons/Brightness2';
|
||||
import LightIcon from '@material-ui/icons/WbSunny';
|
||||
import { createThemeExtension } from '@backstage/frontend-plugin-api';
|
||||
import { ThemeBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const LightTheme = createThemeExtension({
|
||||
id: 'light',
|
||||
title: 'Light Theme',
|
||||
variant: 'light',
|
||||
icon: <LightIcon />,
|
||||
Provider: ({ children }) => (
|
||||
<UnifiedThemeProvider theme={builtinThemes.light} children={children} />
|
||||
),
|
||||
export const LightTheme = ThemeBlueprint.make({
|
||||
name: 'light',
|
||||
params: {
|
||||
theme: {
|
||||
id: 'light',
|
||||
title: 'Light Theme',
|
||||
variant: 'light',
|
||||
icon: <LightIcon />,
|
||||
Provider: ({ children }) => (
|
||||
<UnifiedThemeProvider theme={builtinThemes.light} children={children} />
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const DarkTheme = createThemeExtension({
|
||||
id: 'dark',
|
||||
title: 'Dark Theme',
|
||||
variant: 'dark',
|
||||
icon: <DarkIcon />,
|
||||
Provider: ({ children }) => (
|
||||
<UnifiedThemeProvider theme={builtinThemes.dark} children={children} />
|
||||
),
|
||||
export const DarkTheme = ThemeBlueprint.make({
|
||||
name: 'dark',
|
||||
params: {
|
||||
theme: {
|
||||
id: 'dark',
|
||||
title: 'Dark Theme',
|
||||
variant: 'dark',
|
||||
icon: <DarkIcon />,
|
||||
Provider: ({ children }) => (
|
||||
<UnifiedThemeProvider theme={builtinThemes.dark} children={children} />
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -50,22 +50,23 @@ function createTestExtension(options: {
|
||||
attachTo: options.parent
|
||||
? { id: `test/${options.parent}`, input: 'children' }
|
||||
: { id: 'app/routes', input: 'routes' },
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
path: coreExtensionData.routePath.optional(),
|
||||
routeRef: coreExtensionData.routeRef.optional(),
|
||||
},
|
||||
output: [
|
||||
coreExtensionData.reactElement,
|
||||
coreExtensionData.routePath.optional(),
|
||||
coreExtensionData.routeRef.optional(),
|
||||
],
|
||||
inputs: {
|
||||
children: createExtensionInput({
|
||||
element: coreExtensionData.reactElement,
|
||||
}),
|
||||
children: createExtensionInput([coreExtensionData.reactElement]),
|
||||
},
|
||||
factory() {
|
||||
return {
|
||||
path: options.path,
|
||||
routeRef: options.routeRef,
|
||||
element: React.createElement('div'),
|
||||
};
|
||||
*factory() {
|
||||
if (options.path) {
|
||||
yield coreExtensionData.routePath(options.path);
|
||||
}
|
||||
if (options.routeRef) {
|
||||
yield coreExtensionData.routeRef(options.routeRef);
|
||||
}
|
||||
|
||||
yield coreExtensionData.reactElement(React.createElement('div'));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import { createAppTree } from './createAppTree';
|
||||
const extBase = {
|
||||
id: 'test',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
output: {},
|
||||
factory: () => ({}),
|
||||
output: [],
|
||||
factory: () => [],
|
||||
};
|
||||
|
||||
describe('createAppTree', () => {
|
||||
@@ -60,8 +60,8 @@ describe('createAppTree', () => {
|
||||
name: 'app',
|
||||
attachTo: { id: 'app/routes', input: 'route' },
|
||||
inputs: {},
|
||||
output: {},
|
||||
factory: () => ({}),
|
||||
output: [],
|
||||
factory: () => [],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -23,8 +23,8 @@ const extension = resolveExtensionDefinition(
|
||||
createExtension({
|
||||
name: 'test',
|
||||
attachTo: { id: 'nonexistent', input: 'nonexistent' },
|
||||
output: {},
|
||||
factory: () => ({}),
|
||||
output: [],
|
||||
factory: () => [],
|
||||
}),
|
||||
) as Extension<unknown, unknown>;
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionOverrides,
|
||||
createPageExtension,
|
||||
PageBlueprint,
|
||||
createFrontendPlugin,
|
||||
createThemeExtension,
|
||||
ThemeBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { CreateAppFeatureLoader, createApp } from './createApp';
|
||||
@@ -47,11 +47,16 @@ describe('createApp', () => {
|
||||
createFrontendPlugin({
|
||||
id: 'test',
|
||||
extensions: [
|
||||
createThemeExtension({
|
||||
id: 'derp',
|
||||
title: 'Derp',
|
||||
variant: 'dark',
|
||||
Provider: () => <div>Derp</div>,
|
||||
ThemeBlueprint.make({
|
||||
name: 'derp',
|
||||
params: {
|
||||
theme: {
|
||||
id: 'derp',
|
||||
title: 'Derp',
|
||||
variant: 'dark',
|
||||
Provider: () => <div>Derp</div>,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -71,18 +76,22 @@ describe('createApp', () => {
|
||||
createFrontendPlugin({
|
||||
id: duplicatedFeatureId,
|
||||
extensions: [
|
||||
createPageExtension({
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>First Page</div>,
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>First Page</div>,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
createFrontendPlugin({
|
||||
id: duplicatedFeatureId,
|
||||
extensions: [
|
||||
createPageExtension({
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>Last Page</div>,
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>Last Page</div>,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -110,9 +119,11 @@ describe('createApp', () => {
|
||||
createFrontendPlugin({
|
||||
id: 'test',
|
||||
extensions: [
|
||||
createPageExtension({
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>{config.getString('key')}</div>,
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/',
|
||||
loader: async () => <div>{config.getString('key')}</div>,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -170,7 +181,7 @@ describe('createApp', () => {
|
||||
createExtension({
|
||||
name: 'first',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
output: { element: coreExtensionData.reactElement },
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory() {
|
||||
const Component = () => {
|
||||
const flagsApi = useApi(featureFlagsApiRef);
|
||||
@@ -184,7 +195,7 @@ describe('createApp', () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return { element: <Component /> };
|
||||
return [coreExtensionData.reactElement(<Component />)];
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -197,8 +208,8 @@ describe('createApp', () => {
|
||||
name: 'root',
|
||||
attachTo: { id: 'app', input: 'root' },
|
||||
disabled: true,
|
||||
output: {},
|
||||
factory: () => ({}),
|
||||
output: [],
|
||||
factory: () => [],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -221,14 +232,16 @@ describe('createApp', () => {
|
||||
createFrontendPlugin({
|
||||
id: 'my-plugin',
|
||||
extensions: [
|
||||
createPageExtension({
|
||||
defaultPath: '/',
|
||||
loader: async () => {
|
||||
const Component = () => {
|
||||
appTreeApi = useApi(appTreeApiRef);
|
||||
return <div>My Plugin Page</div>;
|
||||
};
|
||||
return <Component />;
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
defaultPath: '/',
|
||||
loader: async () => {
|
||||
const Component = () => {
|
||||
appTreeApi = useApi(appTreeApiRef);
|
||||
return <div>My Plugin Page</div>;
|
||||
};
|
||||
return <Component />;
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -250,7 +263,7 @@ describe('createApp', () => {
|
||||
content [
|
||||
<app/routes out=[core.reactElement]>
|
||||
routes [
|
||||
<page:my-plugin out=[core.routing.path, core.routing.ref, core.reactElement] />
|
||||
<page:my-plugin out=[core.routing.path, core.reactElement] />
|
||||
]
|
||||
</app/routes>
|
||||
]
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
import React, { JSX, ReactNode } from 'react';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import {
|
||||
ApiBlueprint,
|
||||
AppTree,
|
||||
appTreeApiRef,
|
||||
componentsApiRef,
|
||||
coreExtensionData,
|
||||
createApiExtension,
|
||||
createThemeExtension,
|
||||
createTranslationExtension,
|
||||
FrontendFeature,
|
||||
IconBundleBlueprint,
|
||||
iconsApiRef,
|
||||
RouteResolutionApi,
|
||||
routeResolutionApiRef,
|
||||
ThemeBlueprint,
|
||||
TranslationBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { App } from '../extensions/App';
|
||||
import { AppRoutes } from '../extensions/AppRoutes';
|
||||
@@ -110,7 +110,9 @@ import { stringifyError } from '@backstage/errors';
|
||||
import { icons as defaultIcons } from '../../../app-defaults/src/defaults';
|
||||
import { getBasePath } from '../routing/getBasePath';
|
||||
|
||||
const DefaultApis = defaultApis.map(factory => createApiExtension({ factory }));
|
||||
const DefaultApis = defaultApis.map(factory =>
|
||||
ApiBlueprint.make({ namespace: factory.api.id, params: { factory } }),
|
||||
);
|
||||
|
||||
export const builtinExtensions = [
|
||||
App,
|
||||
@@ -357,23 +359,21 @@ function createApiHolder(
|
||||
const pluginApis =
|
||||
tree.root.edges.attachments
|
||||
.get('apis')
|
||||
?.map(e => e.instance?.getData(createApiExtension.factoryDataRef))
|
||||
?.map(e => e.instance?.getData(ApiBlueprint.dataRefs.factory))
|
||||
.filter((x): x is AnyApiFactory => !!x) ?? [];
|
||||
|
||||
const themeExtensions =
|
||||
tree.root.edges.attachments
|
||||
.get('themes')
|
||||
?.map(e => e.instance?.getData(createThemeExtension.themeDataRef))
|
||||
?.map(e => e.instance?.getData(ThemeBlueprint.dataRefs.theme))
|
||||
.filter((x): x is AppTheme => !!x) ?? [];
|
||||
|
||||
const translationResources =
|
||||
tree.root.edges.attachments
|
||||
.get('translations')
|
||||
?.map(e =>
|
||||
e.instance?.getData(createTranslationExtension.translationDataRef),
|
||||
)
|
||||
?.map(e => e.instance?.getData(TranslationBlueprint.dataRefs.translation))
|
||||
.filter(
|
||||
(x): x is typeof createTranslationExtension.translationDataRef.T => !!x,
|
||||
(x): x is typeof TranslationBlueprint.dataRefs.translation.T => !!x,
|
||||
) ?? [];
|
||||
|
||||
const extensionIcons = tree.root.edges.attachments
|
||||
|
||||
Reference in New Issue
Block a user