Merge pull request #30673 from backstage/rugvip/params

frontend-plugin-api: advanced blueprint param types
This commit is contained in:
Patrik Oldsberg
2025-07-29 13:50:13 +02:00
committed by GitHub
58 changed files with 1723 additions and 453 deletions
+20
View File
@@ -0,0 +1,20 @@
---
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/frontend-app-api': patch
'@backstage/core-compat-api': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-notifications': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-devtools': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-signals': patch
'@backstage/plugin-search': patch
'@backstage/plugin-home': patch
'@backstage/plugin-app': patch
---
Internal update to use the new variant of `ApiBlueprint`.
+40
View File
@@ -0,0 +1,40 @@
---
'@backstage/frontend-plugin-api': minor
---
**BREAKING**: The `ApiBlueprint` has been updated to use the new advanced type parameters through the new `defineParams` blueprint option. This is an immediate breaking change that requires all existing usages of `ApiBlueprint` to switch to the new callback format. Existing extensions created with the old format are still compatible with the latest version of the plugin API however, meaning that this does not break existing plugins.
To update existing usages of `ApiBlueprint`, you remove the outer level of the `params` object and replace `createApiFactory(...)` with `define => define(...)`.
For example, the following old usage:
```ts
ApiBlueprint.make({
name: 'error',
params: {
factory: createApiFactory({
api: errorApiRef,
deps: { alertApi: alertApiRef },
factory: ({ alertApi }) => {
return ...;
},
})
},
})
```
is migrated to the following:
```ts
ApiBlueprint.make({
name: 'error',
params: define =>
define({
api: errorApiRef,
deps: { alertApi: alertApiRef },
factory: ({ alertApi }) => {
return ...;
},
}),
})
```
+42
View File
@@ -0,0 +1,42 @@
---
'@backstage/frontend-plugin-api': minor
---
Added support for advanced parameter types in extension blueprints. The primary purpose of this is to allow extension authors to use type inference in the definition of the blueprint parameters. This often removes the need for extra imports and improves discoverability of blueprint parameters.
This feature is introduced through the new `defineParams` option of `createExtensionBlueprint`, along with accompanying `createExtensionBlueprintParams` function to help implement the new format.
The following is an example of how to create an extension blueprint that uses the new option:
```ts
const ExampleBlueprint = createExtensionBlueprint({
kind: 'example',
attachTo: { id: 'example', input: 'example' },
output: [exampleComponentDataRef, exampleFetcherDataRef],
defineParams<T>(params: {
component(props: ExampleProps<T>): JSX.Element | null;
fetcher(options: FetchOptions): Promise<FetchResult<T>>;
}) {
// The returned params must be wrapped with `createExtensionBlueprintParams`
return createExtensionBlueprintParams(params);
},
*factory(params) {
// These params are now inferred
yield exampleComponentDataRef(params.component);
yield exampleFetcherDataRef(params.fetcher);
},
});
```
Usage of the above example looks as follows:
```ts
const example = ExampleBlueprint.make({
params: define => define({
component: ...,
fetcher: ...,
}),
});
```
This `define => define(<params>)` is also known as the "callback syntax" and is required if a blueprint is created with the new `defineParams` option. The callback syntax can also optionally be used for other blueprints too, which means that it is not a breaking change to remove the `defineParams` option, as long as the external parameter types remain compatible.
@@ -60,6 +60,39 @@ When using `makeWithOverrides`, we no longer pass the blueprint parameters direc
Apart from the addition of the blueprint parameters of the first argument to the original factory function, the `makeWithOverrides` method works the same way as [extension overrides](./25-extension-overrides.md). All the same options and rules apply, including the ability to define additional inputs, override outputs, and so on. We therefore defer to the [extension overrides](./25-extension-overrides.md) documentation for more information on how to use the `makeWithOverrides` method.
### Creating an extension from a blueprint with advanced parameter types
Some blueprints may be defined with something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way that you pass the parameters look a little bit different. Rather than passing the parameters directly, they are instead passed as a callback function of the form `define => define(<params>)`.
An example of a blueprint that uses advanced parameter types is the `ApiBlueprint` blueprint. Using it to create a simple implementation for the `AlertApi` might look like this:
```ts
const alertApiBlueprint = ApiBlueprint.make({
params: define =>
define({
api: alertApiRef,
deps: {},
factory: () => new MyAlertApi(),
}),
});
```
This also works with `makeWithOverrides`, where the define callback is passed as the first argument to the original factory:
```ts
const alertApiBlueprint = ApiBlueprint.makeWithOverrides({
factory(originalFactory, { config }) {
return originalFactory(define =>
define({
api: alertApiRef,
deps: {},
factory: () => new MyAlertApi(config),
}),
);
},
});
```
## Creating an extension blueprint
To create a new extension blueprint, you use the `createExtensionBlueprint` function. At the surface it is very similar to `createExtension`, but with a few key differences. Firstly you must provide a `kind` option, which will be the kind of all extensions created with the blueprint. See the [naming patterns section](./50-naming-patterns.md) for more information about how to select a good extension kind. Secondly, the `factory` function has a new signature where the first parameter is the blueprint parameters, and the second is the factory context. And finally, rather than returning an extension, `createExtensionBlueprint` returns a blueprint object with the `make` method and friends, which is used as is described above.
@@ -99,6 +132,41 @@ This is of course a quite bare-bones example blueprint, but still a very real ex
Most of the options provided to `createExtensionBlueprint` can be overridden when using `makeWithOverrides` to create an extension from the blueprint. These overrides work the same way as [extension overrides](./25-extension-overrides.md), and we defer to that documentation for more information on how overrides work.
### Creating an extension blueprint with advanced parameter types
In some cases you may want to use inferred type parameters in the definition of the blueprint parameters. For this you need to use something known as "advanced parameter types". This is a feature that enables type inference and transform of the blueprint parameters, and the way you define the parameter type is a bit different. Rather than defining the type of the parameters as part of the factory function, you instead provide a separate `defineParams` options. This is a function that takes the parameters as a single argument, and must then return the parameters wrapped with the `createExtensionBlueprintParams` function.
The following is an example of how one might define a blueprint where the parameters make use of inferred types:
```ts
export interface MyWidgetBlueprintParams<T> {
defaultOptions: T;
elementFactory(options: T): JSX.Element;
}
export const MyWidgetBlueprint = createExtensionBlueprint({
kind: 'my-widget',
attachTo: { id: 'page:my-plugin', input: 'widgets' },
output: [coreExtensionData.reactElement],
defineParams<T>(params: MyWidgetBlueprintParams<T>) {
return createExtensionBlueprintParams(params);
},
// Note that we no longer define the parameters type here, they are inferred from the defineParams function
factory(params) {
return [
coreExtensionData.reactElement(
<MyWidgetRenderer
defaultOptions={params.defaultOptions}
elementFactory={params.elementFactory}
/>,
),
];
},
});
```
If you happen to ask yourself, "why can't I just define type parameters on the factory function instead?", this is a limitation in the TypeScript type system. We could technically support that in the blueprint definition, but there would be no way for that logic to be carried forward to the blueprint `.make` and `.makeWithOverrides` methods.
### Blueprint-specific extension data references
In some cases you may want to define and provide [extension data reference](./20-extensions.md#extension-data-references) that are specific to your blueprint. In the above example we might want to forward the `title` as data for example, rather than encapsulating it into the `MyWidgetContainer` component. This gives the parent extension more flexibility in the rendering for our example widget extensions.
@@ -199,13 +199,12 @@ import { ApiBlueprint } from '@backstage/frontend-plugin-api';
const scmIntegrationsApi = ApiBlueprint.make({
name: 'scm-integrations',
params: {
factory: createApiFactory({
params: define =>
define({
api: scmIntegrationsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
}),
},
});
```
@@ -154,19 +154,18 @@ export function ExamplePage() {
```
```tsx title="in src/plugin.ts - Registering a factory for our API"
import { createApiFactory, ApiBlueprint } from '@backstage/frontend-plugin-api';
import { ApiBlueprint } from '@backstage/frontend-plugin-api';
import { exampleApiRef, DefaultExampleApi } from './api';
// highlight-add-start
const exampleApi = ApiBlueprint.make({
name: 'example',
params: {
factory: createApiFactory({
params: define =>
define({
api: exampleApiRef,
deps: {},
factory: () => new DefaultExampleApi(),
}),
},
});
// highlight-add-end
@@ -205,22 +205,17 @@ The major changes we'll make are
The end result, after simplifying imports and cleaning up a bit, might look like this:
```tsx title="in @internal/plugin-example"
import {
storageApiRef,
createApiFactory,
ApiBlueprint,
} from '@backstage/frontend-plugin-api';
import { storageApiRef, ApiBlueprint } from '@backstage/frontend-plugin-api';
import { workApiRef } from '@internal/plugin-example-react';
import { WorkImpl } from './WorkImpl';
const exampleWorkApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: workApiRef,
deps: { storageApi: storageApiRef },
factory: ({ storageApi }) => new WorkImpl({ storageApi }),
}),
},
});
```
@@ -45,7 +45,6 @@ The plugin itself now wants to provide this API and its default implementation,
```tsx title="in @internal/plugin-example"
import {
ApiBlueprint,
createApiFactory,
createFrontendPlugin,
storageApiRef,
StorageApi,
@@ -63,15 +62,14 @@ class WorkImpl implements WorkApi {
const workApi = ApiBlueprint.make({
name: 'work',
params: {
factory: createApiFactory({
params: define =>
define({
api: workApiRef,
deps: { storageApi: storageApiRef },
factory: ({ storageApi }) => {
return new WorkImpl({ storageApi });
},
}),
},
});
/**
@@ -46,14 +46,13 @@ Your utility APIs can depend on other utility APIs in their factories. You do th
import {
configApiRef,
ApiBlueprint,
createApiFactory,
discoveryApiRef,
} from '@backstage/frontend-plugin-api';
import { MyApiImpl } from './MyApiImpl';
const myApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: myApiRef,
deps: {
configApi: configApiRef,
@@ -63,7 +62,6 @@ const myApi = ApiBlueprint.make({
return new MyApiImpl({ configApi, discoveryApi });
},
}),
},
});
```
@@ -310,7 +310,7 @@ export function collectLegacyRoutes(
...Array.from(plugin.getApis()).map(factory =>
ApiBlueprint.make({
name: factory.api.id,
params: { factory },
params: define => define(factory),
}),
),
],
@@ -232,31 +232,32 @@ describe('convertLegacyApp', () => {
const catalogOverride = catalogPlugin.withOverrides({
extensions: [
catalogPlugin.getExtension('api:catalog').override({
params: {
factory: createApiFactory(
catalogApiRef,
catalogApiMock({
entities: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'test',
metadata: {
name: 'x',
params: define =>
define({
api: catalogApiRef,
deps: {},
factory: () =>
catalogApiMock({
entities: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'test',
metadata: {
name: 'x',
},
spec: {},
},
spec: {},
},
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'other',
metadata: {
name: 'x',
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'other',
metadata: {
name: 'x',
},
spec: {},
},
spec: {},
},
],
}),
),
},
],
}),
}),
}),
],
});
@@ -74,7 +74,10 @@ export function convertLegacyAppOptions(
new Map(allApis.map(api => [api.api.id, api])).values(),
);
const extensions: ExtensionDefinition[] = deduplicatedApis.map(factory =>
ApiBlueprint.make({ name: factory.api.id, params: { factory } }),
ApiBlueprint.make({
name: factory.api.id,
params: define => define(factory),
}),
);
if (icons) {
@@ -29,7 +29,10 @@ export function convertLegacyPlugin(
options: { extensions: ExtensionDefinition[] },
): NewBackstagePlugin {
const apiExtensions = Array.from(legacyPlugin.getApis()).map(factory =>
ApiBlueprint.make({ name: factory.api.id, params: { factory } }),
ApiBlueprint.make({
name: factory.api.id,
params: define => define(factory),
}),
);
return createFrontendPlugin({
pluginId: legacyPlugin.getId(),
@@ -31,11 +31,7 @@ import {
import { screen, render } from '@testing-library/react';
import { createSpecializedApp } from './createSpecializedApp';
import { mockApis, TestApiRegistry } from '@backstage/test-utils';
import {
configApiRef,
createApiFactory,
featureFlagsApiRef,
} from '@backstage/core-plugin-api';
import { configApiRef, featureFlagsApiRef } from '@backstage/core-plugin-api';
import { MemoryRouter } from 'react-router-dom';
import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
import { Fragment } from 'react';
@@ -148,16 +144,20 @@ describe('createSpecializedApp', () => {
],
}),
ApiBlueprint.make({
params: {
factory: createApiFactory(featureFlagsApiRef, {
registerFlag(flag) {
flags.push(flag);
},
getRegisteredFlags() {
return flags;
},
} as typeof featureFlagsApiRef.T),
},
params: define =>
define({
api: featureFlagsApiRef,
deps: {},
factory: () =>
({
registerFlag(flag) {
flags.push(flag);
},
getRegisteredFlags() {
return flags;
},
} as typeof featureFlagsApiRef.T),
}),
}),
],
}),
@@ -253,15 +253,14 @@ describe('createSpecializedApp', () => {
pluginId: 'first',
extensions: [
ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: analyticsApiRef,
deps: {},
factory: () => {
throw new Error('BROKEN');
},
}),
},
}),
],
}),
@@ -295,13 +294,12 @@ describe('createSpecializedApp', () => {
},
}),
ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: analyticsApiRef,
deps: {},
factory: mockAnalyticsApi,
}),
},
}),
],
}),
+67 -15
View File
@@ -179,9 +179,13 @@ export type AnyRoutes = {
export const ApiBlueprint: ExtensionBlueprint<{
kind: 'api';
name: undefined;
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
output: ConfigurableExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>;
inputs: {};
config: {};
@@ -519,7 +523,7 @@ export function createExtension<
// @public
export function createExtensionBlueprint<
TParams extends object,
TParams extends object | ExtensionBlueprintParamsDefiner,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
@@ -575,7 +579,7 @@ export function createExtensionBlueprint<
export type CreateExtensionBlueprintOptions<
TKind extends string,
TName extends string | undefined,
TParams,
TParams extends object | ExtensionBlueprintParamsDefiner,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
@@ -603,8 +607,13 @@ export type CreateExtensionBlueprintOptions<
config?: {
schema: TConfigSchema;
};
defineParams?: TParams extends ExtensionBlueprintParamsDefiner
? TParams
: 'The defineParams option must be a function if provided, see the docs for details';
factory(
params: TParams,
params: TParams extends ExtensionBlueprintParamsDefiner
? ReturnType<TParams>['T']
: TParams,
context: {
node: AppNode;
apis: ApiHolder;
@@ -617,6 +626,11 @@ export type CreateExtensionBlueprintOptions<
dataRefs?: TDataRefs;
} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;
// @public
export function createExtensionBlueprintParams<T extends object = object>(
params: T,
): ExtensionBlueprintParams<T>;
// @public (undocumented)
export function createExtensionDataRef<TData>(): {
with<TId extends string>(options: {
@@ -911,11 +925,18 @@ export interface ExtensionBlueprint<
// (undocumented)
dataRefs: T['dataRefs'];
// (undocumented)
make<TNewName extends string | undefined>(args: {
make<
TNewName extends string | undefined,
TParamsInput extends AnyParamsInput_2<NonNullable<T['params']>>,
>(args: {
name?: TNewName;
attachTo?: ExtensionAttachToSpec;
disabled?: boolean;
params: T['params'];
params: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: define => define(<params>) })`'
: TParamsInput;
}): ExtensionDefinition<{
kind: T['kind'];
name: string | undefined extends TNewName ? T['name'] : TNewName;
@@ -957,8 +978,14 @@ export interface ExtensionBlueprint<
};
};
factory(
originalFactory: (
params: T['params'],
originalFactory: <
TParamsInput extends AnyParamsInput_2<NonNullable<T['params']>>,
>(
params: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: TParamsInput,
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
@@ -1012,7 +1039,7 @@ export interface ExtensionBlueprint<
export type ExtensionBlueprintParameters = {
kind: string;
name?: string;
params?: object;
params?: object | ExtensionBlueprintParamsDefiner;
configInput?: {
[K in string]: any;
};
@@ -1034,6 +1061,18 @@ export type ExtensionBlueprintParameters = {
};
};
// @public
export type ExtensionBlueprintParams<T extends object = object> = {
$$type: '@backstage/BlueprintParams';
T: T;
};
// @public
export type ExtensionBlueprintParamsDefiner<
TParams extends object = object,
TInput = any,
> = (params: TInput) => ExtensionBlueprintParams<TParams>;
// @public (undocumented)
export function ExtensionBoundary(props: ExtensionBoundaryProps): JSX_2.Element;
@@ -1130,6 +1169,7 @@ export type ExtensionDefinition<
}
>;
},
TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,
>(
args: Expand<
{
@@ -1147,7 +1187,11 @@ export type ExtensionDefinition<
};
};
factory?(
originalFactory: (
originalFactory: <
TFactoryParamsReturn extends AnyParamsInput<
NonNullable<T['params']>
>,
>(
context?: Expand<
{
config?: T['config'];
@@ -1155,7 +1199,11 @@ export type ExtensionDefinition<
} & ([T['params']] extends [never]
? {}
: {
params?: Partial<T['params']>;
params?: TFactoryParamsReturn extends ExtensionBlueprintParamsDefiner
? TFactoryParamsReturn
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: Partial<T['params']>;
})
>,
) => ExtensionDataContainer<NonNullable<T['output']>>,
@@ -1173,7 +1221,11 @@ export type ExtensionDefinition<
} & ([T['params']] extends [never]
? {}
: {
params?: Partial<T['params']>;
params?: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: Partial<T['params']>;
})
> &
VerifyExtensionFactoryOutput<
@@ -1223,7 +1275,7 @@ export type ExtensionDefinitionParameters = {
}
>;
};
params?: object;
params?: object | ExtensionBlueprintParamsDefiner;
};
// @public (undocumented)
@@ -16,21 +16,19 @@
import { createExtensionInput } from '../wiring';
import { ApiBlueprint } from './ApiBlueprint';
import { createApiFactory, createApiRef } from '@backstage/core-plugin-api';
import { createApiRef } from '@backstage/core-plugin-api';
describe('ApiBlueprint', () => {
it('should create an extension with sensible defaults', () => {
const api = createApiRef<{ foo: string }>({ id: 'test' });
const factory = createApiFactory({
api,
deps: {},
factory: () => ({ foo: 'bar' }),
});
const extension = ApiBlueprint.make({
params: {
factory,
},
params: define =>
define({
api,
deps: {},
factory: () => ({ foo: 'bar' }),
}),
name: 'test',
});
@@ -58,6 +56,97 @@ describe('ApiBlueprint', () => {
`);
});
it('should properly type the API factory', () => {
const fooApi = createApiRef<{ foo: string }>({ id: 'foo' });
const barApi = createApiRef<{ bar: string }>({ id: 'bar' });
expect('test').not.toBe('failing without assertions');
ApiBlueprint.make({
params: define =>
define({ api: fooApi, deps: {}, factory: () => ({ foo: 'foo' }) }),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: {},
// @ts-expect-error missing property
factory: () => ({}),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: {},
// @ts-expect-error wrong property
factory: () => ({
bar: 'bar',
}),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: {},
factory: () => ({
// @ts-expect-error wrong type
foo: 1,
}),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: { bar: barApi },
factory: ({ bar }) => ({ foo: bar.bar }),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: { bar: barApi },
factory: ({ bar }) => ({
// @ts-expect-error not an available property
foo: bar.foo,
}),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: { bar: barApi },
factory: ({ bar }) => ({
// @ts-expect-error not an available property
foo: bar.foo,
}),
}),
});
ApiBlueprint.make({
params: define =>
define({
api: fooApi,
deps: {},
factory: ({ bar }) => ({
// @ts-expect-error unknown dep
foo: bar.bar,
}),
}),
});
});
it('should create an extension with custom factory', () => {
const api = createApiRef<{ foo: string }>({ id: 'test' });
const factory = jest.fn(() => ({ foo: 'bar' }));
@@ -73,13 +162,7 @@ describe('ApiBlueprint', () => {
},
name: api.id,
factory(originalFactory, { config: _config, inputs: _inputs }) {
return originalFactory({
factory: createApiFactory({
api,
deps: {},
factory,
}),
});
return originalFactory(define => define({ api, deps: {}, factory }));
},
});
@@ -14,8 +14,9 @@
* limitations under the License.
*/
import { AnyApiFactory, ApiFactory } from '../apis/system';
import { createExtensionBlueprint, createExtensionDataRef } from '../wiring';
import { AnyApiFactory } from '@backstage/core-plugin-api';
import { createExtensionBlueprintParams } from '../wiring/createExtensionBlueprint';
const factoryDataRef = createExtensionDataRef<AnyApiFactory>().with({
id: 'core.api.factory',
@@ -33,7 +34,14 @@ export const ApiBlueprint = createExtensionBlueprint({
dataRefs: {
factory: factoryDataRef,
},
*factory(params: { factory: AnyApiFactory }) {
yield factoryDataRef(params.factory);
defineParams: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => createExtensionBlueprintParams(params as AnyApiFactory),
*factory(params) {
yield factoryDataRef(params);
},
});
@@ -30,6 +30,7 @@ import { z } from 'zod';
import { createSchemaFromZod } from '../schema/createSchemaFromZod';
import { OpaqueExtensionDefinition } from '@internal/frontend';
import { ExtensionDataContainer } from './types';
import { ExtensionBlueprintParamsDefiner } from './createExtensionBlueprint';
/**
* This symbol is used to pass parameter overrides from the extension override to the blueprint factory
@@ -161,9 +162,23 @@ export type ExtensionDefinitionParameters = {
{ optional: boolean; singleton: boolean }
>;
};
params?: object;
params?: object | ExtensionBlueprintParamsDefiner;
};
/**
* Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined.
* It can't be exported because it breaks API reports.
* @ignore
*/
type AnyParamsInput<TParams extends object | ExtensionBlueprintParamsDefiner> =
TParams extends ExtensionBlueprintParamsDefiner<infer IParams>
? IParams | ((define: TParams) => ReturnType<TParams>)
:
| TParams
| ((
define: ExtensionBlueprintParamsDefiner<TParams, TParams>,
) => ReturnType<ExtensionBlueprintParamsDefiner<TParams, TParams>>);
/** @public */
export type ExtensionDefinition<
T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,
@@ -183,6 +198,7 @@ export type ExtensionDefinition<
{ optional: boolean; singleton: boolean }
>;
},
TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,
>(
args: Expand<
{
@@ -200,14 +216,24 @@ export type ExtensionDefinition<
};
};
factory?(
originalFactory: (
originalFactory: <
TFactoryParamsReturn extends AnyParamsInput<
NonNullable<T['params']>
>,
>(
context?: Expand<
{
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
} & ([T['params']] extends [never]
? {}
: { params?: Partial<T['params']> })
: {
params?: TFactoryParamsReturn extends ExtensionBlueprintParamsDefiner
? TFactoryParamsReturn
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: Partial<T['params']>;
})
>,
) => ExtensionDataContainer<NonNullable<T['output']>>,
context: {
@@ -223,7 +249,13 @@ export type ExtensionDefinition<
): Iterable<UFactoryOutput>;
} & ([T['params']] extends [never]
? {}
: { params?: Partial<T['params']> })
: {
params?: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: Partial<T['params']>;
})
> &
VerifyExtensionFactoryOutput<
AnyExtensionDataRef extends UNewOutput
@@ -15,7 +15,11 @@
*/
import { coreExtensionData } from './coreExtensionData';
import { createExtensionBlueprint } from './createExtensionBlueprint';
import {
createExtensionBlueprint,
createExtensionBlueprintParams,
ExtensionBlueprintParams,
} from './createExtensionBlueprint';
import {
createExtensionTester,
renderInTestApp,
@@ -876,6 +880,21 @@ describe('createExtensionBlueprint', () => {
test2: 'orig-2',
});
const extensionDef = blueprint.make({
// Using define is optional in this case
params: define =>
define({
test1: 'orig-1',
test2: 'orig-2',
}),
});
expect(getOutputs(extensionDef)).toEqual({
test1: 'orig-1',
test2: 'orig-2',
});
// Plain override
expect(
getOutputs(
extension.override({
@@ -896,6 +915,8 @@ describe('createExtensionBlueprint', () => {
extension.override({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
}),
),
@@ -904,6 +925,58 @@ describe('createExtensionBlueprint', () => {
test2: 'override-2',
});
// Partial override with original define
expect(
getOutputs(
extensionDef.override({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
}),
),
).toEqual({
test1: 'orig-1',
test2: 'override-2',
});
// Override with define
expect(
getOutputs(
extension.override({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
// Override with define with original define
expect(
getOutputs(
extensionDef.override({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
expect(
getOutputs(
extension.override({
@@ -930,6 +1003,8 @@ describe('createExtensionBlueprint', () => {
return origFactory({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
});
},
@@ -940,6 +1015,70 @@ describe('createExtensionBlueprint', () => {
test2: 'override-2',
});
// Partial override via factory with original define
expect(
getOutputs(
extensionDef.override({
factory(origFactory) {
return origFactory({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
});
},
}),
),
).toEqual({
test1: 'orig-1',
test2: 'override-2',
});
// Override via factory with define
expect(
getOutputs(
extension.override({
factory(origFactory) {
return origFactory({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
});
},
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
// Override via factory with define with original define
expect(
getOutputs(
extensionDef.override({
factory(origFactory) {
return origFactory({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
});
},
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
expect(() =>
getOutputs(
extension.override({
@@ -991,6 +1130,21 @@ describe('createExtensionBlueprint', () => {
test2: 'orig-2',
});
const extensionDef = blueprint.make({
// Using define is optional in this case
params: define =>
define({
test1: 'orig-1',
test2: 'orig-2',
}),
});
expect(getOutputs(extensionDef)).toEqual({
test1: 'orig-1',
test2: 'orig-2',
});
// Plain override
expect(
getOutputs(
extension.override({
@@ -1011,6 +1165,8 @@ describe('createExtensionBlueprint', () => {
extension.override({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
}),
),
@@ -1019,6 +1175,59 @@ describe('createExtensionBlueprint', () => {
test2: 'override-2',
});
// Partial override with original define
expect(
getOutputs(
extensionDef.override({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
}),
),
).toEqual({
test1: 'orig-1',
test2: 'override-2',
});
// Override with define
expect(
getOutputs(
extension.override({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
// Override with define with original define
expect(
getOutputs(
extensionDef.override({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
// Override via factory
expect(
getOutputs(
extension.override({
@@ -1045,6 +1254,8 @@ describe('createExtensionBlueprint', () => {
return origFactory({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
});
},
@@ -1055,6 +1266,70 @@ describe('createExtensionBlueprint', () => {
test2: 'override-2',
});
// Partial override via factory with original define
expect(
getOutputs(
extensionDef.override({
factory(origFactory) {
return origFactory({
params: {
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
},
});
},
}),
),
).toEqual({
test1: 'orig-1',
test2: 'override-2',
});
// Override via factory with define
expect(
getOutputs(
extension.override({
factory(origFactory) {
return origFactory({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
});
},
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
// Override via factory with define with original define
expect(
getOutputs(
extensionDef.override({
factory(origFactory) {
return origFactory({
params: define =>
define({
test1: 'override-1',
test2: 'override-2',
// @ts-expect-error
test3: 'nonexistent',
}),
});
},
}),
),
).toEqual({
test1: 'override-1',
test2: 'override-2',
});
expect(() =>
getOutputs(
extension.override({
@@ -1069,4 +1344,272 @@ describe('createExtensionBlueprint', () => {
),
).toThrow('Refused to override params and factory at the same time');
});
describe('with advanced parameter types', () => {
const testDataRef = createExtensionDataRef<string>().with({ id: 'test' });
const TestExtensionBlueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef],
defineParams<const A extends string, const B extends A>(params: {
a: A;
b: B;
}) {
return createExtensionBlueprintParams(params);
},
factory(params) {
return [testDataRef(`${params.a} ${params.b}`)];
},
});
it('should allow creation of extension blueprints', () => {
TestExtensionBlueprint.make({
// @ts-expect-error not using define func
params: {
a: 'x',
b: 'y',
},
});
TestExtensionBlueprint.make({
params: define =>
define({
a: 'x',
// @ts-expect-error b doesn't match a
b: 'y',
}),
});
TestExtensionBlueprint.make({
params: define =>
define({
a: 'x',
b: 'x',
// @ts-expect-error extra param
c: 'y',
}),
});
const extension = TestExtensionBlueprint.make({
params: define =>
define({
a: 'x',
b: 'x',
}),
});
expect(extension).toEqual({
$$type: '@backstage/ExtensionDefinition',
T: undefined,
attachTo: {
id: 'test',
input: 'default',
},
configSchema: undefined,
disabled: false,
inputs: {},
kind: 'test-extension',
name: undefined,
namespace: undefined,
output: [testDataRef],
factory: expect.any(Function),
toString: expect.any(Function),
override: expect.any(Function),
version: 'v2',
});
expect(createExtensionTester(extension).get(testDataRef)).toBe('x x');
extension.override({
// @ts-expect-error not using define func
params: {
a: 'z',
b: 'w',
},
});
extension.override({
params: define =>
define({
a: 'z',
// @ts-expect-error b doesn't match a
b: 'w',
}),
});
extension.override({
params: define =>
define({
a: 'z',
b: 'z',
// @ts-expect-error extra param
c: 'w',
}),
});
const override = extension.override({
params: define =>
define({
a: 'z',
b: 'z',
}),
});
expect(createExtensionTester(override).get(testDataRef)).toBe('z z');
});
it('should allow overriding of the default factory', () => {
TestExtensionBlueprint.makeWithOverrides({
factory(originalFactory) {
// @ts-expect-error not using define func
return originalFactory({
a: 'x',
b: 'y',
});
},
});
TestExtensionBlueprint.makeWithOverrides({
factory(originalFactory) {
return originalFactory(define =>
define({
a: 'x',
// @ts-expect-error b doesn't match a
b: 'y',
}),
);
},
});
const extension = TestExtensionBlueprint.makeWithOverrides({
factory(originalFactory) {
return originalFactory(define =>
define({
a: 'x',
b: 'x',
}),
);
},
});
expect(extension).toEqual({
$$type: '@backstage/ExtensionDefinition',
T: undefined,
attachTo: {
id: 'test',
input: 'default',
},
configSchema: undefined,
disabled: false,
inputs: {},
kind: 'test-extension',
name: undefined,
namespace: undefined,
output: [testDataRef],
factory: expect.any(Function),
toString: expect.any(Function),
override: expect.any(Function),
version: 'v2',
});
expect(createExtensionTester(extension).get(testDataRef)).toBe('x x');
extension.override({
// @ts-expect-error not using define func
params: {
a: 'z',
b: 'w',
},
});
extension.override({
params: define =>
define({
a: 'z',
// @ts-expect-error b doesn't match a
b: 'w',
}),
});
const override = extension.override({
params: define =>
define({
a: 'z',
b: 'z',
}),
});
expect(createExtensionTester(override).get(testDataRef)).toBe('z z');
});
it('should allow the params definer to transform the params', () => {
const TestTransformExtensionBlueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef],
defineParams(params: { a: number; b: number }) {
return createExtensionBlueprintParams({
x: params.a + 1,
y: params.b + 1,
});
},
factory(params) {
return [testDataRef(`${params.x} ${params.y}`)];
},
});
const extension = TestTransformExtensionBlueprint.make({
params: define =>
define({
a: 0,
b: 10,
}),
});
expect(createExtensionTester(extension).get(testDataRef)).toBe(`1 11`);
expect(
createExtensionTester(
extension.override({
params: define =>
define({
a: 20,
b: 30,
}),
}),
).get(testDataRef),
).toBe(`21 31`);
});
it('should support overloads', () => {
const TestTransformExtensionBlueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef],
defineParams: (params => createExtensionBlueprintParams(params)) as {
(params: { x: 1 }): ExtensionBlueprintParams<{ x: number }>;
(params: { x: 2 }): ExtensionBlueprintParams<{ x: number }>;
},
factory(params) {
return [testDataRef(`x: ${params.x}`)];
},
});
const extension = TestTransformExtensionBlueprint.make({
params: define => define({ x: 1 }),
});
expect(createExtensionTester(extension).get(testDataRef)).toBe(`x: 1`);
TestTransformExtensionBlueprint.make({
params: define => define({ x: 2 }),
});
TestTransformExtensionBlueprint.make({
// @ts-expect-error doesn't match any overload
params: define => define({ x: 3 }),
});
});
});
});
@@ -16,6 +16,7 @@
import { ApiHolder, AppNode } from '../apis';
import { Expand } from '@backstage/types';
import { OpaqueType } from '@internal/opaque';
import {
ExtensionAttachToSpec,
ExtensionDefinition,
@@ -37,13 +38,73 @@ import {
} from './resolveInputOverrides';
import { ExtensionDataContainer } from './types';
/**
* A function used to define a parameter mapping function in order to facilitate
* advanced parameter typing for extension blueprints.
*
* @remarks
*
* This function is primarily intended to enable the use of inferred type
* parameters for blueprint params, but it can also be used to transoform the
* params before they are handed ot the blueprint.
*
* The function must return an object created with
* {@link createExtensionBlueprintParams}.
*
* @public
*/
export type ExtensionBlueprintParamsDefiner<
TParams extends object = object,
TInput = any,
> = (params: TInput) => ExtensionBlueprintParams<TParams>;
/**
* An opaque type that represents a set of parameters to be passed to a blueprint.
*
* @remarks
*
* Created with {@link createExtensionBlueprintParams}.
*
* @public
*/
export type ExtensionBlueprintParams<T extends object = object> = {
$$type: '@backstage/BlueprintParams';
T: T;
};
const OpaqueBlueprintParams = OpaqueType.create<{
public: ExtensionBlueprintParams;
versions: {
version: 'v1';
params: object;
};
}>({
type: '@backstage/BlueprintParams',
versions: ['v1'],
});
/**
* Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object.
*
* This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}.
*
* @public
* @param params - The plain blueprint parameter object to wrap.
* @returns The wrapped blueprint parameter object.
*/
export function createExtensionBlueprintParams<T extends object = object>(
params: T,
): ExtensionBlueprintParams<T> {
return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params });
}
/**
* @public
*/
export type CreateExtensionBlueprintOptions<
TKind extends string,
TName extends string | undefined,
TParams,
TParams extends object | ExtensionBlueprintParamsDefiner,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
@@ -64,8 +125,51 @@ export type CreateExtensionBlueprintOptions<
config?: {
schema: TConfigSchema;
};
/**
* This option is used to further refine the blueprint params. When this
* option is used, the blueprint will require params to be passed in callback
* form. This function can both transform the params before they are handed to
* the blueprint factory, but importantly it also allows you to define
* inferred type parameters for your blueprint params.
*
* @example
* Blueprint definition with inferred type parameters:
* ```ts
* const ExampleBlueprint = createExtensionBlueprint({
* kind: 'example',
* attachTo: { id: 'example', input: 'example' },
* output: [exampleComponentDataRef, exampleFetcherDataRef],
* defineParams<T>(params: {
* component(props: ExampleProps<T>): JSX.Element | null
* fetcher(options: FetchOptions): Promise<FetchResult<T>>
* }) {
* return createExtensionBlueprintParams(params);
* },
* *factory(params) {
* yield exampleComponentDataRef(params.component)
* yield exampleFetcherDataRef(params.fetcher)
* },
* });
* ```
*
* @example
* Usage of the above example blueprint:
* ```ts
* const example = ExampleBlueprint.make({
* params: define => define({
* component: ...,
* fetcher: ...,
* }),
* });
* ```
*/
defineParams?: TParams extends ExtensionBlueprintParamsDefiner
? TParams
: 'The defineParams option must be a function if provided, see the docs for details';
factory(
params: TParams,
params: TParams extends ExtensionBlueprintParamsDefiner
? ReturnType<TParams>['T']
: TParams,
context: {
node: AppNode;
apis: ApiHolder;
@@ -83,7 +187,7 @@ export type CreateExtensionBlueprintOptions<
export type ExtensionBlueprintParameters = {
kind: string;
name?: string;
params?: object;
params?: object | ExtensionBlueprintParamsDefiner;
configInput?: { [K in string]: any };
config?: { [K in string]: any };
output?: AnyExtensionDataRef;
@@ -96,19 +200,45 @@ export type ExtensionBlueprintParameters = {
dataRefs?: { [name in string]: AnyExtensionDataRef };
};
/** @ignore */
type ParamsFactory<TDefiner extends ExtensionBlueprintParamsDefiner> = (
define: TDefiner,
) => ReturnType<TDefiner>;
/**
* Represents any form of params input that can be passed to a blueprint.
* This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback.
*
* @ignore
*/
type AnyParamsInput<TParams extends object | ExtensionBlueprintParamsDefiner> =
TParams extends ExtensionBlueprintParamsDefiner<infer IParams>
? IParams | ParamsFactory<TParams>
:
| TParams
| ParamsFactory<ExtensionBlueprintParamsDefiner<TParams, TParams>>;
/**
* @public
*/
export interface ExtensionBlueprint<
// TParamsMapper extends (params: any) => object,
T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,
> {
dataRefs: T['dataRefs'];
make<TNewName extends string | undefined>(args: {
make<
TNewName extends string | undefined,
TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,
>(args: {
name?: TNewName;
attachTo?: ExtensionAttachToSpec;
disabled?: boolean;
params: T['params'];
params: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: define => define(<params>) })`'
: TParamsInput;
}): ExtensionDefinition<{
kind: T['kind'];
name: string | undefined extends TNewName ? T['name'] : TNewName;
@@ -154,8 +284,14 @@ export interface ExtensionBlueprint<
};
};
factory(
originalFactory: (
params: T['params'],
originalFactory: <
TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,
>(
params: TParamsInput extends ExtensionBlueprintParamsDefiner
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: TParamsInput,
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
@@ -205,6 +341,76 @@ export interface ExtensionBlueprint<
}>;
}
function unwrapParamsFactory<TParams extends object>(
// Allow `Function` because `typeof <object> === 'function'` allows it, but in practice this should always be a param factory
params: ParamsFactory<ExtensionBlueprintParamsDefiner> | Function,
defineParams: ExtensionBlueprintParamsDefiner,
kind: string,
): TParams {
const paramDefinition = (
params as ParamsFactory<ExtensionBlueprintParamsDefiner>
)(defineParams);
try {
return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams;
} catch (e) {
throw new TypeError(
`Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`,
);
}
}
function unwrapParams<TParams extends object>(
params: object | ParamsFactory<ExtensionBlueprintParamsDefiner> | string,
ctx: { node: AppNode; [ctxParamsSymbol]?: any },
defineParams: ExtensionBlueprintParamsDefiner | undefined,
kind: string,
): TParams {
const overrideParams = ctx[ctxParamsSymbol] as
| object
| ParamsFactory<ExtensionBlueprintParamsDefiner>
| undefined;
if (defineParams) {
if (overrideParams) {
if (typeof overrideParams !== 'function') {
throw new TypeError(
`Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`,
);
}
return unwrapParamsFactory(overrideParams, defineParams, kind);
}
if (typeof params !== 'function') {
throw new TypeError(
`Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`,
);
}
return unwrapParamsFactory(params, defineParams, kind);
}
const base =
typeof params === 'function'
? unwrapParamsFactory<TParams>(
params,
createExtensionBlueprintParams,
kind,
)
: (params as TParams);
const overrides =
typeof overrideParams === 'function'
? unwrapParamsFactory<TParams>(
overrideParams,
createExtensionBlueprintParams,
kind,
)
: (overrideParams as Partial<TParams>);
return {
...base,
...overrides,
};
}
/**
* A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating
* types and instances of those types.
@@ -212,7 +418,7 @@ export interface ExtensionBlueprint<
* @public
*/
export function createExtensionBlueprint<
TParams extends object,
TParams extends object | ExtensionBlueprintParamsDefiner,
UOutput extends AnyExtensionDataRef,
TInputs extends {
[inputName in string]: ExtensionInput<
@@ -254,6 +460,10 @@ export function createExtensionBlueprint<
>;
dataRefs: TDataRefs;
}> {
const defineParams = options.defineParams as
| ExtensionBlueprintParamsDefiner
| undefined;
return {
dataRefs: options.dataRefs,
make(args) {
@@ -267,7 +477,7 @@ export function createExtensionBlueprint<
config: options.config,
factory: ctx =>
options.factory(
{ ...args.params, ...(ctx as any)[ctxParamsSymbol] },
unwrapParams(args.params, ctx, defineParams, options.kind),
ctx,
) as Iterable<ExtensionDataValue<any, any>>,
}) as ExtensionDefinition;
@@ -295,7 +505,7 @@ export function createExtensionBlueprint<
(innerParams, innerContext) => {
return createExtensionDataContainer<UOutput>(
options.factory(
{ ...innerParams, ...(ctx as any)[ctxParamsSymbol] },
unwrapParams(innerParams, ctx, defineParams, options.kind),
{
apis,
node,
@@ -66,6 +66,9 @@ export {
type CreateExtensionBlueprintOptions,
type ExtensionBlueprint,
type ExtensionBlueprintParameters,
type ExtensionBlueprintParams,
type ExtensionBlueprintParamsDefiner,
createExtensionBlueprint,
createExtensionBlueprintParams,
} from './createExtensionBlueprint';
export { type ResolveInputValueOverrides } from './resolveInputOverrides';
@@ -113,6 +113,7 @@ describe('ResolveExtensionId', () => {
kind: TKind;
name: TName;
output: any;
params: never;
}>;
const id1: 'k:ns' = {} as ResolveExtensionId<
NamedExtension<'k', undefined>,
@@ -116,6 +116,7 @@ export type ResolveExtensionId<
> = TExtension extends ExtensionDefinition<{
kind: infer IKind extends string | undefined;
name: infer IName extends string | undefined;
params: any;
}>
? [string] extends [IKind | IName]
? never
+9 -3
View File
@@ -6,11 +6,13 @@
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';
import { EntityCardType } from '@backstage/plugin-catalog-react/alpha';
import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
@@ -73,9 +75,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'entity-card:api-docs/consumed-apis': ExtensionDefinition<{
kind: 'entity-card';
+2 -4
View File
@@ -20,7 +20,6 @@ import {
ApiBlueprint,
NavItemBlueprint,
PageBlueprint,
createApiFactory,
createFrontendPlugin,
} from '@backstage/frontend-plugin-api';
@@ -55,8 +54,8 @@ const apiDocsNavItem = NavItemBlueprint.make({
const apiDocsConfigApi = ApiBlueprint.make({
name: 'config',
params: {
factory: createApiFactory({
params: define =>
define({
api: apiDocsConfigRef,
deps: {},
factory: () => {
@@ -68,7 +67,6 @@ const apiDocsConfigApi = ApiBlueprint.make({
};
},
}),
},
});
const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({
+191 -81
View File
@@ -6,10 +6,12 @@
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { AppTheme } from '@backstage/frontend-plugin-api';
import { ComponentRef } from '@backstage/frontend-plugin-api';
import { ComponentType } from 'react';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
@@ -222,9 +224,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/analytics': ExtensionDefinition<{
kind: 'api';
@@ -237,9 +243,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/app-language': ExtensionDefinition<{
kind: 'api';
@@ -252,9 +262,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/app-theme': ExtensionDefinition<{
config: {};
@@ -275,9 +289,13 @@ const appPlugin: FrontendPlugin<
};
kind: 'api';
name: 'app-theme';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/atlassian-auth': ExtensionDefinition<{
kind: 'api';
@@ -290,9 +308,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/bitbucket-auth': ExtensionDefinition<{
kind: 'api';
@@ -305,9 +327,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/bitbucket-server-auth': ExtensionDefinition<{
kind: 'api';
@@ -320,9 +346,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/components': ExtensionDefinition<{
config: {};
@@ -350,9 +380,13 @@ const appPlugin: FrontendPlugin<
};
kind: 'api';
name: 'components';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/dialog': ExtensionDefinition<{
kind: 'api';
@@ -365,9 +399,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/discovery': ExtensionDefinition<{
kind: 'api';
@@ -380,9 +418,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/error': ExtensionDefinition<{
kind: 'api';
@@ -395,9 +437,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/feature-flags': ExtensionDefinition<{
kind: 'api';
@@ -410,9 +456,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/fetch': ExtensionDefinition<{
kind: 'api';
@@ -425,9 +475,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/github-auth': ExtensionDefinition<{
kind: 'api';
@@ -440,9 +494,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/gitlab-auth': ExtensionDefinition<{
kind: 'api';
@@ -455,9 +513,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/google-auth': ExtensionDefinition<{
kind: 'api';
@@ -470,9 +532,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/icons': ExtensionDefinition<{
config: {};
@@ -499,9 +565,13 @@ const appPlugin: FrontendPlugin<
};
kind: 'api';
name: 'icons';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/microsoft-auth': ExtensionDefinition<{
kind: 'api';
@@ -514,9 +584,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/oauth-request': ExtensionDefinition<{
kind: 'api';
@@ -529,9 +603,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/okta-auth': ExtensionDefinition<{
kind: 'api';
@@ -544,9 +622,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/onelogin-auth': ExtensionDefinition<{
kind: 'api';
@@ -559,9 +641,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/permission': ExtensionDefinition<{
kind: 'api';
@@ -574,9 +660,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/scm-auth': ExtensionDefinition<{
kind: 'api';
@@ -589,9 +679,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/scm-integrations': ExtensionDefinition<{
kind: 'api';
@@ -604,9 +698,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/storage': ExtensionDefinition<{
kind: 'api';
@@ -619,9 +717,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/translations': ExtensionDefinition<{
config: {};
@@ -653,9 +755,13 @@ const appPlugin: FrontendPlugin<
};
kind: 'api';
name: 'translations';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:app/vmware-cloud-auth': ExtensionDefinition<{
kind: 'api';
@@ -668,9 +774,13 @@ const appPlugin: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'app-root-element:app/alert-display': ExtensionDefinition<{
config: {
+41 -64
View File
@@ -39,7 +39,6 @@ import {
} from '../../../packages/core-app-api/src/apis/implementations';
import {
createApiFactory,
alertApiRef,
analyticsApiRef,
errorApiRef,
@@ -75,18 +74,17 @@ import { DefaultDialogApi } from './apis/DefaultDialogApi';
export const apis = [
ApiBlueprint.make({
name: 'dialog',
params: {
factory: createApiFactory({
params: define =>
define({
api: dialogApiRef,
deps: {},
factory: () => new DefaultDialogApi(),
}),
},
}),
ApiBlueprint.make({
name: 'discovery',
params: {
factory: createApiFactory({
params: define =>
define({
api: discoveryApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) =>
@@ -94,32 +92,29 @@ export const apis = [
`${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`,
),
}),
},
}),
ApiBlueprint.make({
name: 'alert',
params: {
factory: createApiFactory({
params: define =>
define({
api: alertApiRef,
deps: {},
factory: () => new AlertApiForwarder(),
}),
},
}),
ApiBlueprint.make({
name: 'analytics',
params: {
factory: createApiFactory({
params: define =>
define({
api: analyticsApiRef,
deps: {},
factory: () => new NoOpAnalyticsApi(),
}),
},
}),
ApiBlueprint.make({
name: 'error',
params: {
factory: createApiFactory({
params: define =>
define({
api: errorApiRef,
deps: { alertApi: alertApiRef },
factory: ({ alertApi }) => {
@@ -128,22 +123,20 @@ export const apis = [
return errorApi;
},
}),
},
}),
ApiBlueprint.make({
name: 'storage',
params: {
factory: createApiFactory({
params: define =>
define({
api: storageApiRef,
deps: { errorApi: errorApiRef },
factory: ({ errorApi }) => WebStorage.create({ errorApi }),
}),
},
}),
ApiBlueprint.make({
name: 'fetch',
params: {
factory: createApiFactory({
params: define =>
define({
api: fetchApiRef,
deps: {
configApi: configApiRef,
@@ -164,22 +157,20 @@ export const apis = [
});
},
}),
},
}),
ApiBlueprint.make({
name: 'oauth-request',
params: {
factory: createApiFactory({
params: define =>
define({
api: oauthRequestApiRef,
deps: {},
factory: () => new OAuthRequestManager(),
}),
},
}),
ApiBlueprint.make({
name: 'google-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: googleAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -194,12 +185,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'microsoft-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: microsoftAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -214,12 +204,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'github-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: githubAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -235,12 +224,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'okta-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: oktaAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -255,12 +243,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'gitlab-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: gitlabAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -275,12 +262,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'onelogin-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: oneloginAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -295,12 +281,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'bitbucket-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: bitbucketAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -316,12 +301,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'bitbucket-server-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: bitbucketServerAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -337,12 +321,11 @@ export const apis = [
environment: configApi.getOptionalString('auth.environment'),
}),
}),
},
}),
ApiBlueprint.make({
name: 'atlassian-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: atlassianAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -358,12 +341,11 @@ export const apis = [
});
},
}),
},
}),
ApiBlueprint.make({
name: 'vmware-cloud-auth',
params: {
factory: createApiFactory({
params: define =>
define({
api: vmwareCloudAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -379,12 +361,11 @@ export const apis = [
});
},
}),
},
}),
ApiBlueprint.make({
name: 'permission',
params: {
factory: createApiFactory({
params: define =>
define({
api: permissionApiRef,
deps: {
discovery: discoveryApiRef,
@@ -394,22 +375,18 @@ export const apis = [
factory: ({ config, discovery, identity }) =>
IdentityPermissionApi.create({ config, discovery, identity }),
}),
},
}),
ApiBlueprint.make({
name: 'scm-auth',
params: {
factory: ScmAuth.createDefaultApiFactory(),
},
params: define => define(ScmAuth.createDefaultApiFactory()),
}),
ApiBlueprint.make({
name: 'scm-integrations',
params: {
factory: createApiFactory({
params: define =>
define({
api: scmIntegrationsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
}),
},
}),
] as const;
+7 -7
View File
@@ -17,14 +17,14 @@
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { AppLanguageSelector } from '../../../../packages/core-app-api/src/apis/implementations/AppLanguageApi';
import { appLanguageApiRef } from '@backstage/core-plugin-api/alpha';
import { ApiBlueprint, createApiFactory } from '@backstage/frontend-plugin-api';
import { ApiBlueprint } from '@backstage/frontend-plugin-api';
export const AppLanguageApi = ApiBlueprint.make({
name: 'app-language',
params: {
factory: createApiFactory(
appLanguageApiRef,
AppLanguageSelector.createWithStorage(),
),
},
params: define =>
define({
api: appLanguageApiRef,
deps: {},
factory: () => AppLanguageSelector.createWithStorage(),
}),
});
+10 -9
View File
@@ -24,7 +24,6 @@ import {
createExtensionInput,
ThemeBlueprint,
ApiBlueprint,
createApiFactory,
appThemeApiRef,
} from '@backstage/frontend-plugin-api';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
@@ -41,14 +40,16 @@ export const AppThemeApi = ApiBlueprint.makeWithOverrides({
}),
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
factory: createApiFactory(
appThemeApiRef,
AppThemeSelector.createWithStorage(
inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)),
),
),
});
return originalFactory(define =>
define({
api: appThemeApiRef,
deps: {},
factory: () =>
AppThemeSelector.createWithStorage(
inputs.themes.map(i => i.get(ThemeBlueprint.dataRefs.theme)),
),
}),
);
},
});
+11 -10
View File
@@ -18,7 +18,6 @@ import {
createComponentExtension,
createExtensionInput,
ApiBlueprint,
createApiFactory,
componentsApiRef,
} from '@backstage/frontend-plugin-api';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
@@ -36,15 +35,17 @@ export const ComponentsApi = ApiBlueprint.makeWithOverrides({
),
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
factory: createApiFactory(
componentsApiRef,
DefaultComponentsApi.fromComponents(
inputs.components.map(i =>
i.get(createComponentExtension.componentDataRef),
return originalFactory(define =>
define({
api: componentsApiRef,
deps: {},
factory: () =>
DefaultComponentsApi.fromComponents(
inputs.components.map(i =>
i.get(createComponentExtension.componentDataRef),
),
),
),
),
});
}),
);
},
});
@@ -16,7 +16,6 @@
import {
ApiBlueprint,
createApiFactory,
featureFlagsApiRef,
} from '@backstage/frontend-plugin-api';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
@@ -27,12 +26,11 @@ import { LocalStorageFeatureFlags } from '../../../../packages/core-app-api/src/
*/
export const FeatureFlagsApi = ApiBlueprint.make({
name: 'feature-flags',
params: {
// TODO: properly discovery feature flags, maybe rework the whole thing
factory: createApiFactory({
params: define =>
define({
// TODO: properly discovery feature flags, maybe rework the whole thing
api: featureFlagsApiRef,
deps: {},
factory: () => new LocalStorageFeatureFlags(),
}),
},
});
+12 -11
View File
@@ -18,7 +18,6 @@ import {
createExtensionInput,
IconBundleBlueprint,
ApiBlueprint,
createApiFactory,
iconsApiRef,
} from '@backstage/frontend-plugin-api';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
@@ -37,15 +36,17 @@ export const IconsApi = ApiBlueprint.makeWithOverrides({
}),
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
factory: createApiFactory(
iconsApiRef,
new DefaultIconsApi(
inputs.icons
.map(i => i.get(IconBundleBlueprint.dataRefs.icons))
.reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons),
),
),
});
return originalFactory(define =>
define({
api: iconsApiRef,
deps: {},
factory: () =>
new DefaultIconsApi(
inputs.icons
.map(i => i.get(IconBundleBlueprint.dataRefs.icons))
.reduce((acc, bundle) => ({ ...acc, ...bundle }), defaultIcons),
),
}),
);
},
});
@@ -16,7 +16,6 @@
import {
ApiBlueprint,
TranslationBlueprint,
createApiFactory,
createExtensionInput,
} from '@backstage/frontend-plugin-api';
import {
@@ -39,8 +38,8 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({
),
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
factory: createApiFactory({
return originalFactory(define =>
define({
api: translationApiRef,
deps: { languageApi: appLanguageApiRef },
factory: ({ languageApi }) =>
@@ -51,6 +50,6 @@ export const TranslationsApi = ApiBlueprint.makeWithOverrides({
),
}),
}),
});
);
},
});
+9 -3
View File
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/core-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/core-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
@@ -103,9 +105,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'page:catalog-import': ExtensionDefinition<{
kind: 'page';
+2 -4
View File
@@ -16,7 +16,6 @@
import {
configApiRef,
createApiFactory,
discoveryApiRef,
fetchApiRef,
} from '@backstage/core-plugin-api';
@@ -53,8 +52,8 @@ const catalogImportPage = PageBlueprint.make({
});
const catalogImportApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: catalogImportApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -81,7 +80,6 @@ const catalogImportApi = ApiBlueprint.make({
configApi,
}),
}),
},
});
/** @alpha */
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
@@ -30,9 +32,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'nav-item:catalog-unprocessed-entities': ExtensionDefinition<{
kind: 'nav-item';
@@ -15,7 +15,6 @@
*/
import {
createApiFactory,
createFrontendPlugin,
discoveryApiRef,
fetchApiRef,
@@ -37,8 +36,8 @@ import { rootRouteRef } from '../routes';
/** @alpha */
export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: catalogUnprocessedEntitiesApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -47,7 +46,6 @@ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({
factory: ({ discoveryApi, fetchApi }) =>
new CatalogUnprocessedEntitiesClient(discoveryApi, fetchApi),
}),
},
});
/** @alpha */
+23 -9
View File
@@ -6,6 +6,7 @@
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';
@@ -13,6 +14,7 @@ import { EntityCardType } from '@backstage/plugin-catalog-react/alpha';
import { EntityContentLayoutProps } from '@backstage/plugin-catalog-react/alpha';
import { EntityContextMenuItemParams } from '@backstage/plugin-catalog-react/alpha';
import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
@@ -146,9 +148,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:catalog/entity-presentation': ExtensionDefinition<{
kind: 'api';
@@ -161,9 +167,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:catalog/starred-entities': ExtensionDefinition<{
kind: 'api';
@@ -176,9 +186,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'catalog-filter:catalog/kind': ExtensionDefinition<{
config: {
+6 -10
View File
@@ -15,7 +15,6 @@
*/
import {
createApiFactory,
discoveryApiRef,
fetchApiRef,
storageApiRef,
@@ -33,8 +32,8 @@ import {
} from '../apis';
export const catalogApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: catalogApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -43,31 +42,28 @@ export const catalogApi = ApiBlueprint.make({
factory: ({ discoveryApi, fetchApi }) =>
new CatalogClient({ discoveryApi, fetchApi }),
}),
},
});
export const catalogStarredEntitiesApi = ApiBlueprint.make({
name: 'starred-entities',
params: {
factory: createApiFactory({
params: define =>
define({
api: starredEntitiesApiRef,
deps: { storageApi: storageApiRef },
factory: ({ storageApi }) =>
new DefaultStarredEntitiesApi({ storageApi }),
}),
},
});
export const entityPresentationApi = ApiBlueprint.make({
name: 'entity-presentation',
params: {
factory: createApiFactory({
params: define =>
define({
api: entityPresentationApiRef,
deps: { catalogApiImp: catalogApiRef },
factory: ({ catalogApiImp }) =>
DefaultEntityPresentationApi.create({ catalogApi: catalogApiImp }),
}),
},
});
export default [catalogApi, catalogStarredEntitiesApi, entityPresentationApi];
+9 -3
View File
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
@@ -30,9 +32,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'nav-item:devtools': ExtensionDefinition<{
kind: 'nav-item';
+2 -4
View File
@@ -15,7 +15,6 @@
*/
import {
createApiFactory,
createFrontendPlugin,
discoveryApiRef,
fetchApiRef,
@@ -34,8 +33,8 @@ import { rootRouteRef } from '../routes';
/** @alpha */
export const devToolsApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: devToolsApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -44,7 +43,6 @@ export const devToolsApi = ApiBlueprint.make({
factory: ({ discoveryApi, fetchApi }) =>
new DevToolsClient({ discoveryApi, fetchApi }),
}),
},
});
/** @alpha */
+9 -3
View File
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
@@ -31,9 +33,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'app-root-element:home/visit-listener': ExtensionDefinition<{
kind: 'app-root-element';
+2 -4
View File
@@ -24,7 +24,6 @@ import {
AppRootElementBlueprint,
identityApiRef,
storageApiRef,
createApiFactory,
ApiBlueprint,
} from '@backstage/frontend-plugin-api';
import { compatWrapper } from '@backstage/core-compat-api';
@@ -79,8 +78,8 @@ const visitListenerAppRootElement = AppRootElementBlueprint.make({
const visitsApi = ApiBlueprint.make({
name: 'visits',
params: {
factory: createApiFactory({
params: define =>
define({
api: visitsApiRef,
deps: {
storageApi: storageApiRef,
@@ -89,7 +88,6 @@ const visitsApi = ApiBlueprint.make({
factory: ({ storageApi, identityApi }) =>
VisitsStorageApi.create({ storageApi, identityApi }),
}),
},
});
/**
+30 -12
View File
@@ -5,10 +5,12 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';
import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
@@ -33,9 +35,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:kubernetes/auth-providers': ExtensionDefinition<{
kind: 'api';
@@ -48,9 +54,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:kubernetes/cluster-link-formatter': ExtensionDefinition<{
kind: 'api';
@@ -63,9 +73,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:kubernetes/proxy': ExtensionDefinition<{
kind: 'api';
@@ -78,9 +92,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'entity-content:kubernetes/kubernetes': ExtensionDefinition<{
kind: 'entity-content';
+8 -13
View File
@@ -16,7 +16,6 @@
import {
ApiBlueprint,
createApiFactory,
discoveryApiRef,
fetchApiRef,
} from '@backstage/frontend-plugin-api';
@@ -41,8 +40,8 @@ import {
} from '@backstage/core-plugin-api';
export const kubernetesApiExtension = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: kubernetesApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -56,13 +55,12 @@ export const kubernetesApiExtension = ApiBlueprint.make({
kubernetesAuthProvidersApi,
}),
}),
},
});
export const kubernetesProxyApi = ApiBlueprint.make({
name: 'proxy',
params: {
factory: createApiFactory({
params: define =>
define({
api: kubernetesProxyApiRef,
deps: {
kubernetesApi: kubernetesApiRef,
@@ -72,13 +70,12 @@ export const kubernetesProxyApi = ApiBlueprint.make({
kubernetesApi,
}),
}),
},
});
export const kubernetesAuthProvidersApi = ApiBlueprint.make({
name: 'auth-providers',
params: {
factory: createApiFactory({
params: define =>
define({
api: kubernetesAuthProvidersApiRef,
deps: {
gitlabAuthApi: gitlabAuthApiRef,
@@ -109,13 +106,12 @@ export const kubernetesAuthProvidersApi = ApiBlueprint.make({
});
},
}),
},
});
export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({
name: 'cluster-link-formatter',
params: {
factory: createApiFactory({
params: define =>
define({
api: kubernetesClusterLinkFormatterApiRef,
deps: { googleAuthApi: googleAuthApiRef },
factory: deps => {
@@ -126,5 +122,4 @@ export const kubernetesClusterLinkFormatterApi = ApiBlueprint.make({
});
},
}),
},
});
+9 -3
View File
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
@@ -29,9 +31,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'page:notifications': ExtensionDefinition<{
kind: 'page';
+2 -4
View File
@@ -17,7 +17,6 @@
import {
ApiBlueprint,
PageBlueprint,
createApiFactory,
createFrontendPlugin,
discoveryApiRef,
fetchApiRef,
@@ -41,14 +40,13 @@ const page = PageBlueprint.make({
});
const api = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: notificationsApiRef,
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
factory: ({ discoveryApi, fetchApi }) =>
new NotificationsClient({ discoveryApi, fetchApi }),
}),
},
});
/** @alpha */
+9 -3
View File
@@ -5,6 +5,7 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyApiRef } from '@backstage/core-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ApiHolder } from '@backstage/core-plugin-api';
import { ApiRef } from '@backstage/frontend-plugin-api';
import { ComponentType } from 'react';
@@ -12,6 +13,7 @@ import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react';
import { Dispatch } from 'react';
import { ExtensionBlueprint } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react';
@@ -218,9 +220,13 @@ export const formFieldsApi: ExtensionDefinition<{
};
kind: 'api';
name: 'form-fields';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
// @alpha @deprecated (undocumented)
@@ -16,7 +16,6 @@
import {
ApiBlueprint,
createApiFactory,
createExtensionInput,
} from '@backstage/frontend-plugin-api';
import { formFieldsApiRef } from './ref';
@@ -53,12 +52,12 @@ export const formFieldsApi = ApiBlueprint.makeWithOverrides({
e.get(FormFieldBlueprint.dataRefs.formFieldLoader),
);
return originalFactory({
factory: createApiFactory({
return originalFactory(define =>
define({
api: formFieldsApiRef,
deps: {},
factory: () => new DefaultScaffolderFormFieldsApi(formFieldLoaders),
}),
});
);
},
});
+30 -12
View File
@@ -5,11 +5,13 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ApiRef } from '@backstage/frontend-plugin-api';
import { ComponentType } from 'react';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { Entity } from '@backstage/catalog-model';
import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
@@ -66,9 +68,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:scaffolder/form-decorators': ExtensionDefinition<{
config: {};
@@ -93,9 +99,13 @@ const _default: FrontendPlugin<
};
kind: 'api';
name: 'form-decorators';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:scaffolder/form-fields': ExtensionDefinition<{
config: {};
@@ -120,9 +130,13 @@ const _default: FrontendPlugin<
};
kind: 'api';
name: 'form-fields';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'entity-icon-link:scaffolder/launch-template': ExtensionDefinition<{
kind: 'entity-icon-link';
@@ -273,9 +287,13 @@ export const formDecoratorsApi: ExtensionDefinition<{
};
kind: 'api';
name: 'form-decorators';
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
// @alpha (undocumented)
@@ -16,7 +16,6 @@
import {
ApiBlueprint,
createApiFactory,
createExtensionInput,
} from '@backstage/frontend-plugin-api';
import { ScaffolderFormDecoratorsApi } from './types';
@@ -58,8 +57,8 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({
e.get(FormDecoratorBlueprint.dataRefs.formDecoratorLoader),
);
return originalFactory({
factory: createApiFactory({
return originalFactory(define =>
define({
api: formDecoratorsApiRef,
deps: {},
factory: () =>
@@ -67,6 +66,6 @@ export const formDecoratorsApi = ApiBlueprint.makeWithOverrides({
decorators: formDecorators,
}),
}),
});
);
},
});
+2 -4
View File
@@ -22,7 +22,6 @@ import {
NavItemBlueprint,
PageBlueprint,
ApiBlueprint,
createApiFactory,
discoveryApiRef,
fetchApiRef,
identityApiRef,
@@ -74,8 +73,8 @@ export const repoUrlPickerFormField = FormFieldBlueprint.make({
});
export const scaffolderApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: scaffolderApiRef,
deps: {
discoveryApi: discoveryApiRef,
@@ -91,5 +90,4 @@ export const scaffolderApi = ApiBlueprint.make({
identityApi,
}),
}),
},
});
+16 -6
View File
@@ -5,7 +5,9 @@
```ts
import { AnyApiFactory } from '@backstage/core-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/core-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
@@ -35,9 +37,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'nav-item:search': ExtensionDefinition<{
kind: 'nav-item';
@@ -145,9 +151,13 @@ export const searchApi: ExtensionDefinition<{
configInput: {};
output: ConfigurableExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
// @alpha (undocumented)
+2 -4
View File
@@ -31,7 +31,6 @@ import {
useApi,
discoveryApiRef,
fetchApiRef,
createApiFactory,
} from '@backstage/core-plugin-api';
import {
@@ -77,14 +76,13 @@ import {
/** @alpha */
export const searchApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: searchApiRef,
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
factory: ({ discoveryApi, fetchApi }) =>
new SearchClient({ discoveryApi, fetchApi }),
}),
},
});
const useSearchPageStyles = makeStyles((theme: Theme) => ({
+9 -3
View File
@@ -4,7 +4,9 @@
```ts
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
@@ -25,9 +27,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'app-root-element:signals/signals-display': ExtensionDefinition<{
kind: 'app-root-element';
+2 -4
View File
@@ -17,7 +17,6 @@
import {
ApiBlueprint,
AppRootElementBlueprint,
createApiFactory,
createFrontendPlugin,
discoveryApiRef,
identityApiRef,
@@ -28,8 +27,8 @@ import { SignalsDisplay } from './plugin';
import { compatWrapper } from '@backstage/core-compat-api';
const api = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: signalApiRef,
deps: {
identity: identityApiRef,
@@ -42,7 +41,6 @@ const api = ApiBlueprint.make({
});
},
}),
},
});
const signalsDisplayAppRootElement = AppRootElementBlueprint.make({
+16 -6
View File
@@ -6,10 +6,12 @@
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api';
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ApiFactory } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { defaultEntityContentGroups } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';
import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha';
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { FrontendPlugin } from '@backstage/frontend-plugin-api';
@@ -46,9 +48,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'api:techdocs/storage': ExtensionDefinition<{
kind: 'api';
@@ -61,9 +67,13 @@ const _default: FrontendPlugin<
{}
>;
inputs: {};
params: {
factory: AnyApiFactory;
};
params: <
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
>(
params: ApiFactory<TApi, TImpl, TDeps>,
) => ExtensionBlueprintParams<AnyApiFactory>;
}>;
'empty-state:techdocs/entity-content': ExtensionDefinition<{
config: {};
+4 -7
View File
@@ -26,7 +26,6 @@ import {
} from '@backstage/frontend-plugin-api';
import {
configApiRef,
createApiFactory,
discoveryApiRef,
fetchApiRef,
} from '@backstage/core-plugin-api';
@@ -68,8 +67,8 @@ const techdocsEntityIconLink = EntityIconLinkBlueprint.make({
/** @alpha */
const techDocsStorageApi = ApiBlueprint.make({
name: 'storage',
params: {
factory: createApiFactory({
params: define =>
define({
api: techdocsStorageApiRef,
deps: {
configApi: configApiRef,
@@ -83,13 +82,12 @@ const techDocsStorageApi = ApiBlueprint.make({
fetchApi,
}),
}),
},
});
/** @alpha */
const techDocsClientApi = ApiBlueprint.make({
params: {
factory: createApiFactory({
params: define =>
define({
api: techdocsApiRef,
deps: {
configApi: configApiRef,
@@ -103,7 +101,6 @@ const techDocsClientApi = ApiBlueprint.make({
fetchApi,
}),
}),
},
});
/** @alpha */