frontend-plugin-api: rename plugin ID option to pluginId

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-04-27 12:06:13 +02:00
parent c4fd744f42
commit fb58f20613
44 changed files with 216 additions and 115 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/frontend-plugin-api': patch
---
The `id` option of `createFrontendPlugin` has been renamed to `pluginId` in order to better align with similar APIs in the frontend and backend systems.
The old `id` option is deprecated and will be removed in a future release.
+23
View File
@@ -0,0 +1,23 @@
---
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/frontend-test-utils': patch
'@backstage/core-compat-api': patch
'@backstage/plugin-app-visualizer': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-notifications': patch
'@backstage/plugin-user-settings': 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
'@backstage/plugin-org': patch
---
Internal update to use the new `pluginId` option of `createFrontendPlugin`.
@@ -28,7 +28,7 @@ const myPage = PageBlueprint.make({
});
export default createFrontendPlugin({
id: 'my-plugin',
pluginId: 'my-plugin',
extensions: [myPage],
});
```
@@ -55,7 +55,7 @@ const catalogIndexPage = createPageExtension({
});
export default createFrontendPlugin({
id: 'catalog',
pluginId: 'catalog',
// highlight-start
routes: {
index: indexRouteRef,
@@ -204,7 +204,7 @@ const catalogIndexPage = createPageExtension({
});
export default createFrontendPlugin({
id: 'catalog',
pluginId: 'catalog',
routes: {
index: indexRouteRef,
},
@@ -411,7 +411,7 @@ const catalogIndexPage = createPageExtension({
});
export default createFrontendPlugin({
id: 'catalog',
pluginId: 'catalog',
routes: {
index: indexRouteRef,
// highlight-next-line
@@ -24,7 +24,7 @@ Example:
```ts
// This declaration is only for internal usage in tests. This could also be a direct default export.
export const userSettingsPlugin = createFrontendPlugin({
id: 'user-settings',
pluginId: 'user-settings',
...
})
@@ -68,7 +68,7 @@ const catalogSearchResultListItem = SearchResultListItemBlueprint.make({
// Note that the extensions themselves are not exported, only the plugin instance
export const catalogPlugin = createFrontendPlugin({
id: 'catalog',
pluginId: 'catalog',
extensions: [catalogEntityPage, catalogSearchResultListItem /* ... */],
});
```
@@ -219,7 +219,7 @@ Can be converted to the following plugin configuration:
```tsx
createFrontendPlugin({
id: 'tech-radar',
pluginId: 'tech-radar',
// ...
featureFlags: [{ name: 'tech-radar' }],
// ...
@@ -32,7 +32,7 @@ This is how to create a minimal plugin:
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
export const examplePlugin = createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [],
});
```
@@ -98,7 +98,7 @@ const exampleNavItem = NavItemBlueprint.make({
// The same plugin as above, now with the extensions added
export const examplePlugin = createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [examplePage, exampleNavItem],
// We can also make routes available to other plugins.
// highlight-start
@@ -174,7 +174,7 @@ const exampleApi = ApiBlueprint.make({
/* Omitted definitions for examplePage, exampleNavItem, and rootRouteRef. */
export const examplePlugin = createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [
// highlight-add-next-line
exampleApi,
@@ -210,7 +210,7 @@ const exampleEntityContent = EntityContentBlueprint.make({
});
export const examplePlugin = createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [
// highlight-add-next-line
exampleEntityContent,
@@ -42,7 +42,9 @@ In order to migrate the actual definition of the plugin you need to recreate the
import { convertLegacyRouteRefs } from '@backstage/core-compat-api';
export default createFrontendPlugin({
id: 'my-plugin',
// The plugin ID is now provided as `pluginId` instead of `id`
/* highlight-next-line */
pluginId: 'my-plugin',
// bind all the extensions to the plugin
/* highlight-next-line */
extensions: [/* APIs will go here, but don't worry about those yet */],
@@ -138,7 +140,7 @@ Then add the `fooPage` extension to the plugin:
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
export default createFrontendPlugin({
id: 'my-plugin',
pluginId: 'my-plugin',
// bind all the extensions to the plugin
/* highlight-remove-next-line */
extensions: [],
@@ -229,7 +231,7 @@ Finally, let's add the `exampleWorkApi` extension to the plugin:
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
export default createFrontendPlugin({
id: 'my-plugin',
pluginId: 'my-plugin',
// bind all the extensions to the plugin
/* highlight-remove-next-line */
extensions: [fooPage],
@@ -80,7 +80,7 @@ const workApi = ApiBlueprint.make({
* @public
*/
export default createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [exampleWorkApi],
});
```
@@ -28,6 +28,6 @@ export const ExamplePage = PageBlueprint.make({
/** @public */
export const examplePlugin = createFrontendPlugin({
id: 'example',
pluginId: 'example',
extensions: [ExamplePage],
});
@@ -131,7 +131,7 @@ const ExternalPage = PageBlueprint.make({
});
export const pagesPlugin = createFrontendPlugin({
id: 'pages',
pluginId: 'pages',
// routes: {
// index: indexRouteRef,
// // reference in config:
@@ -304,7 +304,7 @@ export function collectLegacyRoutes(
for (const [plugin, extensions] of pluginExtensions) {
output.push(
createFrontendPlugin({
id: plugin.getId(),
pluginId: plugin.getId(),
extensions: [
...extensions,
...Array.from(plugin.getApis()).map(factory =>
@@ -85,7 +85,7 @@ export function toLegacyPlugin(
// TODO: Currently a very naive implementation, may need some more work
function toNewPlugin(plugin: LegacyBackstagePlugin): NewFrontendPlugin {
return createNewPlugin({
id: plugin.getId(),
pluginId: plugin.getId(),
});
}
@@ -32,7 +32,7 @@ export function convertLegacyPlugin(
ApiBlueprint.make({ name: factory.api.id, params: { factory } }),
);
return createFrontendPlugin({
id: legacyPlugin.getId(),
pluginId: legacyPlugin.getId(),
featureFlags: [...legacyPlugin.getFeatureFlags()],
routes: convertLegacyRouteRefs(legacyPlugin.routes ?? {}),
externalRoutes: convertLegacyRouteRefs(legacyPlugin.externalRoutes ?? {}),
@@ -35,7 +35,7 @@ describe('collectRouteIds', () => {
const collected = collectRouteIds([
createFrontendPlugin({
id: 'test',
pluginId: 'test',
routes: { ref },
externalRoutes: { extRef },
}),
@@ -81,7 +81,7 @@ function createTestExtension(options: {
function routeInfoFromExtensions(extensions: ExtensionDefinition[]) {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions,
});
@@ -100,7 +100,7 @@ describe('resolveAppNodeSpecs', () => {
it('should override attachment points', () => {
const b = makeExt('b');
const pluginA = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [makeExtDef('a')],
});
expect(
@@ -135,7 +135,7 @@ describe('resolveAppNodeSpecs', () => {
const a = makeExt('test/a');
const b = makeExt('test/b');
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [makeExtDef('a'), makeExtDef('b')],
});
expect(
@@ -182,7 +182,7 @@ describe('resolveAppNodeSpecs', () => {
const b = makeExt('b', 'disabled');
expect(
resolveAppNodeSpecs({
features: [createFrontendPlugin({ id: 'empty', extensions: [] })],
features: [createFrontendPlugin({ pluginId: 'empty', extensions: [] })],
builtinExtensions: [a, b],
parameters: [
{
@@ -221,7 +221,7 @@ describe('resolveAppNodeSpecs', () => {
const g = makeExt('g', 'disabled');
expect(
resolveAppNodeSpecs({
features: [createFrontendPlugin({ id: 'empty', extensions: [] })],
features: [createFrontendPlugin({ pluginId: 'empty', extensions: [] })],
builtinExtensions: [a, b, c, d, e, f, g],
parameters: [
{ id: 'e', disabled: false },
@@ -277,7 +277,7 @@ describe('resolveAppNodeSpecs', () => {
it('should apply module overrides', () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [makeExtDef('a'), makeExtDef('b')],
});
const aOverride = makeExt('test/a', 'enabled', 'other');
@@ -329,7 +329,7 @@ describe('resolveAppNodeSpecs', () => {
const result = resolveAppNodeSpecs({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
makeExtDef('a', 'disabled'),
makeExtDef('b', 'disabled'),
@@ -364,7 +364,7 @@ describe('resolveAppNodeSpecs', () => {
resolveAppNodeSpecs({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [makeExtDef('forbidden')],
}),
],
@@ -382,7 +382,7 @@ describe('resolveAppNodeSpecs', () => {
resolveAppNodeSpecs({
features: [
createFrontendPlugin({
id: 'forbidden',
pluginId: 'forbidden',
extensions: [],
}),
createFrontendModule({
@@ -45,7 +45,7 @@ describe('createSpecializedApp', () => {
const app = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -66,7 +66,7 @@ describe('createSpecializedApp', () => {
const app = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -78,7 +78,7 @@ describe('createSpecializedApp', () => {
],
}),
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -102,7 +102,7 @@ describe('createSpecializedApp', () => {
config: mockApis.config({ data: { test: 'foo' } }),
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -128,7 +128,7 @@ describe('createSpecializedApp', () => {
const app = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
featureFlags: [{ name: 'a' }, { name: 'b' }],
extensions: [
createExtension({
@@ -250,7 +250,7 @@ describe('createSpecializedApp', () => {
const app = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'first',
pluginId: 'first',
extensions: [
ApiBlueprint.make({
params: {
@@ -266,7 +266,7 @@ describe('createSpecializedApp', () => {
],
}),
createFrontendPlugin({
id: 'test',
pluginId: 'test',
featureFlags: [{ name: 'a' }, { name: 'b' }],
extensions: [
createExtension({
@@ -321,7 +321,7 @@ describe('createSpecializedApp', () => {
]),
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -368,7 +368,7 @@ describe('createSpecializedApp', () => {
const { tree } = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -446,7 +446,7 @@ describe('createSpecializedApp', () => {
const extRouteRef = createExternalRouteRef();
const pluginA = createFrontendPlugin({
id: 'a',
pluginId: 'a',
externalRoutes: {
ext: extRouteRef,
},
@@ -489,7 +489,7 @@ describe('createSpecializedApp', () => {
],
});
const pluginB = createFrontendPlugin({
id: 'b',
pluginId: 'b',
routes: {
root: routeRef,
},
@@ -531,7 +531,7 @@ describe('createSpecializedApp', () => {
createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
name: 'root',
@@ -611,7 +611,7 @@ describe('createSpecializedApp', () => {
const app = createSpecializedApp({
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -55,7 +55,7 @@ describe('createApp', () => {
}),
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
ThemeBlueprint.make({
name: 'derp',
@@ -84,7 +84,7 @@ describe('createApp', () => {
configLoader: async () => ({ config: mockApis.config() }),
features: [
createFrontendPlugin({
id: duplicatedFeatureId,
pluginId: duplicatedFeatureId,
extensions: [
PageBlueprint.make({
params: {
@@ -95,7 +95,7 @@ describe('createApp', () => {
],
}),
createFrontendPlugin({
id: duplicatedFeatureId,
pluginId: duplicatedFeatureId,
extensions: [
PageBlueprint.make({
params: {
@@ -128,7 +128,7 @@ describe('createApp', () => {
return {
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
PageBlueprint.make({
params: {
@@ -193,7 +193,7 @@ describe('createApp', () => {
],
}),
createFrontendPlugin({
id: 'test',
pluginId: 'test',
featureFlags: [{ name: 'test-1' }],
extensions: [
createExtension({
@@ -219,7 +219,7 @@ describe('createApp', () => {
],
}),
createFrontendPlugin({
id: 'other',
pluginId: 'other',
featureFlags: [{ name: 'test-2' }],
extensions: [],
}),
@@ -241,7 +241,7 @@ describe('createApp', () => {
features: [
appPlugin,
createFrontendPlugin({
id: 'my-plugin',
pluginId: 'my-plugin',
extensions: [
PageBlueprint.make({
params: {
@@ -402,7 +402,7 @@ describe('createApp', () => {
features: [
appPlugin,
createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [
PageBlueprint.make({
name: 'test-page',
@@ -45,7 +45,7 @@ describe('discoverAvailableFeatures', () => {
});
it('should discover a plugin', () => {
const testPlugin = createFrontendPlugin({ id: 'test' });
const testPlugin = createFrontendPlugin({ pluginId: 'test' });
globalSpy.mockReturnValue({
modules: [{ default: testPlugin }],
});
@@ -86,9 +86,9 @@ describe('discoverAvailableFeatures', () => {
});
it('should discover multiple plugins', () => {
const test1Plugin = createFrontendPlugin({ id: 'test1' });
const test2Plugin = createFrontendPlugin({ id: 'test2' });
const test3Plugin = createFrontendPlugin({ id: 'test3' });
const test1Plugin = createFrontendPlugin({ pluginId: 'test1' });
const test2Plugin = createFrontendPlugin({ pluginId: 'test2' });
const test3Plugin = createFrontendPlugin({ pluginId: 'test3' });
globalSpy.mockReturnValue({
modules: [
{ default: test1Plugin },
@@ -38,7 +38,7 @@ describe('resolveAsyncFeatures', () => {
config: mockApis.config(),
features: [
createFrontendPlugin({
id: 'test-feature',
pluginId: 'test-feature',
extensions: [
PageBlueprint.make({
params: {
@@ -80,7 +80,7 @@ describe('resolveAsyncFeatures', () => {
return {
features: [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
PageBlueprint.make({
params: {
@@ -145,7 +145,7 @@ describe('resolveAsyncFeatures', () => {
async loader({ config: _ }) {
return [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
PageBlueprint.make({
params: {
@@ -191,7 +191,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValue({
default: createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [],
}),
});
@@ -311,13 +311,13 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-1',
pluginId: 'plugin-1',
extensions: [],
}),
});
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [],
}),
});
@@ -428,13 +428,13 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [],
}),
});
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'test-plugin-alpha',
pluginId: 'test-plugin-alpha',
extensions: [],
}),
});
@@ -527,7 +527,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [],
}),
});
@@ -591,7 +591,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValue({
default: createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [],
}),
});
@@ -640,7 +640,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValue({
default: createFrontendPlugin({
id: 'test-plugin',
pluginId: 'test-plugin',
extensions: [],
}),
});
@@ -746,7 +746,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce(undefined);
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [],
}),
});
@@ -876,7 +876,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
});
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [],
}),
});
@@ -989,7 +989,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [],
}),
});
@@ -1099,7 +1099,7 @@ describe('dynamicFrontendFeaturesLoader', () => {
mocks.federation.get.mockReturnValueOnce({
default: createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [],
}),
});
+20 -1
View File
@@ -774,6 +774,25 @@ export function createFrontendPlugin<
MakeSortedExtensionsMap<TExtensions[number], TId>
>;
// @public @deprecated (undocumented)
export function createFrontendPlugin<
TId extends string,
TRoutes extends AnyRoutes = {},
TExternalRoutes extends AnyExternalRoutes = {},
TExtensions extends readonly ExtensionDefinition[] = [],
>(
options: Omit<
PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,
'pluginId'
> & {
id: string;
},
): FrontendPlugin<
TRoutes,
TExternalRoutes,
MakeSortedExtensionsMap<TExtensions[number], TId>
>;
// @public
export function createRouteRef<
TParams extends
@@ -1495,7 +1514,7 @@ export interface PluginOptions<
// (undocumented)
featureFlags?: FeatureFlagConfig[];
// (undocumented)
id: TId;
pluginId: TId;
// (undocumented)
routes?: TRoutes;
}
@@ -60,7 +60,7 @@ describe('createFrontendFeatureLoader', () => {
);
return [
createFrontendPlugin({
id: `${pluginIdPrefix}-1`,
pluginId: `${pluginIdPrefix}-1`,
extensions: [
createExtension({
name: '1',
@@ -76,7 +76,7 @@ describe('createFrontendFeatureLoader', () => {
],
}) as FrontendFeature | FrontendFeatureLoader,
createFrontendPlugin({
id: `${pluginIdPrefix}-2`,
pluginId: `${pluginIdPrefix}-2`,
extensions: [
createExtension({
name: '2',
@@ -92,7 +92,7 @@ describe('createFrontendFeatureLoader', () => {
],
}) as FrontendFeature | FrontendFeatureLoader,
createFrontendPlugin({
id: `${pluginIdPrefix}-output`,
pluginId: `${pluginIdPrefix}-output`,
extensions: [
createExtension({
name: 'output',
@@ -166,7 +166,7 @@ describe('createFrontendFeatureLoader', () => {
async loader(_) {
return [
createFrontendPlugin({
id: 'plugin-0',
pluginId: 'plugin-0',
extensions: [
createExtension({
name: '0',
@@ -184,7 +184,7 @@ describe('createFrontendFeatureLoader', () => {
createFrontendFeatureLoader({
async *loader(__) {
yield createFrontendPlugin({
id: 'plugin-1',
pluginId: 'plugin-1',
extensions: [
createExtension({
name: '1',
@@ -202,7 +202,7 @@ describe('createFrontendFeatureLoader', () => {
yield createFrontendFeatureLoader({
loader: async ___ => [
createFrontendPlugin({
id: 'plugin-2',
pluginId: 'plugin-2',
extensions: [
createExtension({
name: '2',
@@ -222,7 +222,7 @@ describe('createFrontendFeatureLoader', () => {
},
}),
createFrontendPlugin({
id: 'plugin-output',
pluginId: 'plugin-output',
extensions: [
createExtension({
name: 'output',
@@ -278,7 +278,7 @@ describe('createFrontendFeatureLoader', () => {
[
nestedFeatureLoaderHolder.loader,
createFrontendPlugin({
id: 'plugin',
pluginId: 'plugin',
extensions: [
createExtension({
name: 'output',
@@ -319,7 +319,7 @@ describe('createFrontendFeatureLoader', () => {
it('should support multiple output formats', async () => {
const feature = createFrontendPlugin({
id: 'test',
pluginId: 'test',
});
const dynamicFeature = Promise.resolve({ default: feature });
@@ -411,7 +411,7 @@ describe('createFrontendFeatureLoader', () => {
it('should limit feature loading recursion', async () => {
const plugin = createFrontendPlugin({
id: 'plugin',
pluginId: 'plugin',
extensions: [
createExtension({
name: 'output',
@@ -134,6 +134,13 @@ function createTestAppRoot({
describe('createFrontendPlugin', () => {
it('should create an empty plugin', () => {
const plugin = createFrontendPlugin({ pluginId: 'test' });
expect(plugin).toBeDefined();
expect(String(plugin)).toBe('Plugin{id=test}');
});
it('should create an empty plugin with deprecated id option', () => {
const plugin = createFrontendPlugin({ id: 'test' });
expect(plugin).toBeDefined();
@@ -142,7 +149,7 @@ describe('createFrontendPlugin', () => {
it('should create a plugin with extension instances', async () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [Extension1, Extension2, outputExtension],
});
expect(plugin).toBeDefined();
@@ -189,7 +196,7 @@ describe('createFrontendPlugin', () => {
it('should create a plugin with nested extension instances', async () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [Extension1, Extension2, Extension3, Child, outputExtension],
});
expect(plugin).toBeDefined();
@@ -221,7 +228,7 @@ describe('createFrontendPlugin', () => {
it('should create a plugin with nested extension instances and multiple children', async () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
Extension1,
Extension2,
@@ -254,14 +261,14 @@ describe('createFrontendPlugin', () => {
it('should throw on duplicate extensions', async () => {
expect(() =>
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [Extension1, Extension1],
}),
).toThrow("Plugin 'test' provided duplicate extensions: test/1");
expect(() =>
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [
Extension1,
Extension2,
@@ -277,7 +284,7 @@ describe('createFrontendPlugin', () => {
describe('overrides', () => {
it('should return a plugin instance with the correct namespace', () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [Extension1, Extension2],
});
@@ -308,7 +315,7 @@ describe('createFrontendPlugin', () => {
it('should allow overriding extensions that have a matching ID, while keeping old extensions that do not have overlapping IDs', async () => {
const plugin = createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions: [Extension1, Extension2, outputExtension],
});
@@ -51,7 +51,7 @@ export interface PluginOptions<
TExternalRoutes extends AnyExternalRoutes,
TExtensions extends readonly ExtensionDefinition[],
> {
id: TId;
pluginId: TId;
routes?: TRoutes;
externalRoutes?: TExternalRoutes;
extensions?: TExtensions;
@@ -70,7 +70,49 @@ export function createFrontendPlugin<
TRoutes,
TExternalRoutes,
MakeSortedExtensionsMap<TExtensions[number], TId>
>;
/**
* @public
* @deprecated The `id` option is deprecated, use `pluginId` instead.
*/
export function createFrontendPlugin<
TId extends string,
TRoutes extends AnyRoutes = {},
TExternalRoutes extends AnyExternalRoutes = {},
TExtensions extends readonly ExtensionDefinition[] = [],
>(
options: Omit<
PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,
'pluginId'
> & { id: string },
): FrontendPlugin<
TRoutes,
TExternalRoutes,
MakeSortedExtensionsMap<TExtensions[number], TId>
>;
export function createFrontendPlugin<
TId extends string,
TRoutes extends AnyRoutes = {},
TExternalRoutes extends AnyExternalRoutes = {},
TExtensions extends readonly ExtensionDefinition[] = [],
>(
options:
| PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>
| (Omit<
PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,
'pluginId'
> & { id: string }),
): FrontendPlugin<
TRoutes,
TExternalRoutes,
MakeSortedExtensionsMap<TExtensions[number], TId>
> {
const pluginId = 'pluginId' in options ? options.pluginId : options.id;
if (!pluginId) {
throw new Error(
"Either 'id' or 'pluginId' must be provided to createFrontendPlugin",
);
}
const extensions = new Array<Extension<any>>();
const extensionDefinitionsById = new Map<
string,
@@ -79,11 +121,11 @@ export function createFrontendPlugin<
for (const def of options.extensions ?? []) {
const internal = OpaqueExtensionDefinition.toInternal(def);
const ext = resolveExtensionDefinition(def, { namespace: options.id });
const ext = resolveExtensionDefinition(def, { namespace: pluginId });
extensions.push(ext);
extensionDefinitionsById.set(ext.id, {
...internal,
namespace: options.id,
namespace: pluginId,
});
}
@@ -96,14 +138,14 @@ export function createFrontendPlugin<
);
// TODO(Rugvip): This could provide some more information about the kind + name of the extensions
throw new Error(
`Plugin '${options.id}' provided duplicate extensions: ${duplicates.join(
`Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(
', ',
)}`,
);
}
return OpaqueFrontendPlugin.createInstance('v1', {
id: options.id,
id: pluginId,
routes: options.routes ?? ({} as TRoutes),
externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),
featureFlags: options.featureFlags ?? [],
@@ -112,28 +154,29 @@ export function createFrontendPlugin<
const ext = extensionDefinitionsById.get(id);
if (!ext) {
throw new Error(
`Attempted to get non-existent extension '${id}' from plugin '${options.id}'`,
`Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,
);
}
return ext;
},
toString() {
return `Plugin{id=${options.id}}`;
return `Plugin{id=${pluginId}}`;
},
withOverrides(overrides) {
const overriddenExtensionIds = new Set(
overrides.extensions.map(
e => resolveExtensionDefinition(e, { namespace: options.id }).id,
e => resolveExtensionDefinition(e, { namespace: pluginId }).id,
),
);
const nonOverriddenExtensions = (options.extensions ?? []).filter(
e =>
!overriddenExtensionIds.has(
resolveExtensionDefinition(e, { namespace: options.id }).id,
resolveExtensionDefinition(e, { namespace: pluginId }).id,
),
);
return createFrontendPlugin({
...options,
pluginId,
extensions: [...nonOverriddenExtensions, ...overrides.extensions],
});
},
@@ -198,7 +198,7 @@ export function renderInTestApp(
const features: FrontendFeature[] = [
createFrontendPlugin({
id: 'test',
pluginId: 'test',
extensions,
}),
appPluginOverride,
+1 -1
View File
@@ -227,7 +227,7 @@ const apiDocsApisEntityContent = EntityContentBlueprint.make({
});
export default createFrontendPlugin({
id: 'api-docs',
pluginId: 'api-docs',
routes: {
root: convertLegacyRouteRef(rootRoute),
},
+1 -1
View File
@@ -45,6 +45,6 @@ export const appVisualizerNavItem = NavItemBlueprint.make({
/** @public */
export const visualizerPlugin = createFrontendPlugin({
id: 'app-visualizer',
pluginId: 'app-visualizer',
extensions: [appVisualizerPage, appVisualizerNavItem],
});
+1 -1
View File
@@ -41,7 +41,7 @@ import { apis } from './defaultApis';
/** @public */
export const appPlugin = createFrontendPlugin({
id: 'app',
pluginId: 'app',
extensions: [
...apis,
App,
+1 -1
View File
@@ -86,7 +86,7 @@ const CatalogGraphPage = PageBlueprint.makeWithOverrides({
});
export default createFrontendPlugin({
id: 'catalog-graph',
pluginId: 'catalog-graph',
routes: {
catalogGraph: convertLegacyRouteRef(catalogGraphRouteRef),
},
+1 -1
View File
@@ -86,7 +86,7 @@ const catalogImportApi = ApiBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'catalog-import',
pluginId: 'catalog-import',
extensions: [catalogImportApi, catalogImportPage],
routes: {
importPage: convertLegacyRouteRef(rootRouteRef),
@@ -73,7 +73,7 @@ export const catalogUnprocessedEntitiesNavItem = NavItemBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'catalog-unprocessed-entities',
pluginId: 'catalog-unprocessed-entities',
routes: {
root: convertLegacyRouteRef(rootRouteRef),
},
+1 -1
View File
@@ -38,7 +38,7 @@ import contextMenuItems from './contextMenuItems';
/** @alpha */
export default createFrontendPlugin({
id: 'catalog',
pluginId: 'catalog',
routes: convertLegacyRouteRefs({
catalogIndex: rootRouteRef,
catalogEntity: entityRouteRef,
+1 -1
View File
@@ -70,7 +70,7 @@ export const devToolsNavItem = NavItemBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'devtools',
pluginId: 'devtools',
routes: {
root: convertLegacyRouteRef(rootRouteRef),
},
+1 -1
View File
@@ -67,6 +67,6 @@ const homePage = PageBlueprint.makeWithOverrides({
* @alpha
*/
export default createFrontendPlugin({
id: 'home',
pluginId: 'home',
extensions: [homePage],
});
+1 -1
View File
@@ -27,7 +27,7 @@ import {
} from './apis';
export default createFrontendPlugin({
id: 'kubernetes',
pluginId: 'kubernetes',
extensions: [
kubernetesPage,
entityKubernetesContent,
+1 -1
View File
@@ -53,7 +53,7 @@ const api = ApiBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'notifications',
pluginId: 'notifications',
routes: convertLegacyRouteRefs({
root: rootRouteRef,
}),
+1 -1
View File
@@ -72,7 +72,7 @@ const EntityUserProfileCard = EntityCardBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'org',
pluginId: 'org',
extensions: [
EntityGroupProfileCard,
EntityMembersListCard,
+1 -1
View File
@@ -38,7 +38,7 @@ import { formDecoratorsApi } from './api';
/** @alpha */
export default createFrontendPlugin({
id: 'scaffolder',
pluginId: 'scaffolder',
routes: convertLegacyRouteRefs({
root: rootRouteRef,
selectedTemplate: selectedTemplateRouteRef,
+1 -1
View File
@@ -278,7 +278,7 @@ export const searchNavItem = NavItemBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'search',
pluginId: 'search',
extensions: [searchApi, searchPage, searchNavItem],
routes: convertLegacyRouteRefs({
root: rootRouteRef,
+1 -1
View File
@@ -44,6 +44,6 @@ const api = ApiBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'signals',
pluginId: 'signals',
extensions: [api],
});
+1 -1
View File
@@ -235,7 +235,7 @@ const techDocsNavItem = NavItemBlueprint.make({
/** @alpha */
export default createFrontendPlugin({
id: 'techdocs',
pluginId: 'techdocs',
extensions: [
techDocsClientApi,
techDocsStorageApi,
+1 -1
View File
@@ -68,7 +68,7 @@ export const settingsNavItem = NavItemBlueprint.make({
* @alpha
*/
export default createFrontendPlugin({
id: 'user-settings',
pluginId: 'user-settings',
extensions: [userSettingsPage, settingsNavItem],
routes: convertLegacyRouteRefs({
root: settingsRouteRef,