@backstage/frontend-app-api 0.4.0-next.1 → 0.4.0-next.2

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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @backstage/frontend-app-api
2
2
 
3
+ ## 0.4.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - ea06590: The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`.
8
+
9
+ ### Patch Changes
10
+
11
+ - aeb8008: Add support for translation extensions.
12
+ - b7adf24: Use the new plugin type for error boundary components.
13
+ - 8f5d6c1: Updates to match the new extension input wrapping.
14
+ - cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs.
15
+ - 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns.
16
+ - Updated dependencies
17
+ - @backstage/frontend-plugin-api@0.4.0-next.2
18
+ - @backstage/theme@0.5.0-next.1
19
+ - @backstage/config@1.1.1
20
+ - @backstage/core-app-api@1.11.2-next.1
21
+ - @backstage/core-components@0.13.9-next.2
22
+ - @backstage/core-plugin-api@1.8.1-next.1
23
+ - @backstage/types@1.1.1
24
+ - @backstage/version-bridge@1.0.7
25
+
3
26
  ## 0.4.0-next.1
4
27
 
5
28
  ### Minor Changes
package/dist/index.esm.js CHANGED
@@ -1,46 +1,46 @@
1
1
  import React, { useMemo, useState, useEffect, createContext, useContext } from 'react';
2
2
  import { ConfigReader } from '@backstage/config';
3
- import { createExtension, createExtensionInput, coreExtensionData, useApi, componentsApiRef, coreComponentsRefs, useRouteRef, createThemeExtension, createComponentExtension, AnalyticsContext, useAnalytics, appTreeApiRef } from '@backstage/frontend-plugin-api';
3
+ import { createExtension, createExtensionInput, coreExtensionData, createTranslationExtension, useComponentRef, coreComponentRefs, useRouteRef, createThemeExtension, createComponentExtension, AnalyticsContext, useAnalytics, appTreeApiRef, componentsApiRef } from '@backstage/frontend-plugin-api';
4
4
  import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, matchRoutes, generatePath, useLocation, Route } from 'react-router-dom';
5
5
  import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
6
- import { makeStyles } from '@material-ui/core';
7
- import { useApi as useApi$1, appThemeApiRef, FeatureFlagState, createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, attachComponentData, featureFlagsApiRef } from '@backstage/core-plugin-api';
6
+ import { makeStyles, Button as Button$1 } from '@material-ui/core';
7
+ import { useApi, appThemeApiRef, FeatureFlagState, createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, createApiRef, attachComponentData, featureFlagsApiRef } from '@backstage/core-plugin-api';
8
8
  import { UrlPatternDiscovery, AlertApiForwarder, NoOpAnalyticsApi, ErrorAlerter, ErrorApiForwarder, UnhandledErrorForwarder, WebStorage, createFetchApi, FetchMiddlewares, OAuthRequestManager, GoogleAuth, MicrosoftAuth, GithubAuth, OktaAuth, GitlabAuth, OneLoginAuth, BitbucketAuth, BitbucketServerAuth, AtlassianAuth, ApiFactoryRegistry, AppThemeSelector, ApiResolver, ApiProvider } from '@backstage/core-app-api';
9
9
  import useObservable from 'react-use/lib/useObservable';
10
- import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton } from '@backstage/version-bridge';
11
10
  import ObservableImpl from 'zen-observable';
12
11
  import { createInstance } from 'i18next';
13
12
  import { permissionApiRef, IdentityPermissionApi } from '@backstage/plugin-permission-react';
14
13
  import Button from '@material-ui/core/Button';
15
- import MuiApartmentIcon from '@material-ui/icons/Apartment';
16
- import MuiBrokenImageIcon from '@material-ui/icons/BrokenImage';
17
- import MuiCategoryIcon from '@material-ui/icons/Category';
18
- import MuiCreateNewFolderIcon from '@material-ui/icons/CreateNewFolder';
19
- import MuiSubjectIcon from '@material-ui/icons/Subject';
20
- import MuiSearchIcon from '@material-ui/icons/Search';
21
- import MuiChatIcon from '@material-ui/icons/Chat';
22
- import MuiDashboardIcon from '@material-ui/icons/Dashboard';
23
- import MuiDocsIcon from '@material-ui/icons/Description';
24
- import MuiEmailIcon from '@material-ui/icons/Email';
25
- import MuiExtensionIcon from '@material-ui/icons/Extension';
26
- import MuiGitHubIcon from '@material-ui/icons/GitHub';
27
- import MuiHelpIcon from '@material-ui/icons/Help';
28
- import MuiLocationOnIcon from '@material-ui/icons/LocationOn';
29
- import MuiMemoryIcon from '@material-ui/icons/Memory';
30
- import MuiMenuBookIcon from '@material-ui/icons/MenuBook';
31
- import MuiPeopleIcon from '@material-ui/icons/People';
32
- import MuiPersonIcon from '@material-ui/icons/Person';
33
- import MuiWarningIcon from '@material-ui/icons/Warning';
34
- import MuiWorkIcon from '@material-ui/icons/Work';
35
- import MuiFeaturedPlayListIcon from '@material-ui/icons/FeaturedPlayList';
14
+ import '@material-ui/icons/Apartment';
15
+ import '@material-ui/icons/BrokenImage';
16
+ import '@material-ui/icons/Category';
17
+ import '@material-ui/icons/CreateNewFolder';
18
+ import '@material-ui/icons/Subject';
19
+ import '@material-ui/icons/Search';
20
+ import '@material-ui/icons/Chat';
21
+ import '@material-ui/icons/Dashboard';
22
+ import '@material-ui/icons/Description';
23
+ import '@material-ui/icons/Email';
24
+ import '@material-ui/icons/Extension';
25
+ import '@material-ui/icons/GitHub';
26
+ import '@material-ui/icons/Help';
27
+ import '@material-ui/icons/LocationOn';
28
+ import '@material-ui/icons/Memory';
29
+ import '@material-ui/icons/MenuBook';
30
+ import '@material-ui/icons/People';
31
+ import '@material-ui/icons/Person';
32
+ import '@material-ui/icons/Warning';
33
+ import '@material-ui/icons/Work';
34
+ import '@material-ui/icons/FeaturedPlayList';
36
35
  import { UnifiedThemeProvider, themes } from '@backstage/theme';
37
36
  import DarkIcon from '@material-ui/icons/Brightness2';
38
37
  import LightIcon from '@material-ui/icons/WbSunny';
38
+ import { getOrCreateGlobalSingleton, createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
39
39
  import { appLanguageApiRef, translationApiRef } from '@backstage/core-plugin-api/alpha';
40
40
  import mapValues from 'lodash/mapValues';
41
41
 
42
42
  const Core = createExtension({
43
- id: "core",
43
+ namespace: "core",
44
44
  attachTo: { id: "root", input: "default" },
45
45
  // ignored
46
46
  inputs: {
@@ -53,6 +53,9 @@ const Core = createExtension({
53
53
  components: createExtensionInput({
54
54
  component: coreExtensionData.component
55
55
  }),
56
+ translations: createExtensionInput({
57
+ translation: createTranslationExtension.translationDataRef
58
+ }),
56
59
  root: createExtensionInput(
57
60
  {
58
61
  element: coreExtensionData.reactElement
@@ -65,14 +68,15 @@ const Core = createExtension({
65
68
  },
66
69
  factory({ inputs }) {
67
70
  return {
68
- root: inputs.root.element
71
+ root: inputs.root.output.element
69
72
  };
70
73
  }
71
74
  });
72
75
 
73
76
  const CoreRoutes = createExtension({
74
- id: "core.routes",
75
- attachTo: { id: "core.layout", input: "content" },
77
+ namespace: "core",
78
+ name: "routes",
79
+ attachTo: { id: "core/layout", input: "content" },
76
80
  inputs: {
77
81
  routes: createExtensionInput({
78
82
  path: coreExtensionData.routePath,
@@ -85,14 +89,13 @@ const CoreRoutes = createExtension({
85
89
  },
86
90
  factory({ inputs }) {
87
91
  const Routes = () => {
88
- const componentsApi = useApi(componentsApiRef);
89
- const NotFoundErrorPage = componentsApi.getComponent(
90
- coreComponentsRefs.notFoundErrorPage
92
+ const NotFoundErrorPage = useComponentRef(
93
+ coreComponentRefs.notFoundErrorPage
91
94
  );
92
95
  const element = useRoutes([
93
96
  ...inputs.routes.map((route) => ({
94
- path: `${route.path}/*`,
95
- element: route.element
97
+ path: `${route.output.path}/*`,
98
+ element: route.output.element
96
99
  })),
97
100
  {
98
101
  path: "*",
@@ -108,8 +111,9 @@ const CoreRoutes = createExtension({
108
111
  });
109
112
 
110
113
  const CoreLayout = createExtension({
111
- id: "core.layout",
112
- attachTo: { id: "core.router", input: "children" },
114
+ namespace: "core",
115
+ name: "layout",
116
+ attachTo: { id: "core/router", input: "children" },
113
117
  inputs: {
114
118
  nav: createExtensionInput(
115
119
  {
@@ -129,7 +133,7 @@ const CoreLayout = createExtension({
129
133
  },
130
134
  factory({ inputs }) {
131
135
  return {
132
- element: /* @__PURE__ */ React.createElement(SidebarPage, null, inputs.nav.element, inputs.content.element)
136
+ element: /* @__PURE__ */ React.createElement(SidebarPage, null, inputs.nav.output.element, inputs.content.output.element)
133
137
  };
134
138
  }
135
139
  });
@@ -216,8 +220,9 @@ const SidebarNavItem = (props) => {
216
220
  return /* @__PURE__ */ React.createElement(SidebarItem, { to, icon: Icon, text: title });
217
221
  };
218
222
  const CoreNav = createExtension({
219
- id: "core.nav",
220
- attachTo: { id: "core.layout", input: "nav" },
223
+ namespace: "core",
224
+ name: "nav",
225
+ attachTo: { id: "core/layout", input: "nav" },
221
226
  inputs: {
222
227
  items: createExtensionInput({
223
228
  target: coreExtensionData.navTarget
@@ -238,7 +243,7 @@ const CoreNav = createExtension({
238
243
  factory({ inputs }) {
239
244
  var _a;
240
245
  return {
241
- element: /* @__PURE__ */ React.createElement(Sidebar, null, /* @__PURE__ */ React.createElement(SidebarLogo, { ...(_a = inputs.logos) == null ? void 0 : _a.elements }), /* @__PURE__ */ React.createElement(SidebarDivider, null), inputs.items.map((item, index) => /* @__PURE__ */ React.createElement(SidebarNavItem, { ...item.target, key: index })))
246
+ element: /* @__PURE__ */ React.createElement(Sidebar, null, /* @__PURE__ */ React.createElement(SidebarLogo, { ...(_a = inputs.logos) == null ? void 0 : _a.output.elements }), /* @__PURE__ */ React.createElement(SidebarDivider, null), inputs.items.map((item, index) => /* @__PURE__ */ React.createElement(SidebarNavItem, { ...item.output.target, key: index })))
242
247
  };
243
248
  }
244
249
  });
@@ -332,7 +337,7 @@ const useShouldPreferDarkTheme = () => {
332
337
  return shouldPreferDark;
333
338
  };
334
339
  function AppThemeProvider({ children }) {
335
- const appThemeApi = useApi$1(appThemeApiRef);
340
+ const appThemeApi = useApi(appThemeApiRef);
336
341
  const themeId = useObservable(
337
342
  appThemeApi.activeThemeId$(),
338
343
  appThemeApi.getActiveThemeId()
@@ -434,15 +439,6 @@ class AppIdentityProxy {
434
439
  }
435
440
  }
436
441
 
437
- const AppContext = createVersionedContext("app-context");
438
- const AppContextProvider = ({
439
- appContext,
440
- children
441
- }) => {
442
- const versionedValue = createVersionedValueMap({ 1: appContext });
443
- return /* @__PURE__ */ React.createElement(AppContext.Provider, { value: versionedValue, children });
444
- };
445
-
446
442
  var __defProp$2 = Object.defineProperty;
447
443
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
448
444
  var __publicField$2 = (obj, key, value) => {
@@ -1069,6 +1065,23 @@ registerDefaults_fn = function(internalRef) {
1069
1065
  };
1070
1066
  let I18nextTranslationApi = _I18nextTranslationApi;
1071
1067
 
1068
+ function resolveExtensionDefinition(definition, context) {
1069
+ var _a;
1070
+ const { name, kind, namespace: _, ...rest } = definition;
1071
+ const namespace = (_a = definition.namespace) != null ? _a : context == null ? void 0 : context.namespace;
1072
+ const namePart = name && namespace ? `${namespace}/${name}` : namespace || name;
1073
+ if (!namePart) {
1074
+ throw new Error(
1075
+ `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`
1076
+ );
1077
+ }
1078
+ return {
1079
+ ...rest,
1080
+ id: kind ? `${kind}:${namePart}` : namePart,
1081
+ $$type: "@backstage/Extension"
1082
+ };
1083
+ }
1084
+
1072
1085
  const apis = [
1073
1086
  createApiFactory({
1074
1087
  api: discoveryApiRef,
@@ -1307,33 +1320,6 @@ const components = {
1307
1320
  ErrorBoundaryFallback: DefaultErrorBoundaryFallback
1308
1321
  };
1309
1322
 
1310
- const icons = {
1311
- brokenImage: MuiBrokenImageIcon,
1312
- // To be confirmed: see https://github.com/backstage/backstage/issues/4970
1313
- catalog: MuiMenuBookIcon,
1314
- scaffolder: MuiCreateNewFolderIcon,
1315
- techdocs: MuiSubjectIcon,
1316
- search: MuiSearchIcon,
1317
- chat: MuiChatIcon,
1318
- dashboard: MuiDashboardIcon,
1319
- docs: MuiDocsIcon,
1320
- email: MuiEmailIcon,
1321
- github: MuiGitHubIcon,
1322
- group: MuiPeopleIcon,
1323
- help: MuiHelpIcon,
1324
- "kind:api": MuiExtensionIcon,
1325
- "kind:component": MuiMemoryIcon,
1326
- "kind:domain": MuiApartmentIcon,
1327
- "kind:group": MuiPeopleIcon,
1328
- "kind:location": MuiLocationOnIcon,
1329
- "kind:system": MuiCategoryIcon,
1330
- "kind:user": MuiPersonIcon,
1331
- "kind:resource": MuiWorkIcon,
1332
- "kind:template": MuiFeaturedPlayListIcon,
1333
- user: MuiPersonIcon,
1334
- warning: MuiWarningIcon
1335
- };
1336
-
1337
1323
  const LightTheme = createThemeExtension({
1338
1324
  id: "light",
1339
1325
  title: "Light Theme",
@@ -1754,14 +1740,6 @@ function expandShorthandExtensionParameters(arrayEntry, arrayIndex) {
1754
1740
  errorMsg("extension ID must not be empty or contain whitespace")
1755
1741
  );
1756
1742
  }
1757
- if (id2.includes("/")) {
1758
- let message = `extension ID must not contain slashes; got '${id2}'`;
1759
- const good = id2.split("/")[0];
1760
- if (good) {
1761
- message += `, did you mean '${good}'?`;
1762
- }
1763
- throw new Error(errorMsg(message));
1764
- }
1765
1743
  }
1766
1744
  if (typeof arrayEntry === "string") {
1767
1745
  assertValidId(arrayEntry);
@@ -2117,10 +2095,11 @@ function resolveAppNodeSpecs(options) {
2117
2095
 
2118
2096
  function resolveInputData(dataMap, attachment, inputName) {
2119
2097
  return mapValues(dataMap, (ref) => {
2120
- const value = attachment.instance.getData(ref);
2098
+ var _a;
2099
+ const value = (_a = attachment.instance) == null ? void 0 : _a.getData(ref);
2121
2100
  if (value === void 0 && !ref.config.optional) {
2122
2101
  throw new Error(
2123
- `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.id}'`
2102
+ `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.spec.id}'`
2124
2103
  );
2125
2104
  }
2126
2105
  return value;
@@ -2133,7 +2112,7 @@ function resolveInputs(inputMap, attachments) {
2133
2112
  if (undeclaredAttachments.length > 0) {
2134
2113
  throw new Error(
2135
2114
  `received undeclared input${undeclaredAttachments.length > 1 ? "s" : ""} ${undeclaredAttachments.map(
2136
- ([k, exts]) => `'${k}' from extension${exts.length > 1 ? "s" : ""} '${exts.map((e) => e.id).join("', '")}'`
2115
+ ([k, exts]) => `'${k}' from extension${exts.length > 1 ? "s" : ""} '${exts.map((e) => e.spec.id).join("', '")}'`
2137
2116
  ).join(" and ")}`
2138
2117
  );
2139
2118
  }
@@ -2142,7 +2121,7 @@ function resolveInputs(inputMap, attachments) {
2142
2121
  const attachedNodes = (_a = attachments.get(inputName)) != null ? _a : [];
2143
2122
  if (input.config.singleton) {
2144
2123
  if (attachedNodes.length > 1) {
2145
- const attachedNodeIds = attachedNodes.map((e) => e.id);
2124
+ const attachedNodeIds = attachedNodes.map((e) => e.spec.id);
2146
2125
  throw Error(
2147
2126
  `expected ${input.config.optional ? "at most" : "exactly"} one '${inputName}' input but received multiple: '${attachedNodeIds.join(
2148
2127
  "', '"
@@ -2154,11 +2133,19 @@ function resolveInputs(inputMap, attachments) {
2154
2133
  }
2155
2134
  throw Error(`input '${inputName}' is required but was not received`);
2156
2135
  }
2157
- return resolveInputData(input.extensionData, attachedNodes[0], inputName);
2136
+ return {
2137
+ node: attachedNodes[0],
2138
+ output: resolveInputData(
2139
+ input.extensionData,
2140
+ attachedNodes[0],
2141
+ inputName
2142
+ )
2143
+ };
2158
2144
  }
2159
- return attachedNodes.map(
2160
- (attachment) => resolveInputData(input.extensionData, attachment, inputName)
2161
- );
2145
+ return attachedNodes.map((attachment) => ({
2146
+ node: attachment,
2147
+ output: resolveInputData(input.extensionData, attachment, inputName)
2148
+ }));
2162
2149
  });
2163
2150
  }
2164
2151
  function createAppNodeInstance(options) {
@@ -2196,7 +2183,7 @@ function createAppNodeInstance(options) {
2196
2183
  }
2197
2184
  } catch (e) {
2198
2185
  throw new Error(
2199
- `Failed to instantiate extension '${id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e}`}`
2186
+ `Failed to instantiate extension '${id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e.stack}`}`
2200
2187
  );
2201
2188
  }
2202
2189
  return {
@@ -2223,7 +2210,7 @@ function instantiateAppNodeTree(rootNode) {
2223
2210
  if (!childInstance) {
2224
2211
  return [];
2225
2212
  }
2226
- return [{ id: child.spec.id, instance: childInstance }];
2213
+ return [child];
2227
2214
  });
2228
2215
  if (instantiatedChildren.length > 0) {
2229
2216
  instantiatedAttachments.set(input, instantiatedChildren);
@@ -2253,20 +2240,22 @@ function createAppTree(options) {
2253
2240
  }
2254
2241
 
2255
2242
  const DefaultProgressComponent = createComponentExtension({
2256
- ref: coreComponentsRefs.progress,
2243
+ ref: coreComponentRefs.progress,
2257
2244
  component: { sync: () => components.Progress }
2258
2245
  });
2259
- const DefaultBootErrorPageComponent = createComponentExtension({
2260
- ref: coreComponentsRefs.bootErrorPage,
2261
- component: { sync: () => components.BootErrorPage }
2262
- });
2263
2246
  const DefaultNotFoundErrorPageComponent = createComponentExtension({
2264
- ref: coreComponentsRefs.notFoundErrorPage,
2247
+ ref: coreComponentRefs.notFoundErrorPage,
2265
2248
  component: { sync: () => components.NotFoundErrorPage }
2266
2249
  });
2267
2250
  const DefaultErrorBoundaryComponent = createComponentExtension({
2268
- ref: coreComponentsRefs.errorBoundaryFallback,
2269
- component: { sync: () => components.ErrorBoundaryFallback }
2251
+ ref: coreComponentRefs.errorBoundaryFallback,
2252
+ component: {
2253
+ sync: () => (props) => {
2254
+ const { plugin, error, resetError } = props;
2255
+ const title = `Error in ${plugin == null ? void 0 : plugin.id}`;
2256
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { title, error, defaultExpanded: true }, /* @__PURE__ */ React.createElement(Button$1, { variant: "outlined", onClick: resetError }, "Retry"));
2257
+ }
2258
+ }
2270
2259
  });
2271
2260
 
2272
2261
  const InternalAppContext = createContext(void 0);
@@ -2280,6 +2269,16 @@ getOrCreateGlobalSingleton(
2280
2269
  })
2281
2270
  );
2282
2271
 
2272
+ createApiRef({ id: "core.app-tree" });
2273
+
2274
+ createApiRef({
2275
+ id: "core.components"
2276
+ });
2277
+
2278
+ createApiRef({
2279
+ id: "core.analytics"
2280
+ });
2281
+
2283
2282
  function createExtensionDataRef(id) {
2284
2283
  return {
2285
2284
  id,
@@ -2361,7 +2360,8 @@ const RouteTracker = ({
2361
2360
  };
2362
2361
 
2363
2362
  const CoreRouter = createExtension({
2364
- id: "core.router",
2363
+ namespace: "core",
2364
+ name: "router",
2365
2365
  attachTo: { id: "core", input: "root" },
2366
2366
  inputs: {
2367
2367
  signInPage: createExtensionInput(
@@ -2383,7 +2383,7 @@ const CoreRouter = createExtension({
2383
2383
  factory({ inputs }) {
2384
2384
  var _a;
2385
2385
  return {
2386
- element: /* @__PURE__ */ React.createElement(AppRouter, { SignInPageComponent: (_a = inputs.signInPage) == null ? void 0 : _a.component }, inputs.children.element)
2386
+ element: /* @__PURE__ */ React.createElement(AppRouter, { SignInPageComponent: (_a = inputs.signInPage) == null ? void 0 : _a.output.component }, inputs.children.output.element)
2387
2387
  };
2388
2388
  }
2389
2389
  });
@@ -2403,7 +2403,7 @@ function SignInPageWrapper({
2403
2403
  children
2404
2404
  }) {
2405
2405
  const [identityApi, setIdentityApi] = useState();
2406
- const configApi = useApi$1(configApiRef);
2406
+ const configApi = useApi(configApiRef);
2407
2407
  const basePath = getBasePath(configApi);
2408
2408
  if (!identityApi) {
2409
2409
  return /* @__PURE__ */ React.createElement(Component, { onSignInSuccess: setIdentityApi });
@@ -2415,7 +2415,7 @@ function SignInPageWrapper({
2415
2415
  }
2416
2416
  function AppRouter(props) {
2417
2417
  const { children, SignInPageComponent } = props;
2418
- const configApi = useApi$1(configApiRef);
2418
+ const configApi = useApi(configApiRef);
2419
2419
  const basePath = getBasePath(configApi);
2420
2420
  const internalAppContext = useContext(InternalAppContext);
2421
2421
  if (!internalAppContext) {
@@ -2500,11 +2500,10 @@ const builtinExtensions = [
2500
2500
  CoreLayout,
2501
2501
  DefaultProgressComponent,
2502
2502
  DefaultErrorBoundaryComponent,
2503
- DefaultBootErrorPageComponent,
2504
2503
  DefaultNotFoundErrorPageComponent,
2505
2504
  LightTheme,
2506
2505
  DarkTheme
2507
- ];
2506
+ ].map((def) => resolveExtensionDefinition(def));
2508
2507
  function createExtensionTree(options) {
2509
2508
  const features = getAvailableFeatures(options.config);
2510
2509
  const tree = createAppTree({
@@ -2530,7 +2529,7 @@ function createExtensionTree(options) {
2530
2529
  return (_c = (_b = (_a = tree.nodes.get(id)) == null ? void 0 : _a.edges.attachments.get(inputName)) == null ? void 0 : _b.map(convertNode).filter((node) => Boolean(node))) != null ? _c : [];
2531
2530
  },
2532
2531
  getRootRoutes() {
2533
- return this.getExtensionAttachments("core.routes", "routes").map((node) => {
2532
+ return this.getExtensionAttachments("core/routes", "routes").map((node) => {
2534
2533
  const path = node.getData(coreExtensionData.routePath);
2535
2534
  const element = node.getData(coreExtensionData.reactElement);
2536
2535
  const routeRef = node.getData(coreExtensionData.routeRef);
@@ -2549,7 +2548,7 @@ function createExtensionTree(options) {
2549
2548
  const location = useRouteRef(props.routeRef);
2550
2549
  return /* @__PURE__ */ React.createElement(SidebarItem, { icon: props.icon, to: location(), text: props.title });
2551
2550
  };
2552
- return this.getExtensionAttachments("core.nav", "items").map((node, index) => {
2551
+ return this.getExtensionAttachments("core/nav", "items").map((node, index) => {
2553
2552
  const target = node.getData(coreExtensionData.navTarget);
2554
2553
  if (!target) {
2555
2554
  return null;
@@ -2618,11 +2617,6 @@ function createSpecializedApp(options) {
2618
2617
  builtinExtensions,
2619
2618
  config
2620
2619
  });
2621
- const appContext = createLegacyAppContext(
2622
- features.filter(
2623
- (f) => f.$$type === "@backstage/BackstagePlugin"
2624
- )
2625
- );
2626
2620
  const appIdentityProxy = new AppIdentityProxy();
2627
2621
  const apiHolder = createApiHolder(tree, config, appIdentityProxy);
2628
2622
  const featureFlagApi = apiHolder.get(featureFlagsApiRef);
@@ -2650,37 +2644,21 @@ function createSpecializedApp(options) {
2650
2644
  collectRouteIds(features)
2651
2645
  );
2652
2646
  const rootEl = tree.root.instance.getData(coreExtensionData.reactElement);
2653
- const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { ...routeInfo, routeBindings }, /* @__PURE__ */ React.createElement(
2647
+ const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { ...routeInfo, routeBindings }, /* @__PURE__ */ React.createElement(
2654
2648
  InternalAppContext.Provider,
2655
2649
  {
2656
2650
  value: { appIdentityProxy, routeObjects: routeInfo.routeObjects }
2657
2651
  },
2658
2652
  rootEl
2659
- )))));
2653
+ ))));
2660
2654
  return {
2661
2655
  createRoot() {
2662
2656
  return /* @__PURE__ */ React.createElement(App, null);
2663
2657
  }
2664
2658
  };
2665
2659
  }
2666
- function createLegacyAppContext(plugins) {
2667
- return {
2668
- getPlugins() {
2669
- return plugins.map(toLegacyPlugin);
2670
- },
2671
- getSystemIcon(key) {
2672
- return key in icons ? icons[key] : void 0;
2673
- },
2674
- getSystemIcons() {
2675
- return icons;
2676
- },
2677
- getComponents() {
2678
- return components;
2679
- }
2680
- };
2681
- }
2682
2660
  function createApiHolder(tree, configApi, appIdentityProxy) {
2683
- var _a, _b, _c, _d, _e, _f;
2661
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2684
2662
  const factoryRegistry = new ApiFactoryRegistry();
2685
2663
  const pluginApis = (_b = (_a = tree.root.edges.attachments.get("apis")) == null ? void 0 : _a.map((e) => {
2686
2664
  var _a2;
@@ -2690,6 +2668,14 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
2690
2668
  var _a2;
2691
2669
  return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.theme);
2692
2670
  }).filter((x) => !!x)) != null ? _d : [];
2671
+ const translationResources = (_f = (_e = tree.root.edges.attachments.get("translations")) == null ? void 0 : _e.map(
2672
+ (e) => {
2673
+ var _a2;
2674
+ return (_a2 = e.instance) == null ? void 0 : _a2.getData(createTranslationExtension.translationDataRef);
2675
+ }
2676
+ ).filter(
2677
+ (x) => !!x
2678
+ )) != null ? _f : [];
2693
2679
  for (const factory of [...apis, ...pluginApis]) {
2694
2680
  factoryRegistry.register("default", factory);
2695
2681
  }
@@ -2710,10 +2696,10 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
2710
2696
  getTree: () => ({ tree })
2711
2697
  })
2712
2698
  });
2713
- const componentsExtensions = (_f = (_e = tree.root.edges.attachments.get("components")) == null ? void 0 : _e.map((e) => {
2699
+ const componentsExtensions = (_h = (_g = tree.root.edges.attachments.get("components")) == null ? void 0 : _g.map((e) => {
2714
2700
  var _a2;
2715
2701
  return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.component);
2716
- }).filter((x) => !!x)) != null ? _f : [];
2702
+ }).filter((x) => !!x)) != null ? _h : [];
2717
2703
  const componentsMap = componentsExtensions.reduce(
2718
2704
  (components, component) => component ? components.set(component.ref, component == null ? void 0 : component.impl) : components,
2719
2705
  /* @__PURE__ */ new Map()
@@ -2734,13 +2720,6 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
2734
2720
  deps: {},
2735
2721
  factory: () => AppLanguageSelector.createWithStorage()
2736
2722
  });
2737
- factoryRegistry.register("default", {
2738
- api: translationApiRef,
2739
- deps: { languageApi: appLanguageApiRef },
2740
- factory: ({ languageApi }) => I18nextTranslationApi.create({
2741
- languageApi
2742
- })
2743
- });
2744
2723
  factoryRegistry.register("static", {
2745
2724
  api: configApiRef,
2746
2725
  deps: {},
@@ -2751,11 +2730,12 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
2751
2730
  deps: {},
2752
2731
  factory: () => AppLanguageSelector.createWithStorage()
2753
2732
  });
2754
- factoryRegistry.register("default", {
2733
+ factoryRegistry.register("static", {
2755
2734
  api: translationApiRef,
2756
2735
  deps: { languageApi: appLanguageApiRef },
2757
2736
  factory: ({ languageApi }) => I18nextTranslationApi.create({
2758
- languageApi
2737
+ languageApi,
2738
+ resources: translationResources
2759
2739
  })
2760
2740
  });
2761
2741
  for (const factory of apis) {