frontend-plugin-api: complete deprecation of app blueprints
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -13,7 +13,6 @@ import { ExpandRecursive } from '@backstage/types';
|
||||
import { ExtensionBlueprint as ExtensionBlueprint_2 } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionBlueprintParams as ExtensionBlueprintParams_2 } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionDataRef as ExtensionDataRef_2 } from '@backstage/frontend-plugin-api';
|
||||
import { IconComponent as IconComponent_2 } from '@backstage/frontend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
||||
@@ -21,7 +20,6 @@ import { JSX as JSX_3 } from 'react';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api';
|
||||
import { SwappableComponentRef as SwappableComponentRef_2 } from '@backstage/frontend-plugin-api';
|
||||
import type { z } from 'zod';
|
||||
|
||||
@@ -271,30 +269,6 @@ export const AppRootElementBlueprint: ExtensionBlueprint_2<{
|
||||
dataRefs: never;
|
||||
}>;
|
||||
|
||||
// @public @deprecated
|
||||
export const AppRootWrapperBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'app-root-wrapper';
|
||||
params: {
|
||||
Component?: [error: 'Use the `component` parameter instead'];
|
||||
component: (props: { children: ReactNode }) => JSX.Element | null;
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
(props: { children: ReactNode }) => JSX.Element | null,
|
||||
'app.root.wrapper',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef_2<
|
||||
(props: { children: ReactNode }) => JSX.Element | null,
|
||||
'app.root.wrapper',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type AppTheme = {
|
||||
id: string;
|
||||
@@ -1461,33 +1435,6 @@ export const googleAuthApiRef: ApiRef<
|
||||
SessionApi
|
||||
>;
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export const IconBundleBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'icon-bundle';
|
||||
params: {
|
||||
icons: { [key in string]: IconComponent };
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
{
|
||||
[x: string]: IconComponent;
|
||||
},
|
||||
'core.icons',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
icons: ConfigurableExtensionDataRef_2<
|
||||
{
|
||||
[x: string]: IconComponent;
|
||||
},
|
||||
'core.icons',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type IconComponent = ComponentType<{
|
||||
fontSize?: 'medium' | 'large' | 'small' | 'inherit';
|
||||
@@ -1526,45 +1473,6 @@ export const microsoftAuthApiRef: ApiRef<
|
||||
SessionApi
|
||||
>;
|
||||
|
||||
// @public @deprecated
|
||||
export const NavContentBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'nav-content';
|
||||
params: {
|
||||
component: NavContentComponent;
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
NavContentComponent,
|
||||
'core.nav-content.component',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef_2<
|
||||
NavContentComponent,
|
||||
'core.nav-content.component',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type NavContentComponent = (
|
||||
props: NavContentComponentProps,
|
||||
) => JSX.Element | null;
|
||||
|
||||
// @public
|
||||
export interface NavContentComponentProps {
|
||||
items: Array<{
|
||||
icon: IconComponent_2;
|
||||
title: string;
|
||||
routeRef: RouteRef_2<undefined>;
|
||||
to: string;
|
||||
text: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const NavItemBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'nav-item';
|
||||
@@ -1927,30 +1835,6 @@ export type RouteFunc<TParams extends AnyRouteRefParams> = (
|
||||
: readonly [params: TParams]
|
||||
) => string;
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export const RouterBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'app-router-component';
|
||||
params: {
|
||||
Component?: [error: 'Use the `component` parameter instead'];
|
||||
component: (props: { children: ReactNode }) => JSX.Element | null;
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
(props: { children: ReactNode }) => JSX.Element | null,
|
||||
'app.router.wrapper',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef_2<
|
||||
(props: { children: ReactNode }) => JSX.Element | null,
|
||||
'app.router.wrapper',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export interface RouteRef<
|
||||
TParams extends AnyRouteRefParams = AnyRouteRefParams,
|
||||
@@ -2002,35 +1886,6 @@ export namespace SessionState {
|
||||
export type SignedOut = typeof SessionState.SignedOut;
|
||||
}
|
||||
|
||||
// @public @deprecated
|
||||
export const SignInPageBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'sign-in-page';
|
||||
params: {
|
||||
loader: () => Promise<ComponentType<SignInPageProps>>;
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
ComponentType<SignInPageProps>,
|
||||
'core.sign-in-page.component',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef_2<
|
||||
ComponentType<SignInPageProps>,
|
||||
'core.sign-in-page.component',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export type SignInPageProps = {
|
||||
onSignInSuccess(identityApi: IdentityApi): void;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface StorageApi {
|
||||
forBucket(name: string): StorageApi;
|
||||
@@ -2070,65 +1925,6 @@ export interface SubRouteRef<
|
||||
readonly T: TParams;
|
||||
}
|
||||
|
||||
// @public @deprecated
|
||||
export const SwappableComponentBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'component';
|
||||
params: <Ref extends SwappableComponentRef<any>>(params: {
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? {
|
||||
ref: Ref;
|
||||
} & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
: never;
|
||||
}) => ExtensionBlueprintParams_2<{
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? {
|
||||
ref: Ref;
|
||||
} & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
: never;
|
||||
}>;
|
||||
output: ExtensionDataRef_2<
|
||||
{
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
},
|
||||
'core.swappableComponent',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
component: ConfigurableExtensionDataRef_2<
|
||||
{
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
},
|
||||
'core.swappableComponent',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type SwappableComponentRef<
|
||||
TInnerComponentProps extends {} = {},
|
||||
@@ -2154,21 +1950,6 @@ export interface SwappableComponentsApi {
|
||||
// @public
|
||||
export const swappableComponentsApiRef: ApiRef_2<SwappableComponentsApi>;
|
||||
|
||||
// @public @deprecated
|
||||
export const ThemeBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'theme';
|
||||
params: {
|
||||
theme: AppTheme;
|
||||
};
|
||||
output: ExtensionDataRef_2<AppTheme, 'core.theme.theme', {}>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
theme: ConfigurableExtensionDataRef_2<AppTheme, 'core.theme.theme', {}>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TranslationApi = {
|
||||
getTranslation<
|
||||
@@ -2190,43 +1971,6 @@ export type TranslationApi = {
|
||||
// @public (undocumented)
|
||||
export const translationApiRef: ApiRef<TranslationApi>;
|
||||
|
||||
// @public @deprecated
|
||||
export const TranslationBlueprint: ExtensionBlueprint_2<{
|
||||
kind: 'translation';
|
||||
params: {
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
};
|
||||
output: ExtensionDataRef_2<
|
||||
| TranslationResource<string>
|
||||
| TranslationMessages<
|
||||
string,
|
||||
{
|
||||
[x: string]: string;
|
||||
},
|
||||
boolean
|
||||
>,
|
||||
'core.translation.translation',
|
||||
{}
|
||||
>;
|
||||
inputs: {};
|
||||
config: {};
|
||||
configInput: {};
|
||||
dataRefs: {
|
||||
translation: ConfigurableExtensionDataRef_2<
|
||||
| TranslationResource<string>
|
||||
| TranslationMessages<
|
||||
string,
|
||||
{
|
||||
[x: string]: string;
|
||||
},
|
||||
boolean
|
||||
>,
|
||||
'core.translation.translation',
|
||||
{}
|
||||
>;
|
||||
};
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type TranslationFunction<
|
||||
TMessages extends {
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { Fragment } from 'react';
|
||||
import { AppRootWrapperBlueprint } from './AppRootWrapperBlueprint';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionInput,
|
||||
} from '../wiring';
|
||||
import { renderTestApp } from '@backstage/frontend-test-utils';
|
||||
|
||||
describe('AppRootWrapperBlueprint', () => {
|
||||
it('should return an extension with sensible defaults', () => {
|
||||
const extension = AppRootWrapperBlueprint.make({
|
||||
params: {
|
||||
component: () => <div>Hello</div>,
|
||||
},
|
||||
});
|
||||
|
||||
expect(extension).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "app/root",
|
||||
"input": "wrappers",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "app-root-wrapper",
|
||||
"name": undefined,
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render the simple component wrapper', async () => {
|
||||
const extension = AppRootWrapperBlueprint.make({
|
||||
name: 'test',
|
||||
params: {
|
||||
component: () => <div>Hello</div>,
|
||||
},
|
||||
});
|
||||
|
||||
renderTestApp({ extensions: [extension] });
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Hello')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('should render the complex component wrapper', async () => {
|
||||
const extension = AppRootWrapperBlueprint.makeWithOverrides({
|
||||
config: {
|
||||
schema: {
|
||||
name: z => z.string(),
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
children: createExtensionInput([coreExtensionData.reactElement]),
|
||||
},
|
||||
*factory(originalFactory, { inputs, config }) {
|
||||
yield* originalFactory({
|
||||
component: ({ children }) => (
|
||||
<div data-testid={`${config.name}-${inputs.children.length}`}>
|
||||
{children}
|
||||
{inputs.children.flatMap((c, index) => (
|
||||
<Fragment key={index}>
|
||||
{c.get(coreExtensionData.reactElement)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
renderTestApp({
|
||||
extensions: [
|
||||
extension,
|
||||
createExtension({
|
||||
name: 'test-child',
|
||||
attachTo: { id: 'app-root-wrapper:test', input: 'children' },
|
||||
output: [coreExtensionData.reactElement],
|
||||
factory: () => [coreExtensionData.reactElement(<div>Its Me</div>)],
|
||||
}),
|
||||
],
|
||||
config: {
|
||||
app: {
|
||||
extensions: [
|
||||
{
|
||||
'app-root-wrapper:test': { config: { name: 'Robin' } },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('Robin-1')).toBeInTheDocument();
|
||||
expect(screen.getByText('Its Me')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { ReactNode } from 'react';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
|
||||
const componentDataRef = createExtensionDataRef<
|
||||
(props: { children: ReactNode }) => JSX.Element | null
|
||||
>().with({ id: 'app.root.wrapper' });
|
||||
|
||||
/**
|
||||
* Creates a extensions that render a React wrapper at the app root, enclosing
|
||||
* the app layout. This is useful for example for adding global React contexts
|
||||
* and similar.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#AppRootWrapperBlueprint} instead.
|
||||
* If you were using this blueprint to provide a context for your plugin,
|
||||
* use `PluginWrapperBlueprint` from `@backstage/frontend-plugin-api/alpha` instead.
|
||||
*/
|
||||
export const AppRootWrapperBlueprint = createExtensionBlueprint({
|
||||
kind: 'app-root-wrapper',
|
||||
attachTo: { id: 'app/root', input: 'wrappers' },
|
||||
output: [componentDataRef],
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
*factory(params: {
|
||||
/** @deprecated use the `component` parameter instead */
|
||||
Component?: [error: 'Use the `component` parameter instead'];
|
||||
component: (props: { children: ReactNode }) => JSX.Element | null;
|
||||
}) {
|
||||
yield componentDataRef(params.component);
|
||||
},
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { IconComponent } from '../icons';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
|
||||
const iconsDataRef = createExtensionDataRef<{
|
||||
[key in string]: IconComponent;
|
||||
}>().with({ id: 'core.icons' });
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#IconBundleBlueprint} instead.
|
||||
*/
|
||||
export const IconBundleBlueprint = createExtensionBlueprint({
|
||||
kind: 'icon-bundle',
|
||||
attachTo: { id: 'api:app/icons', input: 'icons' },
|
||||
output: [iconsDataRef],
|
||||
factory: (params: { icons: { [key in string]: IconComponent } }) => [
|
||||
iconsDataRef(params.icons),
|
||||
],
|
||||
dataRefs: {
|
||||
icons: iconsDataRef,
|
||||
},
|
||||
});
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createRouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { NavContentBlueprint } from './NavContentBlueprint';
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
|
||||
const routeRef = createRouteRef();
|
||||
|
||||
describe('NavContentBlueprint', () => {
|
||||
it('should create an extension with sensible defaults', () => {
|
||||
const extension = NavContentBlueprint.make({
|
||||
params: {
|
||||
component: () => <div>Nav content</div>,
|
||||
},
|
||||
});
|
||||
|
||||
expect(extension).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "app/nav",
|
||||
"input": "content",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "nav-content",
|
||||
"name": undefined,
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should return a valid component', () => {
|
||||
const extension = NavContentBlueprint.make({
|
||||
name: 'test',
|
||||
params: {
|
||||
component: () => <div>Nav content</div>,
|
||||
},
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension);
|
||||
|
||||
expect(
|
||||
tester.get(NavContentBlueprint.dataRefs.component)({ items: [] }),
|
||||
).toEqual(<div>Nav content</div>);
|
||||
});
|
||||
|
||||
it('should return a valid component with items', () => {
|
||||
const extension = NavContentBlueprint.make({
|
||||
name: 'test',
|
||||
params: {
|
||||
component: ({ items }) => (
|
||||
<div>
|
||||
Items:
|
||||
{items.map((item, index) => (
|
||||
<a key={index} href={item.to}>
|
||||
{item.title}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension);
|
||||
|
||||
expect(
|
||||
tester.get(NavContentBlueprint.dataRefs.component)({
|
||||
items: [
|
||||
{
|
||||
to: '/',
|
||||
text: 'Home',
|
||||
title: 'Home',
|
||||
icon: () => null,
|
||||
routeRef,
|
||||
},
|
||||
],
|
||||
}),
|
||||
).toEqual(
|
||||
<div>
|
||||
Items:
|
||||
{[
|
||||
<a key={0} href="/">
|
||||
Home
|
||||
</a>,
|
||||
]}
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { IconComponent, RouteRef } from '@backstage/frontend-plugin-api';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
|
||||
/**
|
||||
* The props for the {@link NavContentComponent}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface NavContentComponentProps {
|
||||
/**
|
||||
* The nav items available to the component. These are all the items created
|
||||
* with the {@link NavItemBlueprint} in the app.
|
||||
*
|
||||
* In addition to the original properties from the nav items, these also
|
||||
* include a resolved route path as `to`, and duplicated `title` as `text` to
|
||||
* simplify rendering.
|
||||
*/
|
||||
items: Array<{
|
||||
// Original props from nav items
|
||||
icon: IconComponent;
|
||||
title: string;
|
||||
routeRef: RouteRef<undefined>;
|
||||
|
||||
// Additional props to simplify item rendering
|
||||
to: string;
|
||||
text: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A component that renders the nav bar content, to be passed to the {@link NavContentBlueprint}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type NavContentComponent = (
|
||||
props: NavContentComponentProps,
|
||||
) => JSX.Element | null;
|
||||
|
||||
const componentDataRef = createExtensionDataRef<NavContentComponent>().with({
|
||||
id: 'core.nav-content.component',
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an extension that replaces the entire nav bar with your own component.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#NavContentBlueprint} instead.
|
||||
*/
|
||||
export const NavContentBlueprint = createExtensionBlueprint({
|
||||
kind: 'nav-content',
|
||||
attachTo: { id: 'app/nav', input: 'content' },
|
||||
output: [componentDataRef],
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
*factory(params: { component: NavContentComponent }) {
|
||||
yield componentDataRef(params.component);
|
||||
},
|
||||
});
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { RouterBlueprint } from './RouterBlueprint';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionInput,
|
||||
} from '../wiring';
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
|
||||
describe('RouterBlueprint', () => {
|
||||
it('should return an extension when calling make with sensible defaults', () => {
|
||||
const extension = RouterBlueprint.make({
|
||||
params: {
|
||||
component: props => <div>{props.children}</div>,
|
||||
},
|
||||
});
|
||||
|
||||
expect(extension).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "app/root",
|
||||
"input": "router",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "app-router-component",
|
||||
"name": undefined,
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should work with simple options', async () => {
|
||||
const extension = RouterBlueprint.make({
|
||||
params: {
|
||||
component: ({ children }) => (
|
||||
<MemoryRouter>
|
||||
<div data-testid="test-router">{children}</div>
|
||||
</MemoryRouter>
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension);
|
||||
const Component = tester.get(RouterBlueprint.dataRefs.component);
|
||||
|
||||
const { getByTestId } = render(
|
||||
<Component>
|
||||
<div data-testid="test-contents" />
|
||||
</Component>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('test-contents')).toBeInTheDocument();
|
||||
expect(getByTestId('test-router')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with complex options and props', async () => {
|
||||
const extension = RouterBlueprint.makeWithOverrides({
|
||||
name: 'test',
|
||||
config: {
|
||||
schema: {
|
||||
name: z => z.string(),
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
children: createExtensionInput([coreExtensionData.reactElement]),
|
||||
},
|
||||
*factory(originalFactory, { inputs, config }) {
|
||||
yield* originalFactory({
|
||||
component: ({ children }) => (
|
||||
<MemoryRouter>
|
||||
<div
|
||||
data-testid={`test-router-${config.name}-${inputs.children.length}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</MemoryRouter>
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension, {
|
||||
config: { name: 'Robin' },
|
||||
}).add(
|
||||
createExtension({
|
||||
attachTo: {
|
||||
id: 'app-router-component:test',
|
||||
input: 'children',
|
||||
},
|
||||
output: [coreExtensionData.reactElement],
|
||||
*factory() {
|
||||
yield coreExtensionData.reactElement(<div />);
|
||||
},
|
||||
}),
|
||||
);
|
||||
const Component = tester.get(RouterBlueprint.dataRefs.component);
|
||||
|
||||
const { getByTestId } = render(
|
||||
<Component>
|
||||
<div data-testid="test-contents" />
|
||||
</Component>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('test-contents')).toBeInTheDocument();
|
||||
expect(getByTestId('test-router-Robin-1')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { ReactNode } from 'react';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
|
||||
const componentDataRef = createExtensionDataRef<
|
||||
(props: { children: ReactNode }) => JSX.Element | null
|
||||
>().with({ id: 'app.router.wrapper' });
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#RouterBlueprint} instead.
|
||||
*/
|
||||
export const RouterBlueprint = createExtensionBlueprint({
|
||||
kind: 'app-router-component',
|
||||
attachTo: { id: 'app/root', input: 'router' },
|
||||
output: [componentDataRef],
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
*factory(params: {
|
||||
/** @deprecated use the `component` parameter instead */
|
||||
Component?: [error: 'Use the `component` parameter instead'];
|
||||
component: (props: { children: ReactNode }) => JSX.Element | null;
|
||||
}) {
|
||||
yield componentDataRef(params.component);
|
||||
},
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { SignInPageBlueprint } from './SignInPageBlueprint';
|
||||
import {
|
||||
createExtensionTester,
|
||||
renderInTestApp,
|
||||
} from '@backstage/frontend-test-utils';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
|
||||
describe('SignInPageBlueprint', () => {
|
||||
it('should create an extension with sensible defaults', () => {
|
||||
expect(
|
||||
SignInPageBlueprint.make({
|
||||
params: { loader: async () => () => <div /> },
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "app/root",
|
||||
"input": "signInPage",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "sign-in-page",
|
||||
"name": undefined,
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should return the component as the componentRef', async () => {
|
||||
const MockSignInPage = () => <div data-testid="mock-sign-in" />;
|
||||
|
||||
const extension = SignInPageBlueprint.make({
|
||||
params: { loader: async () => () => <MockSignInPage /> },
|
||||
});
|
||||
|
||||
const tester = createExtensionTester(extension);
|
||||
|
||||
const Component = tester.get(SignInPageBlueprint.dataRefs.component);
|
||||
|
||||
renderInTestApp(<Component onSignInSuccess={() => {}} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('mock-sign-in')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { ComponentType, lazy, ReactNode } from 'react';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
import { ExtensionBoundary } from '../components';
|
||||
import { IdentityApi } from '../apis';
|
||||
|
||||
/**
|
||||
* Props for the `SignInPage` component.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SignInPageProps = {
|
||||
/**
|
||||
* Set the IdentityApi on successful sign-in. This should only be called once.
|
||||
*/
|
||||
onSignInSuccess(identityApi: IdentityApi): void;
|
||||
|
||||
/**
|
||||
* The children to render.
|
||||
*/
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
const componentDataRef = createExtensionDataRef<
|
||||
ComponentType<SignInPageProps>
|
||||
>().with({ id: 'core.sign-in-page.component' });
|
||||
|
||||
/**
|
||||
* Creates an extension that replaces the sign in page.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#SignInPageBlueprint} instead.
|
||||
*/
|
||||
export const SignInPageBlueprint = createExtensionBlueprint({
|
||||
kind: 'sign-in-page',
|
||||
attachTo: { id: 'app/root', input: 'signInPage' },
|
||||
output: [componentDataRef],
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
*factory(
|
||||
{
|
||||
loader,
|
||||
}: {
|
||||
loader: () => Promise<ComponentType<SignInPageProps>>;
|
||||
},
|
||||
{ node },
|
||||
) {
|
||||
const ExtensionComponent = lazy(() =>
|
||||
loader().then(component => ({ default: component })),
|
||||
);
|
||||
|
||||
yield componentDataRef(props => (
|
||||
<ExtensionBoundary node={node}>
|
||||
<ExtensionComponent {...props} />
|
||||
</ExtensionBoundary>
|
||||
));
|
||||
},
|
||||
});
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 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 { renderTestApp } from '@backstage/frontend-test-utils';
|
||||
import { createSwappableComponent } from '../components';
|
||||
import { SwappableComponentBlueprint } from './SwappableComponentBlueprint';
|
||||
import { PageBlueprint } from './PageBlueprint';
|
||||
import { screen } from '@testing-library/react';
|
||||
|
||||
describe('SwappableComponentBlueprint', () => {
|
||||
it('should allow defining a component override for a component ref', () => {
|
||||
const Component = createSwappableComponent({
|
||||
id: 'test.component',
|
||||
loader: () => (props: { hello: string }) => <div>{props.hello}</div>,
|
||||
});
|
||||
|
||||
const extension = SwappableComponentBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
component: Component,
|
||||
loader: () => props => {
|
||||
// @ts-expect-error
|
||||
const t: number = props.hello;
|
||||
|
||||
return <div>Override {props.hello}</div>;
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
expect(extension).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render default component refs in the app', async () => {
|
||||
const TestComponent = createSwappableComponent({
|
||||
id: 'test.component',
|
||||
loader: () => (props: { hello: string }) => <div>{props.hello}</div>,
|
||||
});
|
||||
|
||||
renderTestApp({
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
path: '/',
|
||||
loader: async () => <TestComponent hello="test!" />,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
await expect(screen.findByText('test!')).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a component ref without a default implementation', async () => {
|
||||
const TestComponent = createSwappableComponent({
|
||||
id: 'test.component',
|
||||
});
|
||||
|
||||
renderTestApp({
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
path: '/',
|
||||
loader: async () => <TestComponent />,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
await expect(
|
||||
screen.findByTestId('test.component'),
|
||||
).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a component ref with an async loader implementation', async () => {
|
||||
const TestComponent = createSwappableComponent({
|
||||
id: 'test.component',
|
||||
loader: async () => (props: { hello: string }) =>
|
||||
<div>{props.hello}</div>,
|
||||
});
|
||||
|
||||
renderTestApp({
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
// todo(blam): there's a bug that this path cannot be `/`?
|
||||
path: '/',
|
||||
loader: async () => <TestComponent hello="test!" />,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
await expect(screen.findByText('test!')).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a component ref with an async loader implementation and prop transform', async () => {
|
||||
const TestComponent = createSwappableComponent({
|
||||
id: 'test.component',
|
||||
loader: async () => (props: { hello: string }) =>
|
||||
<div>{props.hello}</div>,
|
||||
transformProps: ({ hello }) => ({ hello: `tr ${hello}` }),
|
||||
});
|
||||
|
||||
renderTestApp({
|
||||
extensions: [
|
||||
PageBlueprint.make({
|
||||
params: define =>
|
||||
define({
|
||||
path: '/',
|
||||
loader: async () => <TestComponent hello="test!" />,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
await expect(screen.findByText('tr test!')).resolves.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 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 { SwappableComponentRef } from '../components';
|
||||
import {
|
||||
createExtensionBlueprint,
|
||||
createExtensionBlueprintParams,
|
||||
createExtensionDataRef,
|
||||
} from '../wiring';
|
||||
|
||||
export const componentDataRef = createExtensionDataRef<{
|
||||
ref: SwappableComponentRef;
|
||||
loader:
|
||||
| (() => (props: {}) => JSX.Element | null)
|
||||
| (() => Promise<(props: {}) => JSX.Element | null>);
|
||||
}>().with({ id: 'core.swappableComponent' });
|
||||
|
||||
/**
|
||||
* Blueprint for creating swappable components from a SwappableComponentRef and a loader
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#SwappableComponentBlueprint} instead.
|
||||
*/
|
||||
export const SwappableComponentBlueprint = createExtensionBlueprint({
|
||||
kind: 'component',
|
||||
attachTo: { id: 'api:app/swappable-components', input: 'components' },
|
||||
output: [componentDataRef],
|
||||
dataRefs: {
|
||||
component: componentDataRef,
|
||||
},
|
||||
defineParams<Ref extends SwappableComponentRef<any>>(params: {
|
||||
component: Ref extends SwappableComponentRef<
|
||||
any,
|
||||
infer IExternalComponentProps
|
||||
>
|
||||
? { ref: Ref } & ((props: IExternalComponentProps) => JSX.Element | null)
|
||||
: never;
|
||||
loader: Ref extends SwappableComponentRef<infer IInnerComponentProps, any>
|
||||
?
|
||||
| (() => (props: IInnerComponentProps) => JSX.Element | null)
|
||||
| (() => Promise<(props: IInnerComponentProps) => JSX.Element | null>)
|
||||
: never;
|
||||
}) {
|
||||
return createExtensionBlueprintParams(params);
|
||||
},
|
||||
factory: params => [
|
||||
componentDataRef({
|
||||
ref: params.component.ref,
|
||||
loader: params.loader,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { AppTheme } from '../apis/definitions/AppThemeApi';
|
||||
import { ThemeBlueprint } from './ThemeBlueprint';
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
|
||||
describe('ThemeBlueprint', () => {
|
||||
const theme = {
|
||||
id: 'light',
|
||||
colors: { primary: 'blue' },
|
||||
variant: 'dark',
|
||||
title: 'lols',
|
||||
Provider: (_: { children: React.ReactNode }) => null,
|
||||
} as AppTheme;
|
||||
|
||||
it('should create an extension with sensible defaults', () => {
|
||||
expect(ThemeBlueprint.make({ name: 'light', params: { theme } }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "api:app/app-theme",
|
||||
"input": "themes",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "theme",
|
||||
"name": "light",
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should return the theme as an themeDataRef', async () => {
|
||||
const extension = ThemeBlueprint.make({ params: { theme } });
|
||||
|
||||
expect(
|
||||
createExtensionTester(extension).get(ThemeBlueprint.dataRefs.theme),
|
||||
).toEqual(theme);
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { AppTheme } from '../apis/definitions/AppThemeApi';
|
||||
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
|
||||
const themeDataRef = createExtensionDataRef<AppTheme>().with({
|
||||
id: 'core.theme.theme',
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an extension that adds/replaces an app theme.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#ThemeBlueprint} instead.
|
||||
*/
|
||||
export const ThemeBlueprint = createExtensionBlueprint({
|
||||
kind: 'theme',
|
||||
attachTo: { id: 'api:app/app-theme', input: 'themes' },
|
||||
output: [themeDataRef],
|
||||
dataRefs: {
|
||||
theme: themeDataRef,
|
||||
},
|
||||
factory: ({ theme }: { theme: AppTheme }) => [themeDataRef(theme)],
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
import {
|
||||
createTranslationMessages,
|
||||
createTranslationRef,
|
||||
} from '../translation';
|
||||
import { TranslationBlueprint } from './TranslationBlueprint';
|
||||
|
||||
describe('TranslationBlueprint', () => {
|
||||
const translationRef = createTranslationRef({
|
||||
id: 'translationRefId',
|
||||
messages: {
|
||||
test: 'test',
|
||||
},
|
||||
});
|
||||
|
||||
const messages = createTranslationMessages({
|
||||
ref: translationRef,
|
||||
messages: {
|
||||
test: 'test2',
|
||||
},
|
||||
});
|
||||
|
||||
it('should return an extension instance with sane defaults', () => {
|
||||
expect(
|
||||
TranslationBlueprint.make({
|
||||
name: 'blob',
|
||||
params: {
|
||||
resource: messages,
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"T": undefined,
|
||||
"attachTo": {
|
||||
"id": "api:app/translations",
|
||||
"input": "translations",
|
||||
},
|
||||
"configSchema": undefined,
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "translation",
|
||||
"name": "blob",
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should output a translation data ref', () => {
|
||||
const extension = TranslationBlueprint.make({
|
||||
name: 'blob',
|
||||
params: {
|
||||
resource: messages,
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
createExtensionTester(extension).get(
|
||||
TranslationBlueprint.dataRefs.translation,
|
||||
),
|
||||
).toBe(messages);
|
||||
});
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
|
||||
import { TranslationMessages, TranslationResource } from '../translation';
|
||||
|
||||
const translationDataRef = createExtensionDataRef<
|
||||
TranslationResource | TranslationMessages
|
||||
>().with({ id: 'core.translation.translation' });
|
||||
|
||||
/**
|
||||
* Creates an extension that adds translations to your app.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link @backstage/plugin-app-react#TranslationBlueprint} instead.
|
||||
*/
|
||||
export const TranslationBlueprint = createExtensionBlueprint({
|
||||
kind: 'translation',
|
||||
attachTo: { id: 'api:app/translations', input: 'translations' },
|
||||
output: [translationDataRef],
|
||||
dataRefs: {
|
||||
translation: translationDataRef,
|
||||
},
|
||||
factory: ({
|
||||
resource,
|
||||
}: {
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
}) => [translationDataRef(resource)],
|
||||
});
|
||||
@@ -20,20 +20,5 @@ export {
|
||||
} from './AnalyticsImplementationBlueprint';
|
||||
export { ApiBlueprint } from './ApiBlueprint';
|
||||
export { AppRootElementBlueprint } from './AppRootElementBlueprint';
|
||||
export { AppRootWrapperBlueprint } from './AppRootWrapperBlueprint';
|
||||
export { IconBundleBlueprint } from './IconBundleBlueprint';
|
||||
export {
|
||||
NavContentBlueprint,
|
||||
type NavContentComponent,
|
||||
type NavContentComponentProps,
|
||||
} from './NavContentBlueprint';
|
||||
export { NavItemBlueprint } from './NavItemBlueprint';
|
||||
export { PageBlueprint } from './PageBlueprint';
|
||||
export { RouterBlueprint } from './RouterBlueprint';
|
||||
export {
|
||||
type SignInPageProps,
|
||||
SignInPageBlueprint,
|
||||
} from './SignInPageBlueprint';
|
||||
export { ThemeBlueprint } from './ThemeBlueprint';
|
||||
export { TranslationBlueprint } from './TranslationBlueprint';
|
||||
export { SwappableComponentBlueprint } from './SwappableComponentBlueprint';
|
||||
|
||||
Reference in New Issue
Block a user