Merge pull request #26377 from backstage/blam/deprecate-namespace

NFS: Deprecate `namespace` from `createExtension` and `createExtensionBlueprint`
This commit is contained in:
Ben Lambert
2024-09-02 15:51:26 +02:00
committed by GitHub
15 changed files with 548 additions and 23 deletions
+34
View File
@@ -0,0 +1,34 @@
---
'@backstage/frontend-plugin-api': patch
'@backstage/plugin-app': patch
---
Deprecated the `namespace` option for `createExtensionBlueprint` and `createExtension`, these are no longer required and will default to the `pluginId` instead.
You can migrate some of your extensions that use `createExtensionOverrides` to using `createFrontendModule` instead and providing a `pluginId` there.
```ts
// Before
createExtensionOverrides({
extensions: [
createExtension({
name: 'my-extension',
namespace: 'my-namespace',
kind: 'test',
...
})
],
});
// After
createFrontendModule({
pluginId: 'my-namespace',
extensions: [
createExtension({
name: 'my-extension',
kind: 'test',
...
})
],
});
```
+218 -3
View File
@@ -477,6 +477,55 @@ export function createComponentRef<T extends {} = {}>(options: {
}): ComponentRef<T>;
// @public (undocumented)
export function createExtension<
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{
optional: boolean;
singleton: boolean;
}
>;
},
TConfigSchema extends {
[key: string]: (zImpl: typeof z) => z.ZodType;
},
UFactoryOutput extends ExtensionDataValue<any, any>,
const TKind extends string | undefined = undefined,
const TNamespace extends string | undefined = undefined,
const TName extends string | undefined = undefined,
>(
options: CreateExtensionOptions<
TKind,
undefined,
TName,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput
>,
): ExtensionDefinition<{
config: string extends keyof TConfigSchema
? {}
: {
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
};
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
output: UOutput;
inputs: TInputs;
kind: string | undefined extends TKind ? undefined : TKind;
namespace: string | undefined extends TNamespace ? undefined : TNamespace;
name: string | undefined extends TName ? undefined : TName;
}>;
// @public @deprecated (undocumented)
export function createExtension<
UOutput extends AnyExtensionDataRef,
TInputs extends {
@@ -526,6 +575,63 @@ export function createExtension<
}>;
// @public
export function createExtensionBlueprint<
TParams extends object,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{
optional: boolean;
singleton: boolean;
}
>;
},
TConfigSchema extends {
[key in string]: (zImpl: typeof z) => z.ZodType;
},
UFactoryOutput extends ExtensionDataValue<any, any>,
TKind extends string,
TNamespace extends undefined = undefined,
TName extends string | undefined = undefined,
TDataRefs extends {
[name in string]: AnyExtensionDataRef;
} = never,
>(
options: CreateExtensionBlueprintOptions<
TKind,
undefined,
TName,
TParams,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput,
TDataRefs
>,
): ExtensionBlueprint<{
kind: TKind;
namespace: undefined;
name: TName;
params: TParams;
output: UOutput;
inputs: string extends keyof TInputs ? {} : TInputs;
config: string extends keyof TConfigSchema
? {}
: {
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
};
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
dataRefs: TDataRefs;
}>;
// @public @deprecated (undocumented)
export function createExtensionBlueprint<
TParams extends object,
UOutput extends AnyExtensionDataRef,
@@ -857,6 +963,28 @@ export interface ExtensionBlueprint<
// (undocumented)
dataRefs: T['dataRefs'];
// (undocumented)
make<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
>(args: {
namespace?: undefined;
name?: TNewName;
attachTo?: {
id: string;
input: string;
};
disabled?: boolean;
params: T['params'];
}): ExtensionDefinition<{
kind: T['kind'];
namespace: undefined;
name: string | undefined extends TNewName ? T['name'] : TNewName;
config: T['config'];
configInput: T['configInput'];
output: T['output'];
inputs: T['inputs'];
}>;
// @deprecated (undocumented)
make<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
@@ -898,7 +1026,94 @@ export interface ExtensionBlueprint<
>;
},
>(args: {
namespace?: TNewNamespace;
namespace?: undefined;
name?: TNewName;
attachTo?: {
id: string;
input: string;
};
disabled?: boolean;
inputs?: TExtraInputs & {
[KName in keyof T['inputs']]?: `Error: Input '${KName &
string}' is already defined in parent definition`;
};
output?: Array<UNewOutput>;
config?: {
schema: TExtensionConfigSchema & {
[KName in keyof T['config']]?: `Error: Config key '${KName &
string}' is already defined in parent schema`;
};
};
factory(
originalFactory: (
params: T['params'],
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
},
) => ExtensionDataContainer<NonNullable<T['output']>>,
context: {
node: AppNode;
apis: ApiHolder;
config: T['config'] & {
[key in keyof TExtensionConfigSchema]: z.infer<
ReturnType<TExtensionConfigSchema[key]>
>;
};
inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;
},
): Iterable<UFactoryOutput> &
VerifyExtensionFactoryOutput<
AnyExtensionDataRef extends UNewOutput
? NonNullable<T['output']>
: UNewOutput,
UFactoryOutput
>;
}): ExtensionDefinition<{
config: (string extends keyof TExtensionConfigSchema
? {}
: {
[key in keyof TExtensionConfigSchema]: z.infer<
ReturnType<TExtensionConfigSchema[key]>
>;
}) &
T['config'];
configInput: (string extends keyof TExtensionConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TExtensionConfigSchema]: ReturnType<
TExtensionConfigSchema[key]
>;
}>
>) &
T['configInput'];
output: AnyExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;
inputs: T['inputs'] & TExtraInputs;
kind: T['kind'];
namespace: undefined;
name: string | undefined extends TNewName ? T['name'] : TNewName;
}>;
// @deprecated (undocumented)
makeWithOverrides<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
TExtensionConfigSchema extends {
[key in string]: (zImpl: typeof z) => z.ZodType;
},
UFactoryOutput extends ExtensionDataValue<any, any>,
UNewOutput extends AnyExtensionDataRef,
TExtraInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{
optional: boolean;
singleton: boolean;
}
>;
},
>(args: {
namespace: TNewNamespace;
name?: TNewName;
attachTo?: {
id: string;
@@ -1289,7 +1504,7 @@ export { googleAuthApiRef };
// @public (undocumented)
export const IconBundleBlueprint: ExtensionBlueprint<{
kind: 'icon-bundle';
namespace: 'app';
namespace: undefined;
name: undefined;
params: {
icons: {
@@ -1701,7 +1916,7 @@ export interface SubRouteRef<
// @public
export const ThemeBlueprint: ExtensionBlueprint<{
kind: 'theme';
namespace: 'app';
namespace: undefined;
name: undefined;
params: {
theme: AppTheme;
@@ -24,7 +24,6 @@ const iconsDataRef = createExtensionDataRef<{
/** @public */
export const IconBundleBlueprint = createExtensionBlueprint({
kind: 'icon-bundle',
namespace: 'app',
attachTo: { id: 'api:app/icons', input: 'icons' },
output: [iconsDataRef],
config: {
@@ -42,7 +42,7 @@ describe('ThemeBlueprint', () => {
"inputs": {},
"kind": "theme",
"name": "light",
"namespace": "app",
"namespace": undefined,
"output": [
[Function],
],
@@ -28,7 +28,6 @@ const themeDataRef = createExtensionDataRef<AppTheme>().with({
*/
export const ThemeBlueprint = createExtensionBlueprint({
kind: 'theme',
namespace: 'app',
attachTo: { id: 'api:app/app-theme', input: 'themes' },
output: [themeDataRef],
dataRefs: {
@@ -314,6 +314,94 @@ export function toInternalExtensionDefinition<
}
/** @public */
export function createExtension<
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },
UFactoryOutput extends ExtensionDataValue<any, any>,
const TKind extends string | undefined = undefined,
const TNamespace extends string | undefined = undefined,
const TName extends string | undefined = undefined,
>(
options: CreateExtensionOptions<
TKind,
undefined,
TName,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput
>,
): ExtensionDefinition<{
config: string extends keyof TConfigSchema
? {}
: {
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
};
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
output: UOutput;
inputs: TInputs;
kind: string | undefined extends TKind ? undefined : TKind;
namespace: string | undefined extends TNamespace ? undefined : TNamespace;
name: string | undefined extends TName ? undefined : TName;
}>;
/**
* @public
* @deprecated namespace is no longer required, you can safely remove this option and it will default to the `pluginId`. It will be removed in a future release.
*/
export function createExtension<
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },
UFactoryOutput extends ExtensionDataValue<any, any>,
const TKind extends string | undefined = undefined,
const TNamespace extends string | undefined = undefined,
const TName extends string | undefined = undefined,
>(
options: CreateExtensionOptions<
TKind,
TNamespace,
TName,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput
>,
): ExtensionDefinition<{
config: string extends keyof TConfigSchema
? {}
: {
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
};
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
output: UOutput;
inputs: TInputs;
kind: string | undefined extends TKind ? undefined : TKind;
namespace: string | undefined extends TNamespace ? undefined : TNamespace;
name: string | undefined extends TName ? undefined : TName;
}>;
export function createExtension<
UOutput extends AnyExtensionDataRef,
TInputs extends {
@@ -107,6 +107,25 @@ export interface ExtensionBlueprint<
> {
dataRefs: T['dataRefs'];
make<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
>(args: {
namespace?: undefined;
name?: TNewName;
attachTo?: { id: string; input: string };
disabled?: boolean;
params: T['params'];
}): ExtensionDefinition<{
kind: T['kind'];
namespace: undefined;
name: string | undefined extends TNewName ? T['name'] : TNewName;
config: T['config'];
configInput: T['configInput'];
output: T['output'];
inputs: T['inputs'];
}>;
/** @deprecated namespace is no longer required, you can safely remove this option and it will default to the `pluginId`. It will be removed in a future release. */
make<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
@@ -149,7 +168,88 @@ export interface ExtensionBlueprint<
>;
},
>(args: {
namespace?: TNewNamespace;
namespace?: undefined;
name?: TNewName;
attachTo?: { id: string; input: string };
disabled?: boolean;
inputs?: TExtraInputs & {
[KName in keyof T['inputs']]?: `Error: Input '${KName &
string}' is already defined in parent definition`;
};
output?: Array<UNewOutput>;
config?: {
schema: TExtensionConfigSchema & {
[KName in keyof T['config']]?: `Error: Config key '${KName &
string}' is already defined in parent schema`;
};
};
factory(
originalFactory: (
params: T['params'],
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
},
) => ExtensionDataContainer<NonNullable<T['output']>>,
context: {
node: AppNode;
apis: ApiHolder;
config: T['config'] & {
[key in keyof TExtensionConfigSchema]: z.infer<
ReturnType<TExtensionConfigSchema[key]>
>;
};
inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;
},
): Iterable<UFactoryOutput> &
VerifyExtensionFactoryOutput<
AnyExtensionDataRef extends UNewOutput
? NonNullable<T['output']>
: UNewOutput,
UFactoryOutput
>;
}): ExtensionDefinition<{
config: (string extends keyof TExtensionConfigSchema
? {}
: {
[key in keyof TExtensionConfigSchema]: z.infer<
ReturnType<TExtensionConfigSchema[key]>
>;
}) &
T['config'];
configInput: (string extends keyof TExtensionConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TExtensionConfigSchema]: ReturnType<
TExtensionConfigSchema[key]
>;
}>
>) &
T['configInput'];
output: AnyExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;
inputs: T['inputs'] & TExtraInputs;
kind: T['kind'];
namespace: undefined;
name: string | undefined extends TNewName ? T['name'] : TNewName;
}>;
/** @deprecated namespace is no longer required, you can safely remove this option and it will default to the `pluginId`. It will be removed in a future release. */
makeWithOverrides<
TNewNamespace extends string | undefined,
TNewName extends string | undefined,
TExtensionConfigSchema extends {
[key in string]: (zImpl: typeof z) => z.ZodType;
},
UFactoryOutput extends ExtensionDataValue<any, any>,
UNewOutput extends AnyExtensionDataRef,
TExtraInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
>(args: {
namespace: TNewNamespace;
name?: TNewName;
attachTo?: { id: string; input: string };
disabled?: boolean;
@@ -224,6 +324,102 @@ export interface ExtensionBlueprint<
*
* @public
*/
export function createExtensionBlueprint<
TParams extends object,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },
UFactoryOutput extends ExtensionDataValue<any, any>,
TKind extends string,
TNamespace extends undefined = undefined,
TName extends string | undefined = undefined,
TDataRefs extends { [name in string]: AnyExtensionDataRef } = never,
>(
options: CreateExtensionBlueprintOptions<
TKind,
undefined,
TName,
TParams,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput,
TDataRefs
>,
): ExtensionBlueprint<{
kind: TKind;
namespace: undefined;
name: TName;
params: TParams;
output: UOutput;
inputs: string extends keyof TInputs ? {} : TInputs;
config: string extends keyof TConfigSchema
? {}
: { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
dataRefs: TDataRefs;
}>;
/**
* @public
* @deprecated the namespace is no longer required, you can safely remove this option and it will default to the `pluginId`. It will be removed in a future release.
*/
export function createExtensionBlueprint<
TParams extends object,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },
UFactoryOutput extends ExtensionDataValue<any, any>,
TKind extends string,
TNamespace extends string | undefined = undefined,
TName extends string | undefined = undefined,
TDataRefs extends { [name in string]: AnyExtensionDataRef } = never,
>(
options: CreateExtensionBlueprintOptions<
TKind,
TNamespace,
TName,
TParams,
UOutput,
TInputs,
TConfigSchema,
UFactoryOutput,
TDataRefs
>,
): ExtensionBlueprint<{
kind: TKind;
namespace: TNamespace;
name: TName;
params: TParams;
output: UOutput;
inputs: string extends keyof TInputs ? {} : TInputs;
config: string extends keyof TConfigSchema
? {}
: { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };
configInput: string extends keyof TConfigSchema
? {}
: z.input<
z.ZodObject<{
[key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;
}>
>;
dataRefs: TDataRefs;
}>;
export function createExtensionBlueprint<
TParams extends object,
UOutput extends AnyExtensionDataRef,
@@ -149,6 +149,7 @@ export function resolveExtensionDefinition<
override: _skip2,
...rest
} = internalDefinition;
const namespace = internalDefinition.namespace ?? context?.namespace;
const namePart =
+9 -9
View File
@@ -71,7 +71,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: undefined;
namespace: 'app';
namespace: undefined;
name: undefined;
}>;
'api:app/app-language': ExtensionDefinition<{
@@ -112,7 +112,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: undefined;
namespace: 'app';
namespace: undefined;
name: 'layout';
}>;
'app/nav': ExtensionDefinition<{
@@ -155,7 +155,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: undefined;
namespace: 'app';
namespace: undefined;
name: 'nav';
}>;
'app/root': ExtensionDefinition<{
@@ -220,7 +220,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: undefined;
namespace: 'app';
namespace: undefined;
name: 'root';
}>;
'app/routes': ExtensionDefinition<{
@@ -249,7 +249,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: undefined;
namespace: 'app';
namespace: undefined;
name: 'routes';
}>;
'api:app/app-theme': ExtensionDefinition<{
@@ -275,7 +275,7 @@ const appPlugin: FrontendPlugin<
}>;
'theme:app/light': ExtensionDefinition<{
kind: 'theme';
namespace: 'app';
namespace: undefined;
name: 'light';
config: {};
configInput: {};
@@ -284,7 +284,7 @@ const appPlugin: FrontendPlugin<
}>;
'theme:app/dark': ExtensionDefinition<{
kind: 'theme';
namespace: 'app';
namespace: undefined;
name: 'dark';
config: {};
configInput: {};
@@ -393,7 +393,7 @@ const appPlugin: FrontendPlugin<
}>;
'app-root-element:app/oauth-request-dialog': ExtensionDefinition<{
kind: 'app-root-element';
namespace: 'app';
namespace: undefined;
name: 'oauth-request-dialog';
config: {};
configInput: {};
@@ -436,7 +436,7 @@ const appPlugin: FrontendPlugin<
>;
};
kind: 'app-root-element';
namespace: 'app';
namespace: undefined;
name: 'alert-display';
}>;
'api:app/discovery': ExtensionDefinition<{
-1
View File
@@ -27,7 +27,6 @@ import { ApiProvider } from '../../../../packages/core-app-api/src';
import { AppThemeProvider } from '../../../../packages/core-app-api/src/app/AppThemeProvider';
export const App = createExtension({
namespace: 'app',
attachTo: { id: 'root', input: 'app' },
inputs: {
root: createExtensionInput([coreExtensionData.reactElement], {
-1
View File
@@ -23,7 +23,6 @@ import {
import { SidebarPage } from '@backstage/core-components';
export const AppLayout = createExtension({
namespace: 'app',
name: 'layout',
attachTo: { id: 'app/root', input: 'children' },
inputs: {
-1
View File
@@ -82,7 +82,6 @@ const SidebarNavItem = (
};
export const AppNav = createExtension({
namespace: 'app',
name: 'nav',
attachTo: { id: 'app/layout', input: 'nav' },
inputs: {
-1
View File
@@ -53,7 +53,6 @@ import { RouteTracker } from '../../../../packages/frontend-app-api/src/routing/
import { getBasePath } from '../../../../packages/frontend-app-api/src/routing/getBasePath';
export const AppRoot = createExtension({
namespace: 'app',
name: 'root',
attachTo: { id: 'app', input: 'root' },
inputs: {
-1
View File
@@ -25,7 +25,6 @@ import {
import { useRoutes } from 'react-router-dom';
export const AppRoutes = createExtension({
namespace: 'app',
name: 'routes',
attachTo: { id: 'app/layout', input: 'content' },
inputs: {
-2
View File
@@ -19,7 +19,6 @@ import { AppRootElementBlueprint } from '@backstage/frontend-plugin-api';
import React from 'react';
export const oauthRequestDialogAppRootElement = AppRootElementBlueprint.make({
namespace: 'app',
name: 'oauth-request-dialog',
params: {
element: <OAuthRequestDialog />,
@@ -28,7 +27,6 @@ export const oauthRequestDialogAppRootElement = AppRootElementBlueprint.make({
export const alertDisplayAppRootElement =
AppRootElementBlueprint.makeWithOverrides({
namespace: 'app',
name: 'alert-display',
config: {
schema: {