chore: getting the tests working
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Fredrik Adelöw <freben@users.noreply.github.com> Co-authored-by: Camila Belo <camilaibs@users.noreply.github.com> Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
@@ -189,6 +189,27 @@ export type AnyRoutes = {
|
||||
[name in string]: RouteRef | SubRouteRef;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const ApiBlueprint: ExtensionBlueprint<
|
||||
'api',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
factory: AnyApiFactory;
|
||||
},
|
||||
ConfigurableExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
factory: ConfigurableExtensionDataRef<
|
||||
AnyApiFactory,
|
||||
'core.api.factory',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export { ApiFactory };
|
||||
|
||||
export { ApiHolder };
|
||||
@@ -240,6 +261,50 @@ export interface AppNodeSpec {
|
||||
readonly source?: BackstagePlugin;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const AppRootElementBlueprint: ExtensionBlueprint<
|
||||
'app-root-element',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
element: JSX.Element | (() => JSX.Element);
|
||||
},
|
||||
ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
never
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const AppRootWrapperBlueprint: ExtensionBlueprint<
|
||||
'app-root-wrapper',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
Component: ComponentType<PropsWithChildren<{}>>;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
React_2.ComponentType<{
|
||||
children?: React_2.ReactNode;
|
||||
}>,
|
||||
'app.root.wrapper',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
component: ConfigurableExtensionDataRef<
|
||||
React_2.ComponentType<{
|
||||
children?: React_2.ReactNode;
|
||||
}>,
|
||||
'app.root.wrapper',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export { AppTheme };
|
||||
|
||||
export { AppThemeApi };
|
||||
@@ -381,7 +446,7 @@ export type CoreNotFoundErrorPageProps = {
|
||||
// @public (undocumented)
|
||||
export type CoreProgressProps = {};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export function createApiExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -425,7 +490,7 @@ export { createApiFactory };
|
||||
|
||||
export { createApiRef };
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createAppRootElementExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -447,7 +512,7 @@ export function createAppRootElementExtension<
|
||||
}) => JSX_2.Element);
|
||||
}): ExtensionDefinition<TConfig>;
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createAppRootWrapperExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -675,7 +740,7 @@ export type CreateExtensionBlueprintOptions<
|
||||
},
|
||||
> = {
|
||||
kind: TKind;
|
||||
namespace?: TNamespace | ((params: TParams) => TNamespace);
|
||||
namespace?: TNamespace;
|
||||
attachTo: {
|
||||
id: string;
|
||||
input: string;
|
||||
@@ -683,9 +748,9 @@ export type CreateExtensionBlueprintOptions<
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
output: Array<UOutput>;
|
||||
name?: TName | ((params: TParams) => TName);
|
||||
name?: TName;
|
||||
config?: {
|
||||
schema: TConfigSchema | ((params: TParams) => TConfigSchema);
|
||||
schema: TConfigSchema;
|
||||
};
|
||||
factory(
|
||||
params: TParams,
|
||||
@@ -824,7 +889,7 @@ export function createExternalRouteRef<
|
||||
}
|
||||
>;
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createNavItemExtension(options: {
|
||||
namespace?: string;
|
||||
name?: string;
|
||||
@@ -859,7 +924,7 @@ export namespace createNavItemExtension {
|
||||
>;
|
||||
}
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createNavLogoExtension(options: {
|
||||
name?: string;
|
||||
namespace?: string;
|
||||
@@ -888,7 +953,7 @@ export namespace createNavLogoExtension {
|
||||
>;
|
||||
}
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createPageExtension<
|
||||
TConfig extends {
|
||||
path: string;
|
||||
@@ -958,7 +1023,7 @@ export function createRouteRef<
|
||||
}
|
||||
>;
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function createRouterExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -997,7 +1062,7 @@ export function createSchemaFromZod<TOutput, TInput>(
|
||||
schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>,
|
||||
): PortableSchema<TOutput, TInput>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export function createSignInPageExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
@@ -1036,7 +1101,7 @@ export function createSubRouteRef<
|
||||
parent: RouteRef<ParentParams>;
|
||||
}): MakeSubRouteRef<PathParams<Path>, ParentParams>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export function createThemeExtension(
|
||||
theme: AppTheme,
|
||||
): ExtensionDefinition<
|
||||
@@ -1049,7 +1114,7 @@ export function createThemeExtension(
|
||||
string | undefined
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export namespace createThemeExtension {
|
||||
const // (undocumented)
|
||||
themeDataRef: ConfigurableExtensionDataRef<
|
||||
@@ -1059,7 +1124,7 @@ export namespace createThemeExtension {
|
||||
>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export function createTranslationExtension(options: {
|
||||
name?: string;
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
@@ -1073,7 +1138,7 @@ export function createTranslationExtension(options: {
|
||||
string | undefined
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public @deprecated (undocumented)
|
||||
export namespace createTranslationExtension {
|
||||
const // (undocumented)
|
||||
translationDataRef: ConfigurableExtensionDataRef<
|
||||
@@ -1153,9 +1218,31 @@ export interface ExtensionBlueprint<
|
||||
> {
|
||||
// (undocumented)
|
||||
dataRefs: TDataRefs;
|
||||
// (undocumented)
|
||||
make<
|
||||
TNewNamespace extends string | undefined,
|
||||
TNewName extends string | undefined,
|
||||
>(args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: {
|
||||
id: string;
|
||||
input: string;
|
||||
};
|
||||
disabled?: boolean;
|
||||
params: TParams;
|
||||
}): ExtensionDefinition<
|
||||
TConfig,
|
||||
TConfigInput,
|
||||
UOutput,
|
||||
TInputs,
|
||||
TKind,
|
||||
string | undefined extends TNewNamespace ? TNamespace : TNewNamespace,
|
||||
string | undefined extends TNewName ? TName : TNewName
|
||||
>;
|
||||
makeWithOverrides<
|
||||
TNewNamespace extends string | undefined,
|
||||
TNewName extends string | undefined,
|
||||
TExtensionConfigSchema extends {
|
||||
[key in string]: (zImpl: typeof z) => z.ZodType;
|
||||
},
|
||||
@@ -1170,55 +1257,48 @@ export interface ExtensionBlueprint<
|
||||
}
|
||||
>;
|
||||
},
|
||||
>(
|
||||
args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: {
|
||||
id: string;
|
||||
input: string;
|
||||
>(args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: {
|
||||
id: string;
|
||||
input: string;
|
||||
};
|
||||
disabled?: boolean;
|
||||
inputs?: TExtraInputs & {
|
||||
[KName in keyof TInputs]?: `Error: Input '${KName &
|
||||
string}' is already defined in parent definition`;
|
||||
};
|
||||
output?: Array<UNewOutput>;
|
||||
config?: {
|
||||
schema: TExtensionConfigSchema & {
|
||||
[KName in keyof TConfig]?: `Error: Config key '${KName &
|
||||
string}' is already defined in parent schema`;
|
||||
};
|
||||
disabled?: boolean;
|
||||
inputs?: TExtraInputs & {
|
||||
[KName in keyof TInputs]?: `Error: Input '${KName &
|
||||
string}' is already defined in parent definition`;
|
||||
};
|
||||
output?: Array<UNewOutput>;
|
||||
config?: {
|
||||
schema: TExtensionConfigSchema & {
|
||||
[KName in keyof TConfig]?: `Error: Config key '${KName &
|
||||
string}' is already defined in parent schema`;
|
||||
};
|
||||
factory(
|
||||
originalFactory: (
|
||||
params: TParams,
|
||||
context?: {
|
||||
config?: TConfig;
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
) => ExtensionDataContainer<UOutput>,
|
||||
context: {
|
||||
node: AppNode;
|
||||
config: TConfig & {
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
};
|
||||
} & (
|
||||
| ({
|
||||
factory(
|
||||
originalFactory: (
|
||||
params: TParams,
|
||||
context?: {
|
||||
config?: TConfig;
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
) => ExtensionDataContainer<UOutput>,
|
||||
context: {
|
||||
node: AppNode;
|
||||
config: TConfig & {
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
inputs: Expand<ResolvedExtensionInputs<TInputs & TExtraInputs>>;
|
||||
},
|
||||
): Iterable<UFactoryOutput>;
|
||||
} & VerifyExtensionFactoryOutput<
|
||||
AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput,
|
||||
UFactoryOutput
|
||||
>)
|
||||
| {
|
||||
params: TParams;
|
||||
}
|
||||
),
|
||||
): ExtensionDefinition<
|
||||
inputs: Expand<ResolvedExtensionInputs<TInputs & TExtraInputs>>;
|
||||
},
|
||||
): Iterable<UFactoryOutput> &
|
||||
VerifyExtensionFactoryOutput<
|
||||
AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput,
|
||||
UFactoryOutput
|
||||
>;
|
||||
}): ExtensionDefinition<
|
||||
{
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
@@ -1616,6 +1696,73 @@ export interface LegacyExtensionInput<
|
||||
|
||||
export { microsoftAuthApiRef };
|
||||
|
||||
// @public (undocumented)
|
||||
export const NavItemBlueprint: ExtensionBlueprint<
|
||||
'nav-item',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
title: string;
|
||||
icon: IconComponent_2;
|
||||
routeRef: RouteRef<undefined>;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
{
|
||||
title: string;
|
||||
icon: IconComponent_2;
|
||||
routeRef: RouteRef<undefined>;
|
||||
},
|
||||
'core.nav-item.target',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
target: ConfigurableExtensionDataRef<
|
||||
{
|
||||
title: string;
|
||||
icon: IconComponent_2;
|
||||
routeRef: RouteRef<undefined>;
|
||||
},
|
||||
'core.nav-item.target',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const NavLogoBlueprint: ExtensionBlueprint<
|
||||
'nav-logo',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
logoIcon: JSX.Element;
|
||||
logoFull: JSX.Element;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
{
|
||||
logoIcon?: JSX.Element | undefined;
|
||||
logoFull?: JSX.Element | undefined;
|
||||
},
|
||||
'core.nav-logo.logo-elements',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
logoElements: ConfigurableExtensionDataRef<
|
||||
{
|
||||
logoIcon?: JSX.Element | undefined;
|
||||
logoFull?: JSX.Element | undefined;
|
||||
},
|
||||
'core.nav-logo.logo-elements',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export { OAuthApi };
|
||||
|
||||
export { OAuthRequestApi };
|
||||
@@ -1634,6 +1781,35 @@ export { oneloginAuthApiRef };
|
||||
|
||||
export { OpenIdConnectApi };
|
||||
|
||||
// @public (undocumented)
|
||||
export const PageBlueprint: ExtensionBlueprint<
|
||||
'page',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
defaultPath: string;
|
||||
loader: () => Promise<JSX.Element>;
|
||||
routeRef?: RouteRef<AnyRouteRefParams> | undefined;
|
||||
},
|
||||
| ConfigurableExtensionDataRef<React_2.JSX.Element, 'core.reactElement', {}>
|
||||
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
|
||||
| ConfigurableExtensionDataRef<
|
||||
RouteRef<AnyRouteRefParams>,
|
||||
'core.routing.ref',
|
||||
RouteRef<AnyRouteRefParams> & {
|
||||
optional: true;
|
||||
}
|
||||
>,
|
||||
{},
|
||||
{
|
||||
path: string | undefined;
|
||||
},
|
||||
{
|
||||
path?: string | undefined;
|
||||
},
|
||||
never
|
||||
>;
|
||||
|
||||
export { PendingOAuthRequest };
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -1699,6 +1875,35 @@ export type RouteFunc<TParams extends AnyRouteRefParams> = (
|
||||
: readonly [params: TParams]
|
||||
) => string;
|
||||
|
||||
// @public (undocumented)
|
||||
export const RouterBlueprint: ExtensionBlueprint<
|
||||
'app-router-component',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
Component: ComponentType<PropsWithChildren<{}>>;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
ComponentType<{
|
||||
children?: ReactNode;
|
||||
}>,
|
||||
'app.router.wrapper',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
component: ConfigurableExtensionDataRef<
|
||||
ComponentType<{
|
||||
children?: ReactNode;
|
||||
}>,
|
||||
'app.router.wrapper',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
// @public
|
||||
export interface RouteRef<
|
||||
TParams extends AnyRouteRefParams = AnyRouteRefParams,
|
||||
@@ -1733,6 +1938,31 @@ export { SessionApi };
|
||||
|
||||
export { SessionState };
|
||||
|
||||
// @public (undocumented)
|
||||
export const SignInPageBlueprint: ExtensionBlueprint<
|
||||
'sign-in-page',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
loader: () => Promise<ComponentType<SignInPageProps>>;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
React_2.ComponentType<SignInPageProps>,
|
||||
'core.sign-in-page.component',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
component: ConfigurableExtensionDataRef<
|
||||
React_2.ComponentType<SignInPageProps>,
|
||||
'core.sign-in-page.component',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export { StorageApi };
|
||||
|
||||
export { storageApiRef };
|
||||
@@ -1751,6 +1981,62 @@ export interface SubRouteRef<
|
||||
readonly T: TParams;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const ThemeBlueprint: ExtensionBlueprint<
|
||||
'theme',
|
||||
'app',
|
||||
undefined,
|
||||
{
|
||||
theme: AppTheme;
|
||||
},
|
||||
ConfigurableExtensionDataRef<AppTheme, 'core.theme.theme', {}>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
theme: ConfigurableExtensionDataRef<AppTheme, 'core.theme.theme', {}>;
|
||||
}
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const TranslationBlueprint: ExtensionBlueprint<
|
||||
'translation',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
},
|
||||
ConfigurableExtensionDataRef<
|
||||
| TranslationResource<string>
|
||||
| TranslationMessages<
|
||||
string,
|
||||
{
|
||||
[x: string]: string;
|
||||
},
|
||||
boolean
|
||||
>,
|
||||
'core.translation.translation',
|
||||
{}
|
||||
>,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
translation: ConfigurableExtensionDataRef<
|
||||
| TranslationResource<string>
|
||||
| TranslationMessages<
|
||||
string,
|
||||
{
|
||||
[x: string]: string;
|
||||
},
|
||||
boolean
|
||||
>,
|
||||
'core.translation.translation',
|
||||
{}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export { TranslationMessages };
|
||||
|
||||
export { TranslationMessagesOptions };
|
||||
|
||||
+2
-1
@@ -30,6 +30,7 @@ describe('ApiBlueprint', () => {
|
||||
params: {
|
||||
factory,
|
||||
},
|
||||
namespace: 'test',
|
||||
});
|
||||
|
||||
expect(extension).toMatchInlineSnapshot(`
|
||||
@@ -60,7 +61,7 @@ describe('ApiBlueprint', () => {
|
||||
const api = createApiRef<{ foo: string }>({ id: 'test' });
|
||||
const factory = jest.fn(() => ({ foo: 'bar' }));
|
||||
|
||||
const extension = ApiBlueprint.make({
|
||||
const extension = ApiBlueprint.makeWithOverrides({
|
||||
config: {
|
||||
schema: {
|
||||
test: z => z.string().default('test'),
|
||||
+2
-2
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createApiExtension } from './createApiExtension';
|
||||
import { createApiExtension } from '../extensions/createApiExtension';
|
||||
import { AnyApiFactory } from '@backstage/core-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export const ApiBlueprint = createExtensionBlueprint({
|
||||
kind: 'api',
|
||||
attachTo: { id: 'app', input: 'apis' },
|
||||
@@ -27,5 +28,4 @@ export const ApiBlueprint = createExtensionBlueprint({
|
||||
*factory(params: { factory: AnyApiFactory }) {
|
||||
yield createApiExtension.factoryDataRef(params.factory);
|
||||
},
|
||||
namespace: ({ factory }) => factory.api.id,
|
||||
});
|
||||
+1
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
import { coreExtensionData, createExtensionBlueprint } from '../wiring';
|
||||
|
||||
/** @public */
|
||||
export const AppRootElementBlueprint = createExtensionBlueprint({
|
||||
kind: 'app-root-element',
|
||||
attachTo: { id: 'app/root', input: 'elements' },
|
||||
+5
-2
@@ -78,7 +78,7 @@ describe('AppRootWrapperBlueprint', () => {
|
||||
});
|
||||
|
||||
it('should render the complex component wrapper', async () => {
|
||||
const extension = AppRootWrapperBlueprint.make({
|
||||
const extension = AppRootWrapperBlueprint.makeWithOverrides({
|
||||
namespace: 'ns',
|
||||
name: 'test',
|
||||
config: {
|
||||
@@ -94,6 +94,9 @@ describe('AppRootWrapperBlueprint', () => {
|
||||
Component: ({ children }) => (
|
||||
<div data-testid={`${config.name}-${inputs.children.length}`}>
|
||||
{children}
|
||||
{inputs.children.flatMap(c =>
|
||||
c.get(coreExtensionData.reactElement),
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
});
|
||||
@@ -119,9 +122,9 @@ describe('AppRootWrapperBlueprint', () => {
|
||||
.render();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Its Me')).toBeInTheDocument();
|
||||
expect(getByText('Hi')).toBeInTheDocument();
|
||||
expect(getByTestId('Robin-1')).toBeInTheDocument();
|
||||
expect(getByText('Its Me')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
+2
-1
@@ -17,8 +17,9 @@
|
||||
import React from 'react';
|
||||
import { ComponentType, PropsWithChildren } from 'react';
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createAppRootWrapperExtension } from './createAppRootWrapperExtension';
|
||||
import { createAppRootWrapperExtension } from '../extensions/createAppRootWrapperExtension';
|
||||
|
||||
/** @public */
|
||||
export const AppRootWrapperBlueprint = createExtensionBlueprint({
|
||||
kind: 'app-root-wrapper',
|
||||
attachTo: { id: 'app/root', input: 'wrappers' },
|
||||
-1
@@ -44,7 +44,6 @@ describe('NavItemBlueprint', () => {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"title": {
|
||||
"default": "TEST",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
+7
-5
@@ -17,8 +17,9 @@
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { RouteRef } from '../routing';
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createNavItemExtension } from './createNavItemExtension';
|
||||
import { createNavItemExtension } from '../extensions/createNavItemExtension';
|
||||
|
||||
/** @public */
|
||||
export const NavItemBlueprint = createExtensionBlueprint({
|
||||
kind: 'nav-item',
|
||||
attachTo: { id: 'app/nav', input: 'items' },
|
||||
@@ -30,6 +31,7 @@ export const NavItemBlueprint = createExtensionBlueprint({
|
||||
{
|
||||
icon,
|
||||
routeRef,
|
||||
title,
|
||||
}: {
|
||||
title: string;
|
||||
icon: IconComponent;
|
||||
@@ -38,14 +40,14 @@ export const NavItemBlueprint = createExtensionBlueprint({
|
||||
{ config },
|
||||
) => [
|
||||
createNavItemExtension.targetDataRef({
|
||||
title: config.title,
|
||||
title: config.title ?? title,
|
||||
icon,
|
||||
routeRef,
|
||||
}),
|
||||
],
|
||||
config: {
|
||||
schema: ({ title }) => ({
|
||||
title: z => z.string().default(title),
|
||||
}),
|
||||
schema: {
|
||||
title: z => z.string().optional(),
|
||||
},
|
||||
},
|
||||
});
|
||||
+2
-1
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createNavLogoExtension } from './createNavLogoExtension';
|
||||
import { createNavLogoExtension } from '../extensions/createNavLogoExtension';
|
||||
|
||||
/** @public */
|
||||
export const NavLogoBlueprint = createExtensionBlueprint({
|
||||
kind: 'nav-logo',
|
||||
attachTo: { id: 'app/nav', input: 'logos' },
|
||||
+1
-1
@@ -106,7 +106,7 @@ describe('PageBlueprint', () => {
|
||||
});
|
||||
|
||||
it('should allow defining additional inputs to the extension', async () => {
|
||||
const myPage = PageBlueprint.make({
|
||||
const myPage = PageBlueprint.makeWithOverrides({
|
||||
name: 'test-page',
|
||||
inputs: {
|
||||
cards: createExtensionInput([coreExtensionData.reactElement], {
|
||||
+3
-2
@@ -18,6 +18,7 @@ import { RouteRef } from '../routing';
|
||||
import { coreExtensionData, createExtensionBlueprint } from '../wiring';
|
||||
import { ExtensionBoundary } from '../components';
|
||||
|
||||
/** @public */
|
||||
export const PageBlueprint = createExtensionBlueprint({
|
||||
kind: 'page',
|
||||
attachTo: { id: 'app/routes', input: 'routes' },
|
||||
@@ -37,7 +38,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
loader,
|
||||
routeRef,
|
||||
}: {
|
||||
defaultPath?: string;
|
||||
defaultPath: string;
|
||||
loader: () => Promise<JSX.Element>;
|
||||
routeRef?: RouteRef;
|
||||
},
|
||||
@@ -47,7 +48,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
loader().then(element => ({ default: () => element })),
|
||||
);
|
||||
|
||||
yield coreExtensionData.routePath(config.path ?? defaultPath!);
|
||||
yield coreExtensionData.routePath(config.path ?? defaultPath);
|
||||
yield coreExtensionData.reactElement(
|
||||
<ExtensionBoundary node={node}>
|
||||
<ExtensionComponent />
|
||||
+1
-1
@@ -97,7 +97,7 @@ describe('RouterBlueprint', () => {
|
||||
});
|
||||
|
||||
it('should work with complex options and props', async () => {
|
||||
const extension = RouterBlueprint.make({
|
||||
const extension = RouterBlueprint.makeWithOverrides({
|
||||
namespace: 'test',
|
||||
name: 'test',
|
||||
config: {
|
||||
+2
-1
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
import { ComponentType, PropsWithChildren } from 'react';
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createRouterExtension } from './createRouterExtension';
|
||||
import { createRouterExtension } from '../extensions/createRouterExtension';
|
||||
|
||||
/** @public */
|
||||
export const RouterBlueprint = createExtensionBlueprint({
|
||||
kind: 'app-router-component',
|
||||
attachTo: { id: 'app/root', input: 'router' },
|
||||
+2
-1
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
import React, { ComponentType, lazy } from 'react';
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createSignInPageExtension } from './createSignInPageExtension';
|
||||
import { createSignInPageExtension } from '../extensions/createSignInPageExtension';
|
||||
import { SignInPageProps } from '@backstage/core-plugin-api';
|
||||
import { ExtensionBoundary } from '../components';
|
||||
|
||||
/** @public */
|
||||
export const SignInPageBlueprint = createExtensionBlueprint({
|
||||
kind: 'sign-in-page',
|
||||
attachTo: { id: 'app/root', input: 'signInPage' },
|
||||
+2
-1
@@ -27,7 +27,8 @@ describe('ThemeBlueprint', () => {
|
||||
} as AppTheme;
|
||||
|
||||
it('should create an extension with sensible defaults', () => {
|
||||
expect(ThemeBlueprint.make({ params: { theme } })).toMatchInlineSnapshot(`
|
||||
expect(ThemeBlueprint.make({ name: 'light', params: { theme } }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"attachTo": {
|
||||
+2
-2
@@ -16,12 +16,12 @@
|
||||
|
||||
import { AppTheme } from '@backstage/core-plugin-api';
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createThemeExtension } from './createThemeExtension';
|
||||
import { createThemeExtension } from '../extensions/createThemeExtension';
|
||||
|
||||
/** @public */
|
||||
export const ThemeBlueprint = createExtensionBlueprint({
|
||||
kind: 'theme',
|
||||
namespace: 'app',
|
||||
name: ({ theme }) => theme.id,
|
||||
attachTo: { id: 'app', input: 'themes' },
|
||||
output: [createThemeExtension.themeDataRef],
|
||||
dataRefs: {
|
||||
+1
-1
@@ -56,7 +56,7 @@ describe('TranslationBlueprint', () => {
|
||||
"inputs": {},
|
||||
"kind": "translation",
|
||||
"name": "blob",
|
||||
"namespace": "translationRefId",
|
||||
"namespace": undefined,
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
+2
-2
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
|
||||
import { createExtensionBlueprint } from '../wiring';
|
||||
import { createTranslationExtension } from './createTranslationExtension';
|
||||
import { createTranslationExtension } from '../extensions/createTranslationExtension';
|
||||
import { TranslationMessages, TranslationResource } from '../translation';
|
||||
|
||||
/** @public */
|
||||
export const TranslationBlueprint = createExtensionBlueprint({
|
||||
kind: 'translation',
|
||||
namespace: ({ resource }) => resource.id,
|
||||
attachTo: { id: 'app', input: 'translations' },
|
||||
output: [createTranslationExtension.translationDataRef],
|
||||
dataRefs: {
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { ApiBlueprint } from './ApiBlueprint';
|
||||
export { AppRootElementBlueprint } from './AppRootElementBlueprint';
|
||||
export { AppRootWrapperBlueprint } from './AppRootWrapperBlueprint';
|
||||
export { IconBundleBlueprint } from './IconBundleBlueprint';
|
||||
export { NavItemBlueprint } from './NavItemBlueprint';
|
||||
export { NavLogoBlueprint } from './NavLogoBlueprint';
|
||||
export { PageBlueprint } from './PageBlueprint';
|
||||
export { RouterBlueprint } from './RouterBlueprint';
|
||||
export { SignInPageBlueprint } from './SignInPageBlueprint';
|
||||
export { ThemeBlueprint } from './ThemeBlueprint';
|
||||
export { TranslationBlueprint } from './TranslationBlueprint';
|
||||
@@ -24,7 +24,10 @@ import {
|
||||
import { AnyExtensionInputMap } from '../wiring/createExtension';
|
||||
import { Expand } from '../types';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link ApiBlueprint} instead.
|
||||
*/
|
||||
export function createApiExtension<
|
||||
TConfig extends {},
|
||||
TInputs extends AnyExtensionInputMap,
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
* the app layout. This is useful for example for shared popups and similar.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link AppRootElementBlueprint} instead.
|
||||
*/
|
||||
export function createAppRootElementExtension<
|
||||
TConfig extends {},
|
||||
|
||||
@@ -31,6 +31,7 @@ import { Expand } from '../types';
|
||||
* and similar.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link AppRootWrapperBlueprint} instead.
|
||||
*/
|
||||
export function createAppRootWrapperExtension<
|
||||
TConfig extends {},
|
||||
|
||||
@@ -21,7 +21,9 @@ import { RouteRef } from '../routing';
|
||||
|
||||
/**
|
||||
* Helper for creating extensions for a nav item.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link NavItemBlueprint} instead.
|
||||
*/
|
||||
export function createNavItemExtension(options: {
|
||||
namespace?: string;
|
||||
|
||||
@@ -18,7 +18,9 @@ import { createExtension, createExtensionDataRef } from '../wiring';
|
||||
|
||||
/**
|
||||
* Helper for creating extensions for a nav logos.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link NavLogoBlueprint} instead.
|
||||
*/
|
||||
export function createNavLogoExtension(options: {
|
||||
name?: string;
|
||||
|
||||
@@ -31,6 +31,7 @@ import { ExtensionDefinition } from '../wiring/createExtension';
|
||||
* Helper for creating extensions for a routable React page component.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link PageBlueprint} instead.
|
||||
*/
|
||||
export function createPageExtension<
|
||||
TConfig extends { path: string },
|
||||
|
||||
@@ -31,6 +31,7 @@ import { Expand } from '../types';
|
||||
* MemoryRouter in tests, or to add additional props to a BrowserRouter.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link RouterBlueprint} instead.
|
||||
*/
|
||||
export function createRouterExtension<
|
||||
TConfig extends {},
|
||||
|
||||
@@ -30,6 +30,7 @@ import { SignInPageProps } from '@backstage/core-plugin-api';
|
||||
/**
|
||||
*
|
||||
* @public
|
||||
* @deprecated Use {@link SignInPageBlueprint} instead.
|
||||
*/
|
||||
export function createSignInPageExtension<
|
||||
TConfig extends {},
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
import { createExtension, createExtensionDataRef } from '../wiring';
|
||||
import { AppTheme } from '@backstage/core-plugin-api';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link ThemeBlueprint} instead.
|
||||
*/
|
||||
export function createThemeExtension(theme: AppTheme) {
|
||||
return createExtension({
|
||||
kind: 'theme',
|
||||
@@ -31,7 +34,10 @@ export function createThemeExtension(theme: AppTheme) {
|
||||
});
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link ThemeBlueprint} instead.
|
||||
*/
|
||||
export namespace createThemeExtension {
|
||||
export const themeDataRef = createExtensionDataRef<AppTheme>().with({
|
||||
id: 'core.theme.theme',
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
import { TranslationMessages, TranslationResource } from '../translation';
|
||||
import { createExtension, createExtensionDataRef } from '../wiring';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link TranslationBlueprint} instead.
|
||||
*/
|
||||
export function createTranslationExtension(options: {
|
||||
name?: string;
|
||||
resource: TranslationResource | TranslationMessages;
|
||||
@@ -34,7 +37,10 @@ export function createTranslationExtension(options: {
|
||||
});
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use {@link TranslationBlueprint} instead.
|
||||
*/
|
||||
export namespace createTranslationExtension {
|
||||
export const translationDataRef = createExtensionDataRef<
|
||||
TranslationResource | TranslationMessages
|
||||
|
||||
@@ -25,4 +25,3 @@ export { createSignInPageExtension } from './createSignInPageExtension';
|
||||
export { createThemeExtension } from './createThemeExtension';
|
||||
export { createComponentExtension } from './createComponentExtension';
|
||||
export { createTranslationExtension } from './createTranslationExtension';
|
||||
export { IconBundleBlueprint } from './IconBundleBlueprint';
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
export * from './analytics';
|
||||
export * from './apis';
|
||||
export * from './blueprints';
|
||||
export * from './components';
|
||||
export * from './extensions';
|
||||
export * from './icons';
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const extension = TestExtensionBlueprint.make({
|
||||
const extension = TestExtensionBlueprint.makeWithOverrides({
|
||||
name: 'my-extension',
|
||||
factory(origFactory) {
|
||||
return origFactory({
|
||||
@@ -185,11 +185,8 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const extension = TestExtensionBlueprint.make({
|
||||
const extension = TestExtensionBlueprint.makeWithOverrides({
|
||||
name: 'my-extension',
|
||||
params: {
|
||||
text: 'Hello, world!',
|
||||
},
|
||||
config: {
|
||||
schema: {
|
||||
something: z => z.string(),
|
||||
@@ -236,7 +233,7 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
TestExtensionBlueprint.make({
|
||||
TestExtensionBlueprint.makeWithOverrides({
|
||||
name: 'my-extension',
|
||||
params: {
|
||||
text: 'Hello, world!',
|
||||
@@ -266,11 +263,8 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const extension = TestExtensionBlueprint.make({
|
||||
const extension = TestExtensionBlueprint.makeWithOverrides({
|
||||
name: 'my-extension',
|
||||
params: {
|
||||
text: 'Hello, world!',
|
||||
},
|
||||
config: {
|
||||
schema: {
|
||||
something: z => z.string(),
|
||||
@@ -341,65 +335,6 @@ describe('createExtensionBlueprint', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow providing callback for properties to set with params', () => {
|
||||
type TestParams = { test: string };
|
||||
|
||||
const Blueprint = createExtensionBlueprint({
|
||||
kind: 'test-extension',
|
||||
attachTo: { id: 'test', input: 'default' },
|
||||
name: (params: TestParams) => `${params.test}-name`,
|
||||
output: [coreExtensionData.reactElement],
|
||||
namespace: (props: TestParams) => props.test,
|
||||
config: {
|
||||
schema: (props: TestParams) => ({
|
||||
test: z => z.string().default(props.test),
|
||||
}),
|
||||
},
|
||||
factory(params: TestParams) {
|
||||
return [coreExtensionData.reactElement(<div>{params.test}</div>)];
|
||||
},
|
||||
});
|
||||
|
||||
expect(Blueprint.make({ params: { test: 'hello' } }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"$$type": "@backstage/ExtensionDefinition",
|
||||
"attachTo": {
|
||||
"id": "test",
|
||||
"input": "default",
|
||||
},
|
||||
"configSchema": {
|
||||
"parse": [Function],
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"test": {
|
||||
"default": "hello",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
"inputs": {},
|
||||
"kind": "test-extension",
|
||||
"name": "hello-name",
|
||||
"namespace": "hello",
|
||||
"output": [
|
||||
[Function],
|
||||
],
|
||||
"override": [Function],
|
||||
"toString": [Function],
|
||||
"version": "v2",
|
||||
}
|
||||
`);
|
||||
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow merging of inputs', () => {
|
||||
const blueprint = createExtensionBlueprint({
|
||||
kind: 'test-extension',
|
||||
@@ -418,7 +353,7 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
test2: createExtensionInput([coreExtensionData.reactElement], {
|
||||
singleton: true,
|
||||
@@ -453,7 +388,7 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
// @ts-expect-error
|
||||
test: createExtensionInput([]), // Overrides are not allowed
|
||||
@@ -480,7 +415,7 @@ describe('createExtensionBlueprint', () => {
|
||||
});
|
||||
|
||||
const ext = toInternalExtensionDefinition(
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef2],
|
||||
factory(origFactory) {
|
||||
const parent = origFactory({});
|
||||
@@ -509,7 +444,7 @@ describe('createExtensionBlueprint', () => {
|
||||
|
||||
expect(
|
||||
factoryOutput(
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef1, testDataRef2],
|
||||
*factory(origFactory) {
|
||||
yield* origFactory({});
|
||||
@@ -521,7 +456,7 @@ describe('createExtensionBlueprint', () => {
|
||||
|
||||
expect(
|
||||
factoryOutput(
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef1, testDataRef2],
|
||||
factory(origFactory) {
|
||||
return [...origFactory({}), testDataRef2('bar')];
|
||||
@@ -544,9 +479,9 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-expect-error
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef2.optional()],
|
||||
// @ts-expect-error
|
||||
*factory() {
|
||||
yield testDataRef1('foo');
|
||||
yield testDataRef2('bar');
|
||||
@@ -555,7 +490,7 @@ describe('createExtensionBlueprint', () => {
|
||||
|
||||
expect(
|
||||
factoryOutput(
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef2.optional()],
|
||||
*factory() {
|
||||
yield testDataRef2('bar');
|
||||
@@ -578,9 +513,9 @@ describe('createExtensionBlueprint', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-expect-error
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef1, testDataRef2],
|
||||
// @ts-expect-error
|
||||
*factory(origFactory) {
|
||||
yield* origFactory({});
|
||||
},
|
||||
@@ -588,7 +523,7 @@ describe('createExtensionBlueprint', () => {
|
||||
|
||||
expect(
|
||||
factoryOutput(
|
||||
blueprint.make({
|
||||
blueprint.makeWithOverrides({
|
||||
output: [testDataRef1, testDataRef2],
|
||||
*factory(origFactory) {
|
||||
yield* origFactory({});
|
||||
|
||||
@@ -52,14 +52,14 @@ export type CreateExtensionBlueprintOptions<
|
||||
TDataRefs extends { [name in string]: AnyExtensionDataRef },
|
||||
> = {
|
||||
kind: TKind;
|
||||
namespace?: TNamespace | ((params: TParams) => TNamespace);
|
||||
namespace?: TNamespace;
|
||||
attachTo: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
inputs?: TInputs;
|
||||
output: Array<UOutput>;
|
||||
name?: TName | ((params: TParams) => TName);
|
||||
name?: TName;
|
||||
config?: {
|
||||
schema: TConfigSchema | ((params: TParams) => TConfigSchema);
|
||||
schema: TConfigSchema;
|
||||
};
|
||||
factory(
|
||||
params: TParams,
|
||||
@@ -96,13 +96,32 @@ export interface ExtensionBlueprint<
|
||||
> {
|
||||
dataRefs: TDataRefs;
|
||||
|
||||
make<
|
||||
TNewNamespace extends string | undefined,
|
||||
TNewName extends string | undefined,
|
||||
>(args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
params: TParams;
|
||||
}): ExtensionDefinition<
|
||||
TConfig,
|
||||
TConfigInput,
|
||||
UOutput,
|
||||
TInputs,
|
||||
TKind,
|
||||
string | undefined extends TNewNamespace ? TNamespace : TNewNamespace,
|
||||
string | undefined extends TNewName ? TName : TNewName
|
||||
>;
|
||||
|
||||
/**
|
||||
* Creates a new extension from the blueprint.
|
||||
*
|
||||
* You must either pass `params` directly, or define a `factory` that can
|
||||
* optionally call the original factory with the same params.
|
||||
*/
|
||||
make<
|
||||
makeWithOverrides<
|
||||
TNewNamespace extends string | undefined,
|
||||
TNewName extends string | undefined,
|
||||
TExtensionConfigSchema extends {
|
||||
@@ -116,52 +135,45 @@ export interface ExtensionBlueprint<
|
||||
{ optional: boolean; singleton: boolean }
|
||||
>;
|
||||
},
|
||||
>(
|
||||
args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
inputs?: TExtraInputs & {
|
||||
[KName in keyof TInputs]?: `Error: Input '${KName &
|
||||
string}' is already defined in parent definition`;
|
||||
>(args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
inputs?: TExtraInputs & {
|
||||
[KName in keyof TInputs]?: `Error: Input '${KName &
|
||||
string}' is already defined in parent definition`;
|
||||
};
|
||||
output?: Array<UNewOutput>;
|
||||
config?: {
|
||||
schema: TExtensionConfigSchema & {
|
||||
[KName in keyof TConfig]?: `Error: Config key '${KName &
|
||||
string}' is already defined in parent schema`;
|
||||
};
|
||||
output?: Array<UNewOutput>;
|
||||
config?: {
|
||||
schema: TExtensionConfigSchema & {
|
||||
[KName in keyof TConfig]?: `Error: Config key '${KName &
|
||||
string}' is already defined in parent schema`;
|
||||
};
|
||||
factory(
|
||||
originalFactory: (
|
||||
params: TParams,
|
||||
context?: {
|
||||
config?: TConfig;
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
) => ExtensionDataContainer<UOutput>,
|
||||
context: {
|
||||
node: AppNode;
|
||||
config: TConfig & {
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
};
|
||||
} & (
|
||||
| ({
|
||||
factory(
|
||||
originalFactory: (
|
||||
params: TParams,
|
||||
context?: {
|
||||
config?: TConfig;
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
) => ExtensionDataContainer<UOutput>,
|
||||
context: {
|
||||
node: AppNode;
|
||||
config: TConfig & {
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
inputs: Expand<ResolvedExtensionInputs<TInputs & TExtraInputs>>;
|
||||
},
|
||||
): Iterable<UFactoryOutput>;
|
||||
} & VerifyExtensionFactoryOutput<
|
||||
AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput,
|
||||
UFactoryOutput
|
||||
>)
|
||||
| {
|
||||
params: TParams;
|
||||
}
|
||||
),
|
||||
): ExtensionDefinition<
|
||||
inputs: Expand<ResolvedExtensionInputs<TInputs & TExtraInputs>>;
|
||||
},
|
||||
): Iterable<UFactoryOutput> &
|
||||
VerifyExtensionFactoryOutput<
|
||||
AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput,
|
||||
UFactoryOutput
|
||||
>;
|
||||
}): ExtensionDefinition<
|
||||
{
|
||||
[key in keyof TExtensionConfigSchema]: z.infer<
|
||||
ReturnType<TExtensionConfigSchema[key]>
|
||||
@@ -243,7 +255,7 @@ class ExtensionBlueprintImpl<
|
||||
|
||||
dataRefs: TDataRefs;
|
||||
|
||||
public make<
|
||||
public makeWithOverrides<
|
||||
TExtensionConfigSchema extends {
|
||||
[key in string]: (zImpl: typeof z) => z.ZodType;
|
||||
},
|
||||
@@ -264,11 +276,10 @@ class ExtensionBlueprintImpl<
|
||||
disabled?: boolean;
|
||||
inputs?: TExtraInputs;
|
||||
output?: Array<UNewOutput>;
|
||||
params?: TParams;
|
||||
config?: {
|
||||
schema: TExtensionConfigSchema;
|
||||
};
|
||||
factory?(
|
||||
factory(
|
||||
originalFactory: (
|
||||
params: TParams,
|
||||
context?: {
|
||||
@@ -312,77 +323,82 @@ class ExtensionBlueprintImpl<
|
||||
>
|
||||
>
|
||||
> {
|
||||
const optionsSchema = // can remove this args.params check with the split apart of .make
|
||||
typeof this.options.config?.schema === 'function' && args.params
|
||||
? this.options.config?.schema(args.params)
|
||||
: this.options.config?.schema;
|
||||
|
||||
const schema = {
|
||||
...optionsSchema,
|
||||
...this.options.config?.schema,
|
||||
...args.config?.schema,
|
||||
} as TConfigSchema & TExtensionConfigSchema;
|
||||
|
||||
const namespace =
|
||||
typeof this.options.namespace === 'function' && args.params
|
||||
? this.options.namespace(args.params)
|
||||
: this.options.namespace;
|
||||
|
||||
const name =
|
||||
typeof this.options.name === 'function' && args.params
|
||||
? this.options.name(args.params)
|
||||
: this.options.name;
|
||||
|
||||
return createExtension({
|
||||
kind: this.options.kind,
|
||||
namespace: args.namespace ?? namespace,
|
||||
name: args.name ?? name,
|
||||
namespace: args.namespace ?? this.options.namespace,
|
||||
name: args.name ?? this.options.name,
|
||||
attachTo: args.attachTo ?? this.options.attachTo,
|
||||
disabled: args.disabled ?? this.options.disabled,
|
||||
inputs: { ...args.inputs, ...this.options.inputs },
|
||||
output: args.output ?? this.options.output,
|
||||
config: Object.keys(schema).length === 0 ? undefined : { schema },
|
||||
factory: ({ node, config, inputs }) => {
|
||||
if (args.factory) {
|
||||
return args.factory(
|
||||
(
|
||||
innerParams: TParams,
|
||||
innerContext?: {
|
||||
config?: {
|
||||
[key in keyof TConfigSchema]: z.infer<
|
||||
ReturnType<TConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
): ExtensionDataContainer<UOutput> => {
|
||||
return createDataContainer<UOutput>(
|
||||
this.options.factory(innerParams, {
|
||||
node,
|
||||
config: innerContext?.config ?? config,
|
||||
inputs: (innerContext?.inputs ?? inputs) as any, // TODO: Fix the way input values are overridden
|
||||
}),
|
||||
);
|
||||
return args.factory(
|
||||
(
|
||||
innerParams: TParams,
|
||||
innerContext?: {
|
||||
config?: {
|
||||
[key in keyof TConfigSchema]: z.infer<
|
||||
ReturnType<TConfigSchema[key]>
|
||||
>;
|
||||
};
|
||||
inputs?: Expand<ResolvedExtensionInputs<TInputs>>;
|
||||
},
|
||||
{
|
||||
node,
|
||||
config,
|
||||
inputs,
|
||||
},
|
||||
);
|
||||
} else if (args.params) {
|
||||
return this.options.factory(args.params, {
|
||||
): ExtensionDataContainer<UOutput> => {
|
||||
return createDataContainer<UOutput>(
|
||||
this.options.factory(innerParams, {
|
||||
node,
|
||||
config: innerContext?.config ?? config,
|
||||
inputs: (innerContext?.inputs ?? inputs) as any, // TODO: Fix the way input values are overridden
|
||||
}),
|
||||
);
|
||||
},
|
||||
{
|
||||
node,
|
||||
config,
|
||||
// TODO: Figure out types once legacy data map input type is gone
|
||||
inputs: inputs as unknown as Expand<
|
||||
ResolvedExtensionInputs<TInputs>
|
||||
>,
|
||||
});
|
||||
}
|
||||
throw new Error('Either params or factory must be provided');
|
||||
inputs,
|
||||
},
|
||||
);
|
||||
},
|
||||
} as CreateExtensionOptions<TKind, string | undefined extends TNewNamespace ? TNamespace : TNewNamespace, string | undefined extends TNewName ? TName : TNewName, AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput, TInputs & TExtraInputs, TConfigSchema & TExtensionConfigSchema, UFactoryOutput>);
|
||||
}
|
||||
|
||||
public make<
|
||||
TNewNamespace extends string | undefined = undefined,
|
||||
TNewName extends string | undefined = undefined,
|
||||
>(args: {
|
||||
namespace?: TNewNamespace;
|
||||
name?: TNewName;
|
||||
attachTo?: { id: string; input: string };
|
||||
disabled?: boolean;
|
||||
params: TParams;
|
||||
}): ExtensionDefinition<
|
||||
{
|
||||
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
|
||||
},
|
||||
z.input<
|
||||
z.ZodObject<{
|
||||
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
|
||||
}>
|
||||
>
|
||||
> {
|
||||
return createExtension({
|
||||
kind: this.options.kind,
|
||||
namespace: args.namespace ?? this.options.namespace,
|
||||
name: args.name ?? this.options.name,
|
||||
attachTo: args.attachTo ?? this.options.attachTo,
|
||||
disabled: args.disabled ?? this.options.disabled,
|
||||
inputs: this.options.inputs,
|
||||
output: this.options.output,
|
||||
config: this.options.config,
|
||||
factory: ctx => this.options.factory(args.params, ctx),
|
||||
} as CreateExtensionOptions<TKind, string | undefined extends TNewNamespace ? TNamespace : TNewNamespace, string | undefined extends TNewName ? TName : TNewName, UOutput, TInputs, TConfigSchema, any>);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,6 @@ import { MemoryRouter, Link } from 'react-router-dom';
|
||||
import { RenderResult, render } from '@testing-library/react';
|
||||
import { createSpecializedApp } from '@backstage/frontend-app-api';
|
||||
import {
|
||||
ExtensionDataValue,
|
||||
AppNode,
|
||||
AppTree,
|
||||
Extension,
|
||||
@@ -169,9 +168,7 @@ export class ExtensionTester {
|
||||
: [...internal.output, coreExtensionData.routePath],
|
||||
factory: params => {
|
||||
const parentOutput = Array.from(
|
||||
internal.factory(params as any) as Iterable<
|
||||
ExtensionDataValue<any, any>
|
||||
>,
|
||||
internal.factory(params as any),
|
||||
).filter(val => val.id !== coreExtensionData.routePath.id);
|
||||
|
||||
return [...parentOutput, coreExtensionData.routePath('/')];
|
||||
|
||||
Reference in New Issue
Block a user