- 0169b23: Internal tweak to avoid circular dependencies
9e3868f: Added a new optional info
option to createFrontendPlugin
that lets you provide a loaders for different sources of metadata information about the plugin.
There are two available loaders. The first one is info.packageJson
, which can be used to point to a package.json
file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this:
export default createFrontendPlugin({
pluginId: '...',
info: {
packageJson: () => import('../package.json'),
},
});
The second loader is info.manifest
, which can be used to point to an opaque plugin manifest. This MUST ONLY be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should NOT use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with createApp
from @backstage/frontend-defaults
is able to parse the default catalog-info.yaml
format and built-in fields such as spec.owner
.
Typical usage looks like this:
export default createFrontendPlugin({
pluginId: '...',
info: {
manifest: () => import('../catalog-info.yaml'),
},
});
6f48f71: Added a new useAppNode
hook, which can be used to get a reference to the AppNode
from by the closest ExtensionBoundary
.
- Updated dependencies
- @backstage/core-components@0.17.3
- @backstage/core-plugin-api@1.10.8
- @backstage/types@1.2.1
- @backstage/version-bridge@1.0.11
9e3868f: Added a new optional info
option to createFrontendPlugin
that lets you provide a loaders for different sources of metadata information about the plugin.
There are two available loaders. The first one is info.packageJson
, which can be used to point to a package.json
file for the plugin. This is recommended for any plugin that is defined within its own package, especially all plugins that are published to a package registry. Typical usage looks like this:
export default createFrontendPlugin({
pluginId: '...',
info: {
packageJson: () => import('../package.json'),
},
});
The second loader is info.manifest
, which can be used to point to an opaque plugin manifest. This MUST ONLY be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should NOT use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with createApp
from @backstage/frontend-defaults
is able to parse the default catalog-info.yaml
format and built-in fields such as spec.owner
.
Typical usage looks like this:
export default createFrontendPlugin({
pluginId: '...',
info: {
manifest: () => import('../catalog-info.yaml'),
},
});
6f48f71: Added a new useAppNode
hook, which can be used to get a reference to the AppNode
from by the closest ExtensionBoundary
.
- 2bb9517: Introduce the
@backstage/plugin-app
package to hold all of the built-in extensions for easy consumption and overriding.
c816e2d: Added createFrontendModule
as a replacement for createExtensionOverrides
, which is now deprecated.
Deprecated the BackstagePlugin
and FrontendFeature
type in favor of FrontendPlugin
and FrontendFeature
from @backstage/frontend-app-api
respectively.
52f9c5a: Deprecated the namespace
option for createExtensionBlueprint
and createExtension
, these are no longer required and will default to the pluginId
instead.
You can migrate some of your extensions that use createExtensionOverrides
to using createFrontendModule
instead and providing a pluginId
there.
// Before
createExtensionOverrides({
extensions: [
createExtension({
name: 'my-extension',
namespace: 'my-namespace',
kind: 'test',
...
})
],
});
// After
createFrontendModule({
pluginId: 'my-namespace',
extensions: [
createExtension({
name: 'my-extension',
kind: 'test',
...
})
],
});
f3a2b91: Moved several implementations of built-in APIs from being hardcoded in the app to instead be provided as API extensions. This moves all API-related inputs from the app
extension to the respective API extensions. For example, extensions created with ThemeBlueprint
are now attached to the themes
input of api:app-theme
rather than the app
extension.
- 836127c: Updated dependency
@testing-library/react
to ^16.0.0
.
- 948d431: Removing deprecated
namespace
parameter in favour of pluginId
instead
- 043d7cd: Internal refactor
- 220f4f7: Remove unnecessary config object on IconBundleBlueprint
- 2a61422: The
factory
option is no longer required when overriding an extension.
98850de: Added support for defining replaces
in createExtensionInput
which will allow extensions to redirect missing attachTo
points to an input of the created extension.
export const AppThemeApi = ApiBlueprint.makeWithOverrides({
name: 'app-theme',
inputs: {
themes: createExtensionInput([ThemeBlueprint.dataRefs.theme], {
// attachTo: { id: 'app', input: 'themes'} will be redirected to this input instead
replaces: [{ id: 'app', input: 'themes' }],
}),
},
factory: () {
...
}
});
4a66456: A new apis
parameter has been added to factory
for extensions. This is a way to access utility APIs without being coupled to the React context.
- Updated dependencies
- @backstage/core-components@0.15.0
- @backstage/core-plugin-api@1.9.4
- @backstage/version-bridge@1.0.9
- @backstage/types@1.1.1
c816e2d: Added createFrontendModule
as a replacement for createExtensionOverrides
, which is now deprecated.
Deprecated the BackstagePlugin
and FrontendFeature
type in favor of FrontendPlugin
and FrontendFeature
from @backstage/frontend-app-api
respectively.
52f9c5a: Deprecated the namespace
option for createExtensionBlueprint
and createExtension
, these are no longer required and will default to the pluginId
instead.
You can migrate some of your extensions that use createExtensionOverrides
to using createFrontendModule
instead and providing a pluginId
there.
// Before
createExtensionOverrides({
extensions: [
createExtension({
name: 'my-extension',
namespace: 'my-namespace',
kind: 'test',
...
})
],
});
// After
createFrontendModule({
pluginId: 'my-namespace',
extensions: [
createExtension({
name: 'my-extension',
kind: 'test',
...
})
],
});
948d431: Removing deprecated namespace
parameter in favour of pluginId
instead
- Updated dependencies
- @backstage/core-components@0.14.11-next.0
- @backstage/core-plugin-api@1.9.3
- @backstage/types@1.1.1
- @backstage/version-bridge@1.0.8
- 6f72c2b: Fixing issue with extension blueprints
inputs
merging.
- 210d066: Added support for using the
params
in other properties of the createExtensionBlueprint
options by providing a callback.
- 9b356dc: Renamed
createPlugin
to createFrontendPlugin
. The old symbol is still exported but deprecated.
- a376559: Correct the
TConfig
type of data references to only contain config
4e53ad6: Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with createExtensionBlueprint
This allows the creation of extension instances with the following pattern:
// create the extension blueprint which is used to create instances
const EntityCardBlueprint = createExtensionBlueprint({
kind: 'entity-card',
attachTo: { id: 'test', input: 'default' },
output: [coreExtensionData.reactElement],
factory(params: { text: string }) {
return [coreExtensionData.reactElement(<h1>{params.text}</h1>)];
},
});
// create an instance of the extension blueprint with params
const testExtension = EntityCardBlueprint.make({
name: 'foo',
params: {
text: 'Hello World',
},
});
9b89b82: The ExtensionBoundary
now by default infers whether it's routable from whether it outputs a route path.
- e493020: Deprecated
inputs
and configSchema
options for createComponentExtenion
, these will be removed in a future release
7777b5f: Added a new IconBundleBlueprint
that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons.
import { IconBundleBlueprint } from '@backstage/frontend-plugin-api';
const exampleIconBundle = IconBundleBlueprint.make({
name: 'example-bundle',
params: {
icons: {
user: MyOwnUserIcon,
},
},
});
99abb6b: Support overriding of plugin extensions using the new plugin.withOverrides
method.
import homePlugin from '@backstage/plugin-home';
export default homePlugin.withOverrides({
extensions: [
homePage.getExtension('page:home').override({
*factory(originalFactory) {
yield* originalFactory();
yield coreExtensionData.reactElement(<h1>My custom home page</h1>);
},
}),
],
});
813cac4: Add an ExtensionBoundary.lazy
function to create properly wrapped lazy-loading enabled elements, suitable for use with coreExtensionData.reactElement
. The page blueprint now automatically leverages this.
- a65cfc8: Add support for accessing extensions definitions provided by a plugin via
plugin.getExtension(...)
. For this to work the extensions must be defined using the v2 format, typically using an extension blueprint.
3be9aeb: Extensions have been changed to be declared with an array of inputs and outputs, rather than a map of named data refs. This change was made to reduce confusion around the role of the input and output names, as well as enable more powerful APIs for overriding extensions.
An extension that was previously declared like this:
const exampleExtension = createExtension({
name: 'example',
inputs: {
items: createExtensionInput({
element: coreExtensionData.reactElement,
}),
},
output: {
element: coreExtensionData.reactElement,
},
factory({ inputs }) {
return {
element: (
<div>
Example
{inputs.items.map(item => {
return <div>{item.output.element}</div>;
})}
</div>
),
};
},
});
Should be migrated to the following:
const exampleExtension = createExtension({
name: 'example',
inputs: {
items: createExtensionInput([coreExtensionData.reactElement]),
},
output: [coreExtensionData.reactElement],
factory({ inputs }) {
return [
coreExtensionData.reactElement(
<div>
Example
{inputs.items.map(item => {
return <div>{item.get(coreExtensionData.reactElement)}</div>;
})}
</div>,
),
];
},
});
34f1b2a: Support merging of inputs
in extension blueprints, but stop merging output
. In addition, the original factory in extension blueprints now returns a data container that both provides access to the returned data, but can also be forwarded as output.
- 3fb421d: Added support to be able to define
zod
config schema in Blueprints, with built in schema merging from the Blueprint and the extension instances.
2d21599: Added support for being able to override extension definitions.
const TestCard = EntityCardBlueprint.make({
...
});
TestCard.override({
// override attachment points
attachTo: { id: 'something-else', input: 'overridden' },
// extend the config schema
config: {
schema: {
newConfig: z => z.string().optional(),
}
},
// override factory
*factory(originalFactory, { inputs, config }){
const originalOutput = originalFactory();
yield coreExentsionData.reactElement(
<Wrapping>
{originalOutput.get(coreExentsionData.reactElement)}
</Wrapping>
);
}
});
31bfc44: Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release.
For example, the following code:
export const myExtension =
createExtensionDataRef<MyType>('my-plugin.my-data');
Should be updated to the following:
export const myExtension = createExtensionDataRef<MyType>().with({
id: 'my-plugin.my-data',
});
6349099: Added config input type to the extensions
- Updated dependencies
- @backstage/core-components@0.14.10
- @backstage/core-plugin-api@1.9.3
- @backstage/types@1.1.1
- @backstage/version-bridge@1.0.8
3be9aeb: Extensions have been changed to be declared with an array of inputs and outputs, rather than a map of named data refs. This change was made to reduce confusion around the role of the input and output names, as well as enable more powerful APIs for overriding extensions.
An extension that was previously declared like this:
const exampleExtension = createExtension({
name: 'example',
inputs: {
items: createExtensionInput({
element: coreExtensionData.reactElement,
}),
},
output: {
element: coreExtensionData.reactElement,
},
factory({ inputs }) {
return {
element: (
<div>
Example
{inputs.items.map(item => {
return <div>{item.output.element}</div>;
})}
</div>
),
};
},
});
Should be migrated to the following:
const exampleExtension = createExtension({
name: 'example',
inputs: {
items: createExtensionInput([coreExtensionData.reactElement]),
},
output: [coreExtensionData.reactElement],
factory({ inputs }) {
return [
coreExtensionData.reactElement(
<div>
Example
{inputs.items.map(item => {
return <div>{item.get(coreExtensionData.reactElement)}</div>;
})}
</div>,
),
];
},
});
3fb421d: Added support to be able to define zod
config schema in Blueprints, with built in schema merging from the Blueprint and the extension instances.
- 6349099: Added config input type to the extensions
- Updated dependencies
- @backstage/core-components@0.14.10-next.0
- @backstage/core-plugin-api@1.9.3
- @backstage/types@1.1.1
- @backstage/version-bridge@1.0.8
4e53ad6: Introduce a new way to encapsulate extension kinds that replaces the extension creator pattern with createExtensionBlueprint
This allows the creation of extension instances with the following pattern:
// create the extension blueprint which is used to create instances
const EntityCardBlueprint = createExtensionBlueprint({
kind: 'entity-card',
attachTo: { id: 'test', input: 'default' },
output: {
element: coreExtensionData.reactElement,
},
factory(params: { text: string }) {
return {
element: <h1>{params.text}</h1>,
};
},
});
// create an instance of the extension blueprint with params
const testExtension = EntityCardBlueprint.make({
name: 'foo',
params: {
text: 'Hello World',
},
});
9b89b82: The ExtensionBoundary
now by default infers whether it's routable from whether it outputs a route path.
7777b5f: Added a new IconBundleBlueprint
that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons.
import { IconBundleBlueprint } from '@backstage/frontend-plugin-api';
const exampleIconBundle = IconBundleBlueprint.make({
name: 'example-bundle',
params: {
icons: {
user: MyOwnUserIcon,
},
},
});
31bfc44: Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release.
For example, the following code:
export const myExtension =
createExtensionDataRef<MyType>('my-plugin.my-data');
Should be updated to the following:
export const myExtension = createExtensionDataRef<MyType>().with({
id: 'my-plugin.my-data',
});
Updated dependencies
- @backstage/core-components@0.14.10-next.0
- @backstage/core-plugin-api@1.9.3
- @backstage/types@1.1.1
- @backstage/version-bridge@1.0.8