@backstage/core-compat-api 0.2.8-next.3 → 0.2.9-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/collectLegacyRoutes.esm.js +33 -25
- package/dist/collectLegacyRoutes.esm.js.map +1 -1
- package/dist/compatWrapper/BackwardsCompatProvider.esm.js +2 -2
- package/dist/compatWrapper/BackwardsCompatProvider.esm.js.map +1 -1
- package/dist/convertLegacyApp.esm.js +14 -17
- package/dist/convertLegacyApp.esm.js.map +1 -1
- package/dist/convertLegacyPageExtension.esm.js +31 -0
- package/dist/convertLegacyPageExtension.esm.js.map +1 -0
- package/dist/convertLegacyPlugin.esm.js +18 -0
- package/dist/convertLegacyPlugin.esm.js.map +1 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/package.json +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @backstage/core-compat-api
|
|
2
2
|
|
|
3
|
+
## 0.2.9-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fec8b57: Updated exports to use the new type parameters for extensions and extension blueprints.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/frontend-plugin-api@0.8.0-next.0
|
|
10
|
+
- @backstage/core-plugin-api@1.9.3
|
|
11
|
+
- @backstage/version-bridge@1.0.8
|
|
12
|
+
|
|
13
|
+
## 0.2.8
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`.
|
|
18
|
+
- fe1fbb2: Migrating usages of the deprecated `createExtension` `v1` format to the newer `v2` format, and old `create*Extension` extension creators to blueprints.
|
|
19
|
+
- 16cf96c: Both `compatWrapper` and `convertLegacyRouteRef` now support converting from the new system to the old.
|
|
20
|
+
- 519b8e0: Added new utilities for converting legacy plugins and extensions to the new system. The `convertLegacyPlugin` option will convert an existing plugin to the new system, although you need to supply extensions for the plugin yourself. To help out with this, there is also a new `convertLegacyPageExtension` which converts an existing page extension to the new system.
|
|
21
|
+
- 6349099: Added config input type to the extensions
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @backstage/frontend-plugin-api@0.7.0
|
|
24
|
+
- @backstage/core-plugin-api@1.9.3
|
|
25
|
+
- @backstage/version-bridge@1.0.8
|
|
26
|
+
|
|
3
27
|
## 0.2.8-next.3
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getComponentData } from '@backstage/core-plugin-api';
|
|
2
|
-
import {
|
|
2
|
+
import { PageBlueprint, createExtensionInput, coreExtensionData, createFrontendPlugin, ApiBlueprint, createExtension } from '@backstage/frontend-plugin-api';
|
|
3
3
|
import React, { Children, isValidElement } from 'react';
|
|
4
4
|
import { Route, Routes } from 'react-router-dom';
|
|
5
5
|
import { convertLegacyRouteRef, convertLegacyRouteRefs } from './convertLegacyRouteRef.esm.js';
|
|
@@ -12,19 +12,23 @@ function makeRoutingShimExtension(options) {
|
|
|
12
12
|
name,
|
|
13
13
|
attachTo: { id: parentExtensionId, input: "childRoutingShims" },
|
|
14
14
|
inputs: {
|
|
15
|
-
childRoutingShims: createExtensionInput(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
childRoutingShims: createExtensionInput([
|
|
16
|
+
coreExtensionData.routePath.optional(),
|
|
17
|
+
coreExtensionData.routeRef.optional()
|
|
18
|
+
])
|
|
19
19
|
},
|
|
20
|
-
output:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
factory
|
|
25
|
-
routePath
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
output: [
|
|
21
|
+
coreExtensionData.routePath.optional(),
|
|
22
|
+
coreExtensionData.routeRef.optional()
|
|
23
|
+
],
|
|
24
|
+
*factory() {
|
|
25
|
+
if (routePath !== void 0) {
|
|
26
|
+
yield coreExtensionData.routePath(routePath);
|
|
27
|
+
}
|
|
28
|
+
if (routeRef) {
|
|
29
|
+
yield coreExtensionData.routeRef(convertLegacyRouteRef(routeRef));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
28
32
|
});
|
|
29
33
|
}
|
|
30
34
|
function visitRouteChildren(options) {
|
|
@@ -115,19 +119,23 @@ function collectLegacyRoutes(flatRoutesElement) {
|
|
|
115
119
|
const pageExtensionName = extensions.length ? getUniqueName() : void 0;
|
|
116
120
|
const pageExtensionId = `page:${plugin.getId()}${pageExtensionName ? `/${pageExtensionName}` : pageExtensionName}`;
|
|
117
121
|
extensions.push(
|
|
118
|
-
|
|
122
|
+
PageBlueprint.makeWithOverrides({
|
|
119
123
|
name: pageExtensionName,
|
|
120
|
-
defaultPath: path[0] === "/" ? path.slice(1) : path,
|
|
121
|
-
routeRef: routeRef ? convertLegacyRouteRef(routeRef) : void 0,
|
|
122
124
|
inputs: {
|
|
123
|
-
childRoutingShims: createExtensionInput(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
childRoutingShims: createExtensionInput([
|
|
126
|
+
coreExtensionData.routePath.optional(),
|
|
127
|
+
coreExtensionData.routeRef.optional()
|
|
128
|
+
])
|
|
127
129
|
},
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
factory(originalFactory, { inputs: _inputs }) {
|
|
131
|
+
return originalFactory({
|
|
132
|
+
defaultPath: path[0] === "/" ? path.slice(1) : path,
|
|
133
|
+
routeRef: routeRef ? convertLegacyRouteRef(routeRef) : void 0,
|
|
134
|
+
loader: async () => compatWrapper(
|
|
135
|
+
route.props.children ? /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, { path: "*", element: routeElement }, /* @__PURE__ */ React.createElement(Route, { path: "*", element: route.props.children }))) : routeElement
|
|
136
|
+
)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
131
139
|
})
|
|
132
140
|
);
|
|
133
141
|
visitRouteChildren({
|
|
@@ -143,12 +151,12 @@ function collectLegacyRoutes(flatRoutesElement) {
|
|
|
143
151
|
}
|
|
144
152
|
);
|
|
145
153
|
return Array.from(pluginExtensions).map(
|
|
146
|
-
([plugin, extensions]) =>
|
|
154
|
+
([plugin, extensions]) => createFrontendPlugin({
|
|
147
155
|
id: plugin.getId(),
|
|
148
156
|
extensions: [
|
|
149
157
|
...extensions,
|
|
150
158
|
...Array.from(plugin.getApis()).map(
|
|
151
|
-
(factory) =>
|
|
159
|
+
(factory) => ApiBlueprint.make({ namespace: factory.api.id, params: { factory } })
|
|
152
160
|
)
|
|
153
161
|
],
|
|
154
162
|
routes: convertLegacyRouteRefs(plugin.routes ?? {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectLegacyRoutes.esm.js","sources":["../src/collectLegacyRoutes.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AnyRouteRefParams,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n getComponentData,\n} from '@backstage/core-plugin-api';\nimport {\n BackstagePlugin,\n ExtensionDefinition,\n coreExtensionData,\n createApiExtension,\n createExtension,\n createExtensionInput,\n createPageExtension,\n createPlugin,\n} from '@backstage/frontend-plugin-api';\nimport React, { Children, ReactNode, isValidElement } from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport {\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from './convertLegacyRouteRef';\nimport { compatWrapper } from './compatWrapper';\n\n/*\n\n# Legacy interoperability\n\nUse-cases (prioritized):\n 1. Slowly migrate over an existing app to DI, piece by piece\n 2. Use a legacy plugin in a new DI app\n 3. Use DI in an existing legacy app\n\nStarting point: use-case #1\n\nPotential solutions:\n 1. Codemods (we're not considering this for now)\n 2. Legacy apps are migrated bottom-up, i.e. keep legacy root, replace pages with DI\n 3. Legacy apps are migrated top-down i.e. switch out base to DI, legacy adapter allows for usage of existing app structure\n\nChosen path: #3\n\nExisting tasks:\n - Adopters can migrate their existing app gradually (~4)\n - Example-app uses legacy base with DI adapters\n - Create an API that lets you inject DI into existing apps - working assumption is that this is enough\n - Adopters can use legacy plugins in DI through adapters (~8)\n - App-next uses DI base with legacy adapters\n - Create a legacy adapter that is able to take an existing extension tree\n\n*/\n\n// Creates a shim extension whose purpose is to build up the tree (anchored at\n// the root page) of paths/routeRefs so that the app can bind them properly.\nfunction makeRoutingShimExtension(options: {\n name: string;\n parentExtensionId: string;\n routePath?: string;\n routeRef?: RouteRef;\n}) {\n const { name, parentExtensionId, routePath, routeRef } = options;\n return createExtension({\n kind: 'routing-shim',\n name,\n attachTo: { id: parentExtensionId, input: 'childRoutingShims' },\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n output: {\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n },\n factory: () => ({\n routePath,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n }),\n });\n}\n\nfunction visitRouteChildren(options: {\n children: ReactNode;\n parentExtensionId: string;\n context: {\n pluginId: string;\n extensions: ExtensionDefinition<any, any>[];\n getUniqueName: () => string;\n discoverPlugin: (plugin: LegacyBackstagePlugin) => void;\n };\n}): void {\n const { children, parentExtensionId, context } = options;\n const { pluginId, extensions, getUniqueName, discoverPlugin } = context;\n\n Children.forEach(children, node => {\n if (!isValidElement(node)) {\n return;\n }\n\n const plugin = getComponentData<LegacyBackstagePlugin>(node, 'core.plugin');\n const routeRef = getComponentData<RouteRef<AnyRouteRefParams>>(\n node,\n 'core.mountPoint',\n );\n const routePath: string | undefined = node.props?.path;\n\n if (plugin) {\n // We just mark the plugin as discovered, but don't change the context\n discoverPlugin(plugin);\n }\n\n let nextParentExtensionId = parentExtensionId;\n if (routeRef || routePath) {\n const nextParentExtensionName = getUniqueName();\n nextParentExtensionId = `routing-shim:${pluginId}/${nextParentExtensionName}`;\n extensions.push(\n makeRoutingShimExtension({\n name: nextParentExtensionName,\n parentExtensionId,\n routePath,\n routeRef,\n }),\n );\n }\n\n visitRouteChildren({\n children: node.props.children,\n parentExtensionId: nextParentExtensionId,\n context,\n });\n });\n}\n\n/** @internal */\nexport function collectLegacyRoutes(\n flatRoutesElement: JSX.Element,\n): BackstagePlugin[] {\n const pluginExtensions = new Map<\n LegacyBackstagePlugin,\n ExtensionDefinition<any, any>[]\n >();\n\n const getUniqueName = (() => {\n let currentIndex = 1;\n return () => String(currentIndex++);\n })();\n\n const getPluginExtensions = (plugin: LegacyBackstagePlugin) => {\n let extensions = pluginExtensions.get(plugin);\n if (!extensions) {\n extensions = [];\n pluginExtensions.set(plugin, extensions);\n }\n return extensions;\n };\n\n React.Children.forEach(\n flatRoutesElement.props.children,\n (route: ReactNode) => {\n // TODO(freben): Handle feature flag and permissions framework wrapper elements\n if (!React.isValidElement(route)) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found element of type ${typeof route}.`,\n );\n }\n if (route.type !== Route) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found ${route.type}.`,\n );\n }\n const routeElement = route.props.element;\n const path: string | undefined = route.props.path;\n const plugin = getComponentData<LegacyBackstagePlugin>(\n routeElement,\n 'core.plugin',\n );\n const routeRef = getComponentData<RouteRef>(\n routeElement,\n 'core.mountPoint',\n );\n if (!plugin) {\n throw new Error(\n // TODO(vinzscam): add See <link-to-app-migration-docs> for more info\n `Route with path ${path} has en element that can not be converted as it does not belong to a plugin. Make sure that the top-level React element of the element prop is an extension from a Backstage plugin, or remove the Route completely.`,\n );\n }\n if (path === undefined) {\n throw new Error(\n `Route element inside FlatRoutes had no path prop value given`,\n );\n }\n\n const extensions = getPluginExtensions(plugin);\n const pageExtensionName = extensions.length ? getUniqueName() : undefined;\n const pageExtensionId = `page:${plugin.getId()}${\n pageExtensionName ? `/${pageExtensionName}` : pageExtensionName\n }`;\n\n extensions.push(\n createPageExtension({\n name: pageExtensionName,\n defaultPath: path[0] === '/' ? path.slice(1) : path,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n loader: async () =>\n compatWrapper(\n route.props.children ? (\n <Routes>\n <Route path=\"*\" element={routeElement}>\n <Route path=\"*\" element={route.props.children} />\n </Route>\n </Routes>\n ) : (\n routeElement\n ),\n ),\n }),\n );\n\n visitRouteChildren({\n children: route.props.children,\n parentExtensionId: pageExtensionId,\n context: {\n pluginId: plugin.getId(),\n extensions,\n getUniqueName,\n discoverPlugin: getPluginExtensions,\n },\n });\n },\n );\n\n return Array.from(pluginExtensions).map(([plugin, extensions]) =>\n createPlugin({\n id: plugin.getId(),\n extensions: [\n ...extensions,\n ...Array.from(plugin.getApis()).map(factory =>\n createApiExtension({ factory }),\n ),\n ],\n routes: convertLegacyRouteRefs(plugin.routes ?? {}),\n externalRoutes: convertLegacyRouteRefs(plugin.externalRoutes ?? {}),\n }),\n );\n}\n"],"names":[],"mappings":";;;;;;;AAsEA,SAAS,yBAAyB,OAK/B,EAAA;AACD,EAAA,MAAM,EAAE,IAAA,EAAM,iBAAmB,EAAA,SAAA,EAAW,UAAa,GAAA,OAAA,CAAA;AACzD,EAAA,OAAO,eAAgB,CAAA;AAAA,IACrB,IAAM,EAAA,cAAA;AAAA,IACN,IAAA;AAAA,IACA,QAAU,EAAA,EAAE,EAAI,EAAA,iBAAA,EAAmB,OAAO,mBAAoB,EAAA;AAAA,IAC9D,MAAQ,EAAA;AAAA,MACN,mBAAmB,oBAAqB,CAAA;AAAA,QACtC,SAAA,EAAW,iBAAkB,CAAA,SAAA,CAAU,QAAS,EAAA;AAAA,QAChD,QAAA,EAAU,iBAAkB,CAAA,QAAA,CAAS,QAAS,EAAA;AAAA,OAC/C,CAAA;AAAA,KACH;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,SAAA,EAAW,iBAAkB,CAAA,SAAA,CAAU,QAAS,EAAA;AAAA,MAChD,QAAA,EAAU,iBAAkB,CAAA,QAAA,CAAS,QAAS,EAAA;AAAA,KAChD;AAAA,IACA,SAAS,OAAO;AAAA,MACd,SAAA;AAAA,MACA,QAAU,EAAA,QAAA,GAAW,qBAAsB,CAAA,QAAQ,CAAI,GAAA,KAAA,CAAA;AAAA,KACzD,CAAA;AAAA,GACD,CAAA,CAAA;AACH,CAAA;AAEA,SAAS,mBAAmB,OASnB,EAAA;AACP,EAAA,MAAM,EAAE,QAAA,EAAU,iBAAmB,EAAA,OAAA,EAAY,GAAA,OAAA,CAAA;AACjD,EAAA,MAAM,EAAE,QAAA,EAAU,UAAY,EAAA,aAAA,EAAe,gBAAmB,GAAA,OAAA,CAAA;AAEhE,EAAS,QAAA,CAAA,OAAA,CAAQ,UAAU,CAAQ,IAAA,KAAA;AACjC,IAAI,IAAA,CAAC,cAAe,CAAA,IAAI,CAAG,EAAA;AACzB,MAAA,OAAA;AAAA,KACF;AAEA,IAAM,MAAA,MAAA,GAAS,gBAAwC,CAAA,IAAA,EAAM,aAAa,CAAA,CAAA;AAC1E,IAAA,MAAM,QAAW,GAAA,gBAAA;AAAA,MACf,IAAA;AAAA,MACA,iBAAA;AAAA,KACF,CAAA;AACA,IAAM,MAAA,SAAA,GAAgC,KAAK,KAAO,EAAA,IAAA,CAAA;AAElD,IAAA,IAAI,MAAQ,EAAA;AAEV,MAAA,cAAA,CAAe,MAAM,CAAA,CAAA;AAAA,KACvB;AAEA,IAAA,IAAI,qBAAwB,GAAA,iBAAA,CAAA;AAC5B,IAAA,IAAI,YAAY,SAAW,EAAA;AACzB,MAAA,MAAM,0BAA0B,aAAc,EAAA,CAAA;AAC9C,MAAwB,qBAAA,GAAA,CAAA,aAAA,EAAgB,QAAQ,CAAA,CAAA,EAAI,uBAAuB,CAAA,CAAA,CAAA;AAC3E,MAAW,UAAA,CAAA,IAAA;AAAA,QACT,wBAAyB,CAAA;AAAA,UACvB,IAAM,EAAA,uBAAA;AAAA,UACN,iBAAA;AAAA,UACA,SAAA;AAAA,UACA,QAAA;AAAA,SACD,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAEA,IAAmB,kBAAA,CAAA;AAAA,MACjB,QAAA,EAAU,KAAK,KAAM,CAAA,QAAA;AAAA,MACrB,iBAAmB,EAAA,qBAAA;AAAA,MACnB,OAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACH,CAAA;AAGO,SAAS,oBACd,iBACmB,EAAA;AACnB,EAAM,MAAA,gBAAA,uBAAuB,GAG3B,EAAA,CAAA;AAEF,EAAA,MAAM,gCAAuB,CAAA,MAAA;AAC3B,IAAA,IAAI,YAAe,GAAA,CAAA,CAAA;AACnB,IAAO,OAAA,MAAM,OAAO,YAAc,EAAA,CAAA,CAAA;AAAA,GACjC,GAAA,CAAA;AAEH,EAAM,MAAA,mBAAA,GAAsB,CAAC,MAAkC,KAAA;AAC7D,IAAI,IAAA,UAAA,GAAa,gBAAiB,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAC5C,IAAA,IAAI,CAAC,UAAY,EAAA;AACf,MAAA,UAAA,GAAa,EAAC,CAAA;AACd,MAAiB,gBAAA,CAAA,GAAA,CAAI,QAAQ,UAAU,CAAA,CAAA;AAAA,KACzC;AACA,IAAO,OAAA,UAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAA,KAAA,CAAM,QAAS,CAAA,OAAA;AAAA,IACb,kBAAkB,KAAM,CAAA,QAAA;AAAA,IACxB,CAAC,KAAqB,KAAA;AAEpB,MAAA,IAAI,CAAC,KAAA,CAAM,cAAe,CAAA,KAAK,CAAG,EAAA;AAChC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,4EAAA,EAA+E,OAAO,KAAK,CAAA,CAAA,CAAA;AAAA,SAC7F,CAAA;AAAA,OACF;AACA,MAAI,IAAA,KAAA,CAAM,SAAS,KAAO,EAAA;AACxB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,4DAAA,EAA+D,MAAM,IAAI,CAAA,CAAA,CAAA;AAAA,SAC3E,CAAA;AAAA,OACF;AACA,MAAM,MAAA,YAAA,GAAe,MAAM,KAAM,CAAA,OAAA,CAAA;AACjC,MAAM,MAAA,IAAA,GAA2B,MAAM,KAAM,CAAA,IAAA,CAAA;AAC7C,MAAA,MAAM,MAAS,GAAA,gBAAA;AAAA,QACb,YAAA;AAAA,QACA,aAAA;AAAA,OACF,CAAA;AACA,MAAA,MAAM,QAAW,GAAA,gBAAA;AAAA,QACf,YAAA;AAAA,QACA,iBAAA;AAAA,OACF,CAAA;AACA,MAAA,IAAI,CAAC,MAAQ,EAAA;AACX,QAAA,MAAM,IAAI,KAAA;AAAA;AAAA,UAER,mBAAmB,IAAI,CAAA,oNAAA,CAAA;AAAA,SACzB,CAAA;AAAA,OACF;AACA,MAAA,IAAI,SAAS,KAAW,CAAA,EAAA;AACtB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,4DAAA,CAAA;AAAA,SACF,CAAA;AAAA,OACF;AAEA,MAAM,MAAA,UAAA,GAAa,oBAAoB,MAAM,CAAA,CAAA;AAC7C,MAAA,MAAM,iBAAoB,GAAA,UAAA,CAAW,MAAS,GAAA,aAAA,EAAkB,GAAA,KAAA,CAAA,CAAA;AAChE,MAAM,MAAA,eAAA,GAAkB,CAAQ,KAAA,EAAA,MAAA,CAAO,KAAM,EAAC,GAC5C,iBAAoB,GAAA,CAAA,CAAA,EAAI,iBAAiB,CAAA,CAAA,GAAK,iBAChD,CAAA,CAAA,CAAA;AAEA,MAAW,UAAA,CAAA,IAAA;AAAA,QACT,mBAAoB,CAAA;AAAA,UAClB,IAAM,EAAA,iBAAA;AAAA,UACN,WAAA,EAAa,KAAK,CAAC,CAAA,KAAM,MAAM,IAAK,CAAA,KAAA,CAAM,CAAC,CAAI,GAAA,IAAA;AAAA,UAC/C,QAAU,EAAA,QAAA,GAAW,qBAAsB,CAAA,QAAQ,CAAI,GAAA,KAAA,CAAA;AAAA,UACvD,MAAQ,EAAA;AAAA,YACN,mBAAmB,oBAAqB,CAAA;AAAA,cACtC,SAAA,EAAW,iBAAkB,CAAA,SAAA,CAAU,QAAS,EAAA;AAAA,cAChD,QAAA,EAAU,iBAAkB,CAAA,QAAA,CAAS,QAAS,EAAA;AAAA,aAC/C,CAAA;AAAA,WACH;AAAA,UACA,QAAQ,YACN,aAAA;AAAA,YACE,KAAA,CAAM,MAAM,QACV,mBAAA,KAAA,CAAA,aAAA,CAAC,8BACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,MAAK,GAAI,EAAA,OAAA,EAAS,gCACtB,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,MAAK,GAAI,EAAA,OAAA,EAAS,MAAM,KAAM,CAAA,QAAA,EAAU,CACjD,CACF,CAEA,GAAA,YAAA;AAAA,WAEJ;AAAA,SACH,CAAA;AAAA,OACH,CAAA;AAEA,MAAmB,kBAAA,CAAA;AAAA,QACjB,QAAA,EAAU,MAAM,KAAM,CAAA,QAAA;AAAA,QACtB,iBAAmB,EAAA,eAAA;AAAA,QACnB,OAAS,EAAA;AAAA,UACP,QAAA,EAAU,OAAO,KAAM,EAAA;AAAA,UACvB,UAAA;AAAA,UACA,aAAA;AAAA,UACA,cAAgB,EAAA,mBAAA;AAAA,SAClB;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAAA,GACF,CAAA;AAEA,EAAO,OAAA,KAAA,CAAM,IAAK,CAAA,gBAAgB,CAAE,CAAA,GAAA;AAAA,IAAI,CAAC,CAAC,MAAQ,EAAA,UAAU,MAC1D,YAAa,CAAA;AAAA,MACX,EAAA,EAAI,OAAO,KAAM,EAAA;AAAA,MACjB,UAAY,EAAA;AAAA,QACV,GAAG,UAAA;AAAA,QACH,GAAG,KAAM,CAAA,IAAA,CAAK,MAAO,CAAA,OAAA,EAAS,CAAE,CAAA,GAAA;AAAA,UAAI,CAClC,OAAA,KAAA,kBAAA,CAAmB,EAAE,OAAA,EAAS,CAAA;AAAA,SAChC;AAAA,OACF;AAAA,MACA,MAAQ,EAAA,sBAAA,CAAuB,MAAO,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,MAClD,cAAgB,EAAA,sBAAA,CAAuB,MAAO,CAAA,cAAA,IAAkB,EAAE,CAAA;AAAA,KACnE,CAAA;AAAA,GACH,CAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"collectLegacyRoutes.esm.js","sources":["../src/collectLegacyRoutes.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AnyRouteRefParams,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n getComponentData,\n} from '@backstage/core-plugin-api';\nimport {\n BackstagePlugin,\n ExtensionDefinition,\n coreExtensionData,\n createExtension,\n createExtensionInput,\n createFrontendPlugin,\n ApiBlueprint,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport React, { Children, ReactNode, isValidElement } from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport {\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from './convertLegacyRouteRef';\nimport { compatWrapper } from './compatWrapper';\n\n/*\n\n# Legacy interoperability\n\nUse-cases (prioritized):\n 1. Slowly migrate over an existing app to DI, piece by piece\n 2. Use a legacy plugin in a new DI app\n 3. Use DI in an existing legacy app\n\nStarting point: use-case #1\n\nPotential solutions:\n 1. Codemods (we're not considering this for now)\n 2. Legacy apps are migrated bottom-up, i.e. keep legacy root, replace pages with DI\n 3. Legacy apps are migrated top-down i.e. switch out base to DI, legacy adapter allows for usage of existing app structure\n\nChosen path: #3\n\nExisting tasks:\n - Adopters can migrate their existing app gradually (~4)\n - Example-app uses legacy base with DI adapters\n - Create an API that lets you inject DI into existing apps - working assumption is that this is enough\n - Adopters can use legacy plugins in DI through adapters (~8)\n - App-next uses DI base with legacy adapters\n - Create a legacy adapter that is able to take an existing extension tree\n\n*/\n\n// Creates a shim extension whose purpose is to build up the tree (anchored at\n// the root page) of paths/routeRefs so that the app can bind them properly.\nfunction makeRoutingShimExtension(options: {\n name: string;\n parentExtensionId: string;\n routePath?: string;\n routeRef?: RouteRef;\n}) {\n const { name, parentExtensionId, routePath, routeRef } = options;\n return createExtension({\n kind: 'routing-shim',\n name,\n attachTo: { id: parentExtensionId, input: 'childRoutingShims' },\n inputs: {\n childRoutingShims: createExtensionInput([\n coreExtensionData.routePath.optional(),\n coreExtensionData.routeRef.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath.optional(),\n coreExtensionData.routeRef.optional(),\n ],\n *factory() {\n if (routePath !== undefined) {\n yield coreExtensionData.routePath(routePath);\n }\n\n if (routeRef) {\n yield coreExtensionData.routeRef(convertLegacyRouteRef(routeRef));\n }\n },\n });\n}\n\nfunction visitRouteChildren(options: {\n children: ReactNode;\n parentExtensionId: string;\n context: {\n pluginId: string;\n extensions: ExtensionDefinition[];\n getUniqueName: () => string;\n discoverPlugin: (plugin: LegacyBackstagePlugin) => void;\n };\n}): void {\n const { children, parentExtensionId, context } = options;\n const { pluginId, extensions, getUniqueName, discoverPlugin } = context;\n\n Children.forEach(children, node => {\n if (!isValidElement(node)) {\n return;\n }\n\n const plugin = getComponentData<LegacyBackstagePlugin>(node, 'core.plugin');\n const routeRef = getComponentData<RouteRef<AnyRouteRefParams>>(\n node,\n 'core.mountPoint',\n );\n const routePath: string | undefined = node.props?.path;\n\n if (plugin) {\n // We just mark the plugin as discovered, but don't change the context\n discoverPlugin(plugin);\n }\n\n let nextParentExtensionId = parentExtensionId;\n if (routeRef || routePath) {\n const nextParentExtensionName = getUniqueName();\n nextParentExtensionId = `routing-shim:${pluginId}/${nextParentExtensionName}`;\n extensions.push(\n makeRoutingShimExtension({\n name: nextParentExtensionName,\n parentExtensionId,\n routePath,\n routeRef,\n }),\n );\n }\n\n visitRouteChildren({\n children: node.props.children,\n parentExtensionId: nextParentExtensionId,\n context,\n });\n });\n}\n\n/** @internal */\nexport function collectLegacyRoutes(\n flatRoutesElement: JSX.Element,\n): BackstagePlugin[] {\n const pluginExtensions = new Map<\n LegacyBackstagePlugin,\n ExtensionDefinition[]\n >();\n\n const getUniqueName = (() => {\n let currentIndex = 1;\n return () => String(currentIndex++);\n })();\n\n const getPluginExtensions = (plugin: LegacyBackstagePlugin) => {\n let extensions = pluginExtensions.get(plugin);\n if (!extensions) {\n extensions = [];\n pluginExtensions.set(plugin, extensions);\n }\n return extensions;\n };\n\n React.Children.forEach(\n flatRoutesElement.props.children,\n (route: ReactNode) => {\n // TODO(freben): Handle feature flag and permissions framework wrapper elements\n if (!React.isValidElement(route)) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found element of type ${typeof route}.`,\n );\n }\n if (route.type !== Route) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found ${route.type}.`,\n );\n }\n const routeElement = route.props.element;\n const path: string | undefined = route.props.path;\n const plugin = getComponentData<LegacyBackstagePlugin>(\n routeElement,\n 'core.plugin',\n );\n const routeRef = getComponentData<RouteRef>(\n routeElement,\n 'core.mountPoint',\n );\n if (!plugin) {\n throw new Error(\n // TODO(vinzscam): add See <link-to-app-migration-docs> for more info\n `Route with path ${path} has en element that can not be converted as it does not belong to a plugin. Make sure that the top-level React element of the element prop is an extension from a Backstage plugin, or remove the Route completely.`,\n );\n }\n if (path === undefined) {\n throw new Error(\n `Route element inside FlatRoutes had no path prop value given`,\n );\n }\n\n const extensions = getPluginExtensions(plugin);\n const pageExtensionName = extensions.length ? getUniqueName() : undefined;\n const pageExtensionId = `page:${plugin.getId()}${\n pageExtensionName ? `/${pageExtensionName}` : pageExtensionName\n }`;\n\n extensions.push(\n PageBlueprint.makeWithOverrides({\n name: pageExtensionName,\n inputs: {\n childRoutingShims: createExtensionInput([\n coreExtensionData.routePath.optional(),\n coreExtensionData.routeRef.optional(),\n ]),\n },\n factory(originalFactory, { inputs: _inputs }) {\n // todo(blam): why do we not use the inputs here?\n return originalFactory({\n defaultPath: path[0] === '/' ? path.slice(1) : path,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n loader: async () =>\n compatWrapper(\n route.props.children ? (\n <Routes>\n <Route path=\"*\" element={routeElement}>\n <Route path=\"*\" element={route.props.children} />\n </Route>\n </Routes>\n ) : (\n routeElement\n ),\n ),\n });\n },\n }),\n );\n\n visitRouteChildren({\n children: route.props.children,\n parentExtensionId: pageExtensionId,\n context: {\n pluginId: plugin.getId(),\n extensions,\n getUniqueName,\n discoverPlugin: getPluginExtensions,\n },\n });\n },\n );\n\n return Array.from(pluginExtensions).map(([plugin, extensions]) =>\n createFrontendPlugin({\n id: plugin.getId(),\n extensions: [\n ...extensions,\n ...Array.from(plugin.getApis()).map(factory =>\n ApiBlueprint.make({ namespace: factory.api.id, params: { factory } }),\n ),\n ],\n routes: convertLegacyRouteRefs(plugin.routes ?? {}),\n externalRoutes: convertLegacyRouteRefs(plugin.externalRoutes ?? {}),\n }),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { AppContextProvider } from '../core-app-api/src/app/AppContext.esm.js';
|
|
3
|
-
import { useApi, appTreeApiRef, componentsApiRef, iconsApiRef, coreComponentRefs, routeResolutionApiRef,
|
|
3
|
+
import { useApi, appTreeApiRef, componentsApiRef, iconsApiRef, coreComponentRefs, routeResolutionApiRef, createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
4
4
|
import { getOrCreateGlobalSingleton, createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
|
|
5
5
|
import { convertLegacyRouteRef } from '../convertLegacyRouteRef.esm.js';
|
|
6
6
|
|
|
@@ -35,7 +35,7 @@ function toLegacyPlugin(plugin) {
|
|
|
35
35
|
return legacy;
|
|
36
36
|
}
|
|
37
37
|
function toNewPlugin(plugin) {
|
|
38
|
-
return
|
|
38
|
+
return createFrontendPlugin({
|
|
39
39
|
id: plugin.getId()
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/BackwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { ReactNode } from 'react';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppContextProvider } from '../../../core-app-api/src/app/AppContext';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef';\nimport {\n createPlugin as createNewPlugin,\n BackstagePlugin as NewBackstagePlugin,\n appTreeApiRef,\n componentsApiRef,\n coreComponentRefs,\n iconsApiRef,\n useApi,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n AppComponents,\n IconComponent,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n} from '@backstage/core-plugin-api';\nimport {\n VersionedValue,\n createVersionedContext,\n createVersionedValueMap,\n getOrCreateGlobalSingleton,\n} from '@backstage/version-bridge';\nimport { convertLegacyRouteRef } from '../convertLegacyRouteRef';\n\n// Make sure that we only convert each new plugin instance to its legacy equivalent once\nconst legacyPluginStore = getOrCreateGlobalSingleton(\n 'legacy-plugin-compatibility-store',\n () => new WeakMap<NewBackstagePlugin, LegacyBackstagePlugin>(),\n);\n\nexport function toLegacyPlugin(\n plugin: NewBackstagePlugin,\n): LegacyBackstagePlugin {\n let legacy = legacyPluginStore.get(plugin);\n if (legacy) {\n return legacy;\n }\n\n const errorMsg = 'Not implemented in legacy plugin compatibility layer';\n const notImplemented = () => {\n throw new Error(errorMsg);\n };\n\n legacy = {\n getId(): string {\n return plugin.id;\n },\n get routes() {\n return {};\n },\n get externalRoutes() {\n return {};\n },\n getApis: notImplemented,\n getFeatureFlags: notImplemented,\n provide: notImplemented,\n };\n\n legacyPluginStore.set(plugin, legacy);\n return legacy;\n}\n\n// TODO: Currently a very naive implementation, may need some more work\nfunction toNewPlugin(plugin: LegacyBackstagePlugin): NewBackstagePlugin {\n return createNewPlugin({\n id: plugin.getId(),\n });\n}\n\n// Recreates the old AppContext APIs using the various new APIs that replaced it\nfunction LegacyAppContextProvider(props: { children: ReactNode }) {\n const appTreeApi = useApi(appTreeApiRef);\n const componentsApi = useApi(componentsApiRef);\n const iconsApi = useApi(iconsApiRef);\n\n const appContext = useMemo(() => {\n const { tree } = appTreeApi.getTree();\n\n let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined;\n\n const ErrorBoundaryFallback = componentsApi.getComponent(\n coreComponentRefs.errorBoundaryFallback,\n );\n const ErrorBoundaryFallbackWrapper: AppComponents['ErrorBoundaryFallback'] =\n ({ plugin, ...rest }) => (\n <ErrorBoundaryFallback\n {...rest}\n plugin={plugin && toNewPlugin(plugin)}\n />\n );\n\n return {\n getPlugins(): LegacyBackstagePlugin[] {\n if (gatheredPlugins) {\n return gatheredPlugins;\n }\n\n const pluginSet = new Set<LegacyBackstagePlugin>();\n for (const node of tree.nodes.values()) {\n const plugin = node.spec.source;\n if (plugin) {\n pluginSet.add(toLegacyPlugin(plugin));\n }\n }\n gatheredPlugins = Array.from(pluginSet);\n\n return gatheredPlugins;\n },\n\n getSystemIcon(key: string): IconComponent | undefined {\n return iconsApi.getIcon(key);\n },\n\n getSystemIcons(): Record<string, IconComponent> {\n return Object.fromEntries(\n iconsApi.listIconKeys().map(key => [key, iconsApi.getIcon(key)!]),\n );\n },\n\n getComponents(): AppComponents {\n return {\n NotFoundErrorPage: componentsApi.getComponent(\n coreComponentRefs.notFoundErrorPage,\n ),\n BootErrorPage() {\n throw new Error(\n 'The BootErrorPage app component should not be accessed by plugins',\n );\n },\n Progress: componentsApi.getComponent(coreComponentRefs.progress),\n Router() {\n throw new Error(\n 'The Router app component should not be accessed by plugins',\n );\n },\n ErrorBoundaryFallback: ErrorBoundaryFallbackWrapper,\n };\n },\n };\n }, [appTreeApi, componentsApi, iconsApi]);\n\n return (\n <AppContextProvider appContext={appContext}>\n {props.children}\n </AppContextProvider>\n );\n}\n\nconst RoutingContext = createVersionedContext<{ 1: RouteResolver }>(\n 'routing-context',\n);\n\nfunction LegacyRoutingProvider(props: { children: ReactNode }) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const value = useMemo<VersionedValue<{ 1: RouteResolver }>>(() => {\n return createVersionedValueMap({\n 1: {\n resolve(anyRouteRef, location) {\n const sourcePath =\n typeof location === 'string' ? location : location.pathname ?? '';\n\n return routeResolutionApi.resolve(\n // This removes the requirement to use convertLegacyRouteRef inside plugins, but\n // they still need to converted when passed to the plugin instance\n convertLegacyRouteRef(anyRouteRef as RouteRef),\n { sourcePath },\n );\n },\n },\n });\n }, [routeResolutionApi]);\n\n return (\n <RoutingContext.Provider value={value}>\n {props.children}\n </RoutingContext.Provider>\n );\n}\n\nexport function BackwardsCompatProvider(props: { children: ReactNode }) {\n return (\n <LegacyRoutingProvider>\n <LegacyAppContextProvider>{props.children}</LegacyAppContextProvider>\n </LegacyRoutingProvider>\n );\n}\n"],"names":["createNewPlugin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BackwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/BackwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { ReactNode } from 'react';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppContextProvider } from '../../../core-app-api/src/app/AppContext';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef';\nimport {\n createFrontendPlugin as createNewPlugin,\n BackstagePlugin as NewBackstagePlugin,\n appTreeApiRef,\n componentsApiRef,\n coreComponentRefs,\n iconsApiRef,\n useApi,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n AppComponents,\n IconComponent,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n} from '@backstage/core-plugin-api';\nimport {\n VersionedValue,\n createVersionedContext,\n createVersionedValueMap,\n getOrCreateGlobalSingleton,\n} from '@backstage/version-bridge';\nimport { convertLegacyRouteRef } from '../convertLegacyRouteRef';\n\n// Make sure that we only convert each new plugin instance to its legacy equivalent once\nconst legacyPluginStore = getOrCreateGlobalSingleton(\n 'legacy-plugin-compatibility-store',\n () => new WeakMap<NewBackstagePlugin, LegacyBackstagePlugin>(),\n);\n\nexport function toLegacyPlugin(\n plugin: NewBackstagePlugin,\n): LegacyBackstagePlugin {\n let legacy = legacyPluginStore.get(plugin);\n if (legacy) {\n return legacy;\n }\n\n const errorMsg = 'Not implemented in legacy plugin compatibility layer';\n const notImplemented = () => {\n throw new Error(errorMsg);\n };\n\n legacy = {\n getId(): string {\n return plugin.id;\n },\n get routes() {\n return {};\n },\n get externalRoutes() {\n return {};\n },\n getApis: notImplemented,\n getFeatureFlags: notImplemented,\n provide: notImplemented,\n };\n\n legacyPluginStore.set(plugin, legacy);\n return legacy;\n}\n\n// TODO: Currently a very naive implementation, may need some more work\nfunction toNewPlugin(plugin: LegacyBackstagePlugin): NewBackstagePlugin {\n return createNewPlugin({\n id: plugin.getId(),\n });\n}\n\n// Recreates the old AppContext APIs using the various new APIs that replaced it\nfunction LegacyAppContextProvider(props: { children: ReactNode }) {\n const appTreeApi = useApi(appTreeApiRef);\n const componentsApi = useApi(componentsApiRef);\n const iconsApi = useApi(iconsApiRef);\n\n const appContext = useMemo(() => {\n const { tree } = appTreeApi.getTree();\n\n let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined;\n\n const ErrorBoundaryFallback = componentsApi.getComponent(\n coreComponentRefs.errorBoundaryFallback,\n );\n const ErrorBoundaryFallbackWrapper: AppComponents['ErrorBoundaryFallback'] =\n ({ plugin, ...rest }) => (\n <ErrorBoundaryFallback\n {...rest}\n plugin={plugin && toNewPlugin(plugin)}\n />\n );\n\n return {\n getPlugins(): LegacyBackstagePlugin[] {\n if (gatheredPlugins) {\n return gatheredPlugins;\n }\n\n const pluginSet = new Set<LegacyBackstagePlugin>();\n for (const node of tree.nodes.values()) {\n const plugin = node.spec.source;\n if (plugin) {\n pluginSet.add(toLegacyPlugin(plugin));\n }\n }\n gatheredPlugins = Array.from(pluginSet);\n\n return gatheredPlugins;\n },\n\n getSystemIcon(key: string): IconComponent | undefined {\n return iconsApi.getIcon(key);\n },\n\n getSystemIcons(): Record<string, IconComponent> {\n return Object.fromEntries(\n iconsApi.listIconKeys().map(key => [key, iconsApi.getIcon(key)!]),\n );\n },\n\n getComponents(): AppComponents {\n return {\n NotFoundErrorPage: componentsApi.getComponent(\n coreComponentRefs.notFoundErrorPage,\n ),\n BootErrorPage() {\n throw new Error(\n 'The BootErrorPage app component should not be accessed by plugins',\n );\n },\n Progress: componentsApi.getComponent(coreComponentRefs.progress),\n Router() {\n throw new Error(\n 'The Router app component should not be accessed by plugins',\n );\n },\n ErrorBoundaryFallback: ErrorBoundaryFallbackWrapper,\n };\n },\n };\n }, [appTreeApi, componentsApi, iconsApi]);\n\n return (\n <AppContextProvider appContext={appContext}>\n {props.children}\n </AppContextProvider>\n );\n}\n\nconst RoutingContext = createVersionedContext<{ 1: RouteResolver }>(\n 'routing-context',\n);\n\nfunction LegacyRoutingProvider(props: { children: ReactNode }) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const value = useMemo<VersionedValue<{ 1: RouteResolver }>>(() => {\n return createVersionedValueMap({\n 1: {\n resolve(anyRouteRef, location) {\n const sourcePath =\n typeof location === 'string' ? location : location.pathname ?? '';\n\n return routeResolutionApi.resolve(\n // This removes the requirement to use convertLegacyRouteRef inside plugins, but\n // they still need to converted when passed to the plugin instance\n convertLegacyRouteRef(anyRouteRef as RouteRef),\n { sourcePath },\n );\n },\n },\n });\n }, [routeResolutionApi]);\n\n return (\n <RoutingContext.Provider value={value}>\n {props.children}\n </RoutingContext.Provider>\n );\n}\n\nexport function BackwardsCompatProvider(props: { children: ReactNode }) {\n return (\n <LegacyRoutingProvider>\n <LegacyAppContextProvider>{props.children}</LegacyAppContextProvider>\n </LegacyRoutingProvider>\n );\n}\n"],"names":["createNewPlugin"],"mappings":"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"}
|
|
@@ -58,32 +58,29 @@ function convertLegacyApp(rootElement) {
|
|
|
58
58
|
name: "layout",
|
|
59
59
|
attachTo: { id: "app", input: "root" },
|
|
60
60
|
inputs: {
|
|
61
|
-
content: createExtensionInput(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
-
{ singleton: true }
|
|
66
|
-
)
|
|
67
|
-
},
|
|
68
|
-
output: {
|
|
69
|
-
element: coreExtensionData.reactElement
|
|
61
|
+
content: createExtensionInput([coreExtensionData.reactElement], {
|
|
62
|
+
singleton: true
|
|
63
|
+
})
|
|
70
64
|
},
|
|
65
|
+
output: [coreExtensionData.reactElement],
|
|
71
66
|
factory({ inputs }) {
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
return [
|
|
68
|
+
coreExtensionData.reactElement(
|
|
69
|
+
React.cloneElement(
|
|
70
|
+
rootEl,
|
|
71
|
+
void 0,
|
|
72
|
+
inputs.content.get(coreExtensionData.reactElement)
|
|
73
|
+
)
|
|
77
74
|
)
|
|
78
|
-
|
|
75
|
+
];
|
|
79
76
|
}
|
|
80
77
|
});
|
|
81
78
|
const CoreNavOverride = createExtension({
|
|
82
79
|
namespace: "app",
|
|
83
80
|
name: "nav",
|
|
84
81
|
attachTo: { id: "app/layout", input: "nav" },
|
|
85
|
-
output:
|
|
86
|
-
factory: () =>
|
|
82
|
+
output: [],
|
|
83
|
+
factory: () => [],
|
|
87
84
|
disabled: true
|
|
88
85
|
});
|
|
89
86
|
const collectedRoutes = collectLegacyRoutes(routesEl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertLegacyApp.esm.js","sources":["../src/convertLegacyApp.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n Children,\n Fragment,\n ReactElement,\n ReactNode,\n isValidElement,\n} from 'react';\nimport {\n FrontendFeature,\n coreExtensionData,\n createExtension,\n createExtensionInput,\n createExtensionOverrides,\n} from '@backstage/frontend-plugin-api';\nimport { getComponentData } from '@backstage/core-plugin-api';\nimport { collectLegacyRoutes } from './collectLegacyRoutes';\n\nfunction selectChildren(\n rootNode: ReactNode,\n selector?: (element: ReactElement<{ children?: ReactNode }>) => boolean,\n strictError?: string,\n): Array<ReactElement<{ children?: ReactNode }>> {\n return Children.toArray(rootNode).flatMap(node => {\n if (!isValidElement<{ children?: ReactNode }>(node)) {\n return [];\n }\n\n if (node.type === Fragment) {\n return selectChildren(node.props.children, selector, strictError);\n }\n\n if (selector === undefined || selector(node)) {\n return [node];\n }\n\n if (strictError) {\n throw new Error(strictError);\n }\n\n return selectChildren(node.props.children, selector, strictError);\n });\n}\n\n/** @public */\nexport function convertLegacyApp(\n rootElement: React.JSX.Element,\n): FrontendFeature[] {\n if (getComponentData(rootElement, 'core.type') === 'FlatRoutes') {\n return collectLegacyRoutes(rootElement);\n }\n\n const appRouterEls = selectChildren(\n rootElement,\n el => getComponentData(el, 'core.type') === 'AppRouter',\n );\n if (appRouterEls.length !== 1) {\n throw new Error(\n \"Failed to convert legacy app, AppRouter element could not been found. Make sure it's at the top level of the App element tree\",\n );\n }\n\n const rootEls = selectChildren(\n appRouterEls[0].props.children,\n el =>\n Boolean(el.props.children) &&\n selectChildren(\n el.props.children,\n innerEl => getComponentData(innerEl, 'core.type') === 'FlatRoutes',\n ).length === 1,\n );\n if (rootEls.length !== 1) {\n throw new Error(\n \"Failed to convert legacy app, Root element containing FlatRoutes could not been found. Make sure it's within the AppRouter element of the App element tree\",\n );\n }\n const [rootEl] = rootEls;\n\n const routesEls = selectChildren(\n rootEls[0].props.children,\n el => getComponentData(el, 'core.type') === 'FlatRoutes',\n );\n if (routesEls.length !== 1) {\n throw new Error(\n 'Unexpectedly failed to find FlatRoutes in app element tree',\n );\n }\n const [routesEl] = routesEls;\n\n const CoreLayoutOverride = createExtension({\n namespace: 'app',\n name: 'layout',\n attachTo: { id: 'app', input: 'root' },\n inputs: {\n content: createExtensionInput(
|
|
1
|
+
{"version":3,"file":"convertLegacyApp.esm.js","sources":["../src/convertLegacyApp.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, {\n Children,\n Fragment,\n ReactElement,\n ReactNode,\n isValidElement,\n} from 'react';\nimport {\n FrontendFeature,\n coreExtensionData,\n createExtension,\n createExtensionInput,\n createExtensionOverrides,\n} from '@backstage/frontend-plugin-api';\nimport { getComponentData } from '@backstage/core-plugin-api';\nimport { collectLegacyRoutes } from './collectLegacyRoutes';\n\nfunction selectChildren(\n rootNode: ReactNode,\n selector?: (element: ReactElement<{ children?: ReactNode }>) => boolean,\n strictError?: string,\n): Array<ReactElement<{ children?: ReactNode }>> {\n return Children.toArray(rootNode).flatMap(node => {\n if (!isValidElement<{ children?: ReactNode }>(node)) {\n return [];\n }\n\n if (node.type === Fragment) {\n return selectChildren(node.props.children, selector, strictError);\n }\n\n if (selector === undefined || selector(node)) {\n return [node];\n }\n\n if (strictError) {\n throw new Error(strictError);\n }\n\n return selectChildren(node.props.children, selector, strictError);\n });\n}\n\n/** @public */\nexport function convertLegacyApp(\n rootElement: React.JSX.Element,\n): FrontendFeature[] {\n if (getComponentData(rootElement, 'core.type') === 'FlatRoutes') {\n return collectLegacyRoutes(rootElement);\n }\n\n const appRouterEls = selectChildren(\n rootElement,\n el => getComponentData(el, 'core.type') === 'AppRouter',\n );\n if (appRouterEls.length !== 1) {\n throw new Error(\n \"Failed to convert legacy app, AppRouter element could not been found. Make sure it's at the top level of the App element tree\",\n );\n }\n\n const rootEls = selectChildren(\n appRouterEls[0].props.children,\n el =>\n Boolean(el.props.children) &&\n selectChildren(\n el.props.children,\n innerEl => getComponentData(innerEl, 'core.type') === 'FlatRoutes',\n ).length === 1,\n );\n if (rootEls.length !== 1) {\n throw new Error(\n \"Failed to convert legacy app, Root element containing FlatRoutes could not been found. Make sure it's within the AppRouter element of the App element tree\",\n );\n }\n const [rootEl] = rootEls;\n\n const routesEls = selectChildren(\n rootEls[0].props.children,\n el => getComponentData(el, 'core.type') === 'FlatRoutes',\n );\n if (routesEls.length !== 1) {\n throw new Error(\n 'Unexpectedly failed to find FlatRoutes in app element tree',\n );\n }\n const [routesEl] = routesEls;\n\n const CoreLayoutOverride = createExtension({\n namespace: 'app',\n name: 'layout',\n attachTo: { id: 'app', input: 'root' },\n inputs: {\n content: createExtensionInput([coreExtensionData.reactElement], {\n singleton: true,\n }),\n },\n output: [coreExtensionData.reactElement],\n factory({ inputs }) {\n // Clone the root element, this replaces the FlatRoutes declared in the app with out content input\n return [\n coreExtensionData.reactElement(\n React.cloneElement(\n rootEl,\n undefined,\n inputs.content.get(coreExtensionData.reactElement),\n ),\n ),\n ];\n },\n });\n const CoreNavOverride = createExtension({\n namespace: 'app',\n name: 'nav',\n attachTo: { id: 'app/layout', input: 'nav' },\n output: [],\n factory: () => [],\n disabled: true,\n });\n\n const collectedRoutes = collectLegacyRoutes(routesEl);\n\n return [\n ...collectedRoutes,\n createExtensionOverrides({\n extensions: [CoreLayoutOverride, CoreNavOverride],\n }),\n ];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getComponentData } from '@backstage/core-plugin-api';
|
|
2
|
+
import { PageBlueprint } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import kebabCase from 'lodash/kebabCase';
|
|
4
|
+
import { convertLegacyRouteRef } from './convertLegacyRouteRef.esm.js';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { compatWrapper } from './compatWrapper/compatWrapper.esm.js';
|
|
7
|
+
|
|
8
|
+
function convertLegacyPageExtension(LegacyExtension, overrides) {
|
|
9
|
+
const element = /* @__PURE__ */ React.createElement(LegacyExtension, null);
|
|
10
|
+
const extName = getComponentData(element, "core.extensionName");
|
|
11
|
+
if (!extName) {
|
|
12
|
+
throw new Error("Extension has no name");
|
|
13
|
+
}
|
|
14
|
+
const mountPoint = getComponentData(
|
|
15
|
+
element,
|
|
16
|
+
"core.mountPoint"
|
|
17
|
+
);
|
|
18
|
+
const name = extName.endsWith("Page") ? extName.slice(0, -"Page".length) : extName;
|
|
19
|
+
const kebabName = kebabCase(name);
|
|
20
|
+
return PageBlueprint.make({
|
|
21
|
+
name: overrides?.name ?? kebabName,
|
|
22
|
+
params: {
|
|
23
|
+
defaultPath: overrides?.defaultPath ?? `/${kebabName}`,
|
|
24
|
+
routeRef: mountPoint && convertLegacyRouteRef(mountPoint),
|
|
25
|
+
loader: async () => compatWrapper(element)
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { convertLegacyPageExtension };
|
|
31
|
+
//# sourceMappingURL=convertLegacyPageExtension.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convertLegacyPageExtension.esm.js","sources":["../src/convertLegacyPageExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n getComponentData,\n RouteRef as LegacyRouteRef,\n} from '@backstage/core-plugin-api';\nimport {\n ExtensionDefinition,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport kebabCase from 'lodash/kebabCase';\nimport { convertLegacyRouteRef } from './convertLegacyRouteRef';\nimport { ComponentType } from 'react';\nimport React from 'react';\nimport { compatWrapper } from './compatWrapper';\n\n/** @public */\nexport function convertLegacyPageExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n defaultPath?: string;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const mountPoint = getComponentData<LegacyRouteRef>(\n element,\n 'core.mountPoint',\n );\n\n const name = extName.endsWith('Page')\n ? extName.slice(0, -'Page'.length)\n : extName;\n const kebabName = kebabCase(name);\n\n return PageBlueprint.make({\n name: overrides?.name ?? kebabName,\n params: {\n defaultPath: overrides?.defaultPath ?? `/${kebabName}`,\n routeRef: mountPoint && convertLegacyRouteRef(mountPoint),\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;AA+BgB,SAAA,0BAAA,CACd,iBACA,SAIqB,EAAA;AACrB,EAAM,MAAA,OAAA,uCAAW,eAAgB,EAAA,IAAA,CAAA,CAAA;AAEjC,EAAM,MAAA,OAAA,GAAU,gBAAyB,CAAA,OAAA,EAAS,oBAAoB,CAAA,CAAA;AACtE,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAM,MAAA,IAAI,MAAM,uBAAuB,CAAA,CAAA;AAAA,GACzC;AAEA,EAAA,MAAM,UAAa,GAAA,gBAAA;AAAA,IACjB,OAAA;AAAA,IACA,iBAAA;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,IAAA,GAAO,OAAQ,CAAA,QAAA,CAAS,MAAM,CAAA,GAChC,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,CAAC,MAAO,CAAA,MAAM,CAC/B,GAAA,OAAA,CAAA;AACJ,EAAM,MAAA,SAAA,GAAY,UAAU,IAAI,CAAA,CAAA;AAEhC,EAAA,OAAO,cAAc,IAAK,CAAA;AAAA,IACxB,IAAA,EAAM,WAAW,IAAQ,IAAA,SAAA;AAAA,IACzB,MAAQ,EAAA;AAAA,MACN,WAAa,EAAA,SAAA,EAAW,WAAe,IAAA,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,MACpD,QAAA,EAAU,UAAc,IAAA,qBAAA,CAAsB,UAAU,CAAA;AAAA,MACxD,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO,CAAA;AAAA,KAC3C;AAAA,GACD,CAAA,CAAA;AACH;;;;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ApiBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { convertLegacyRouteRefs } from './convertLegacyRouteRef.esm.js';
|
|
3
|
+
|
|
4
|
+
function convertLegacyPlugin(legacyPlugin, options) {
|
|
5
|
+
const apiExtensions = Array.from(legacyPlugin.getApis()).map(
|
|
6
|
+
(factory) => ApiBlueprint.make({ namespace: factory.api.id, params: { factory } })
|
|
7
|
+
);
|
|
8
|
+
return createFrontendPlugin({
|
|
9
|
+
id: legacyPlugin.getId(),
|
|
10
|
+
featureFlags: [...legacyPlugin.getFeatureFlags()],
|
|
11
|
+
routes: convertLegacyRouteRefs(legacyPlugin.routes ?? {}),
|
|
12
|
+
externalRoutes: convertLegacyRouteRefs(legacyPlugin.externalRoutes ?? {}),
|
|
13
|
+
extensions: [...apiExtensions, ...options.extensions]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { convertLegacyPlugin };
|
|
18
|
+
//# sourceMappingURL=convertLegacyPlugin.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convertLegacyPlugin.esm.js","sources":["../src/convertLegacyPlugin.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BackstagePlugin as LegacyBackstagePlugin } from '@backstage/core-plugin-api';\nimport {\n ApiBlueprint,\n ExtensionDefinition,\n BackstagePlugin as NewBackstagePlugin,\n createFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { convertLegacyRouteRefs } from './convertLegacyRouteRef';\n\n/** @public */\nexport function convertLegacyPlugin(\n legacyPlugin: LegacyBackstagePlugin,\n options: { extensions: ExtensionDefinition[] },\n): NewBackstagePlugin {\n const apiExtensions = Array.from(legacyPlugin.getApis()).map(factory =>\n ApiBlueprint.make({ namespace: factory.api.id, params: { factory } }),\n );\n return createFrontendPlugin({\n id: legacyPlugin.getId(),\n featureFlags: [...legacyPlugin.getFeatureFlags()],\n routes: convertLegacyRouteRefs(legacyPlugin.routes ?? {}),\n externalRoutes: convertLegacyRouteRefs(legacyPlugin.externalRoutes ?? {}),\n extensions: [...apiExtensions, ...options.extensions],\n });\n}\n"],"names":[],"mappings":";;;AA0BgB,SAAA,mBAAA,CACd,cACA,OACoB,EAAA;AACpB,EAAA,MAAM,gBAAgB,KAAM,CAAA,IAAA,CAAK,YAAa,CAAA,OAAA,EAAS,CAAE,CAAA,GAAA;AAAA,IAAI,CAC3D,OAAA,KAAA,YAAA,CAAa,IAAK,CAAA,EAAE,SAAW,EAAA,OAAA,CAAQ,GAAI,CAAA,EAAA,EAAI,MAAQ,EAAA,EAAE,OAAQ,EAAA,EAAG,CAAA;AAAA,GACtE,CAAA;AACA,EAAA,OAAO,oBAAqB,CAAA;AAAA,IAC1B,EAAA,EAAI,aAAa,KAAM,EAAA;AAAA,IACvB,YAAc,EAAA,CAAC,GAAG,YAAA,CAAa,iBAAiB,CAAA;AAAA,IAChD,MAAQ,EAAA,sBAAA,CAAuB,YAAa,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,IACxD,cAAgB,EAAA,sBAAA,CAAuB,YAAa,CAAA,cAAA,IAAkB,EAAE,CAAA;AAAA,IACxE,YAAY,CAAC,GAAG,aAAe,EAAA,GAAG,QAAQ,UAAU,CAAA;AAAA,GACrD,CAAA,CAAA;AACH;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
2
|
-
import { AnalyticsApi, AnalyticsEvent, RouteRef, SubRouteRef, ExternalRouteRef, AnyRouteRefParams } from '@backstage/core-plugin-api';
|
|
3
|
-
import { AnalyticsApi as AnalyticsApi$1, AnalyticsEvent as AnalyticsEvent$1, FrontendFeature, RouteRef as RouteRef$1, SubRouteRef as SubRouteRef$1, ExternalRouteRef as ExternalRouteRef$1 } from '@backstage/frontend-plugin-api';
|
|
1
|
+
import React, { ReactNode, ComponentType } from 'react';
|
|
2
|
+
import { AnalyticsApi, AnalyticsEvent, BackstagePlugin, RouteRef, SubRouteRef, ExternalRouteRef, AnyRouteRefParams } from '@backstage/core-plugin-api';
|
|
3
|
+
import { AnalyticsApi as AnalyticsApi$1, AnalyticsEvent as AnalyticsEvent$1, FrontendFeature, ExtensionDefinition, BackstagePlugin as BackstagePlugin$1, RouteRef as RouteRef$1, SubRouteRef as SubRouteRef$1, ExternalRouteRef as ExternalRouteRef$1 } from '@backstage/frontend-plugin-api';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Wraps a React element in a bidirectional compatibility provider, allow APIs
|
|
@@ -66,6 +66,17 @@ declare class NoOpAnalyticsApi implements AnalyticsApi, AnalyticsApi$1 {
|
|
|
66
66
|
/** @public */
|
|
67
67
|
declare function convertLegacyApp(rootElement: React.JSX.Element): FrontendFeature[];
|
|
68
68
|
|
|
69
|
+
/** @public */
|
|
70
|
+
declare function convertLegacyPlugin(legacyPlugin: BackstagePlugin, options: {
|
|
71
|
+
extensions: ExtensionDefinition[];
|
|
72
|
+
}): BackstagePlugin$1;
|
|
73
|
+
|
|
74
|
+
/** @public */
|
|
75
|
+
declare function convertLegacyPageExtension(LegacyExtension: ComponentType<{}>, overrides?: {
|
|
76
|
+
name?: string;
|
|
77
|
+
defaultPath?: string;
|
|
78
|
+
}): ExtensionDefinition;
|
|
79
|
+
|
|
69
80
|
/**
|
|
70
81
|
* Converts a legacy route ref type to the new system.
|
|
71
82
|
*
|
|
@@ -138,4 +149,4 @@ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: S
|
|
|
138
149
|
*/
|
|
139
150
|
declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: ExternalRouteRef$1<TParams>): ExternalRouteRef<TParams, true>;
|
|
140
151
|
|
|
141
|
-
export { MultipleAnalyticsApi, NoOpAnalyticsApi, type ToNewRouteRef, compatWrapper, convertLegacyApp, convertLegacyRouteRef, convertLegacyRouteRefs };
|
|
152
|
+
export { MultipleAnalyticsApi, NoOpAnalyticsApi, type ToNewRouteRef, compatWrapper, convertLegacyApp, convertLegacyPageExtension, convertLegacyPlugin, convertLegacyRouteRef, convertLegacyRouteRefs };
|
package/dist/index.esm.js
CHANGED
|
@@ -2,5 +2,7 @@ export { compatWrapper } from './compatWrapper/compatWrapper.esm.js';
|
|
|
2
2
|
export { MultipleAnalyticsApi } from './apis/implementations/AnalyticsApi/MultipleAnalyticsApi.esm.js';
|
|
3
3
|
export { NoOpAnalyticsApi } from './apis/implementations/AnalyticsApi/NoOpAnalyticsApi.esm.js';
|
|
4
4
|
export { convertLegacyApp } from './convertLegacyApp.esm.js';
|
|
5
|
+
export { convertLegacyPlugin } from './convertLegacyPlugin.esm.js';
|
|
6
|
+
export { convertLegacyPageExtension } from './convertLegacyPageExtension.esm.js';
|
|
5
7
|
export { convertLegacyRouteRef, convertLegacyRouteRefs } from './convertLegacyRouteRef.esm.js';
|
|
6
8
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/core-compat-api",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9-next.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -32,19 +32,20 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@backstage/core-plugin-api": "^1.9.3",
|
|
35
|
-
"@backstage/frontend-plugin-api": "^0.
|
|
35
|
+
"@backstage/frontend-plugin-api": "^0.8.0-next.0",
|
|
36
36
|
"@backstage/version-bridge": "^1.0.8",
|
|
37
|
-
"@types/react": "^16.13.1 || ^17.0.0"
|
|
37
|
+
"@types/react": "^16.13.1 || ^17.0.0",
|
|
38
|
+
"lodash": "^4.17.21"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@backstage-community/plugin-puppetdb": "^0.1.18",
|
|
41
42
|
"@backstage-community/plugin-stackstorm": "^0.1.16",
|
|
42
|
-
"@backstage/cli": "^0.27.
|
|
43
|
-
"@backstage/core-app-api": "^1.14.2
|
|
44
|
-
"@backstage/frontend-app-api": "^0.
|
|
45
|
-
"@backstage/frontend-test-utils": "^0.
|
|
46
|
-
"@backstage/plugin-catalog": "^1.22.
|
|
47
|
-
"@backstage/test-utils": "^1.
|
|
43
|
+
"@backstage/cli": "^0.27.1-next.0",
|
|
44
|
+
"@backstage/core-app-api": "^1.14.2",
|
|
45
|
+
"@backstage/frontend-app-api": "^0.9.0-next.0",
|
|
46
|
+
"@backstage/frontend-test-utils": "^0.2.0-next.0",
|
|
47
|
+
"@backstage/plugin-catalog": "^1.22.1-next.0",
|
|
48
|
+
"@backstage/test-utils": "^1.6.0-next.0",
|
|
48
49
|
"@oriflame/backstage-plugin-score-card": "^0.8.0",
|
|
49
50
|
"@testing-library/jest-dom": "^6.0.0",
|
|
50
51
|
"@testing-library/react": "^15.0.0"
|