@backstage/frontend-app-api 0.2.0-next.1 → 0.2.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,27 @@
1
1
  # @backstage/frontend-app-api
2
2
 
3
+ ## 0.2.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - 4461d87d5a: Removed support for the new `useRouteRef`.
8
+
9
+ ### Patch Changes
10
+
11
+ - 5072824817: Implement `toString()` and `toJSON()` for extension instances.
12
+ - 06432f900c: Updates for `at` -> `attachTo` refactor.
13
+ - 1718ec75b7: Added support for the existing routing system.
14
+ - Updated dependencies
15
+ - @backstage/frontend-plugin-api@0.2.0-next.2
16
+ - @backstage/core-app-api@1.11.0-next.2
17
+ - @backstage/core-components@0.13.6-next.2
18
+ - @backstage/core-plugin-api@1.7.0-next.1
19
+ - @backstage/plugin-graphiql@0.2.55-next.2
20
+ - @backstage/theme@0.4.3-next.0
21
+ - @backstage/config@1.1.1-next.0
22
+ - @backstage/types@1.1.1
23
+ - @backstage/version-bridge@1.0.5
24
+
3
25
  ## 0.2.0-next.1
4
26
 
5
27
  ### Patch Changes
package/dist/index.esm.js CHANGED
@@ -1,14 +1,14 @@
1
- import React, { createContext, useMemo, useState, useEffect } from 'react';
1
+ import React, { useMemo, useState, useEffect } from 'react';
2
2
  import { ConfigReader } from '@backstage/config';
3
- import { createExtension, createExtensionInput, coreExtensionData, useRouteRef, createThemeExtension } from '@backstage/frontend-plugin-api';
4
- import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, Route } from 'react-router-dom';
3
+ import { createExtension, createExtensionInput, coreExtensionData, createThemeExtension } from '@backstage/frontend-plugin-api';
4
+ import { useRoutes, matchRoutes, generatePath, BrowserRouter, useInRouterContext, MemoryRouter, Route } from 'react-router-dom';
5
5
  import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
6
+ import { useRouteRef, useApi, 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
7
  import { makeStyles } from '@material-ui/core';
7
8
  import mapValues from 'lodash/mapValues';
8
- import { useApi, appThemeApiRef, FeatureFlagState, createApiFactory, discoveryApiRef, configApiRef, alertApiRef, analyticsApiRef, errorApiRef, storageApiRef, fetchApiRef, identityApiRef, oauthRequestApiRef, googleAuthApiRef, microsoftAuthApiRef, githubAuthApiRef, oktaAuthApiRef, gitlabAuthApiRef, oneloginAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, atlassianAuthApiRef, attachComponentData, useRouteRef as useRouteRef$1, featureFlagsApiRef } from '@backstage/core-plugin-api';
9
9
  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';
10
10
  import useObservable from 'react-use/lib/useObservable';
11
- import { createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
11
+ import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton } from '@backstage/version-bridge';
12
12
  import { permissionApiRef, IdentityPermissionApi } from '@backstage/plugin-permission-react';
13
13
  import Button from '@material-ui/core/Button';
14
14
  import MuiApartmentIcon from '@material-ui/icons/Apartment';
@@ -38,7 +38,7 @@ import LightIcon from '@material-ui/icons/WbSunny';
38
38
 
39
39
  const Core = createExtension({
40
40
  id: "core",
41
- at: "root",
41
+ attachTo: { id: "root", input: "default" },
42
42
  inputs: {
43
43
  apis: createExtensionInput({
44
44
  api: coreExtensionData.apiFactory
@@ -51,7 +51,7 @@ const Core = createExtension({
51
51
 
52
52
  const CoreRoutes = createExtension({
53
53
  id: "core.routes",
54
- at: "core.layout/content",
54
+ attachTo: { id: "core.layout", input: "content" },
55
55
  inputs: {
56
56
  routes: createExtensionInput({
57
57
  path: coreExtensionData.routePath,
@@ -80,7 +80,7 @@ const CoreRoutes = createExtension({
80
80
 
81
81
  const CoreLayout = createExtension({
82
82
  id: "core.layout",
83
- at: "root",
83
+ attachTo: { id: "root", input: "default" },
84
84
  inputs: {
85
85
  nav: createExtensionInput(
86
86
  {
@@ -182,12 +182,12 @@ const SidebarLogo = () => {
182
182
  };
183
183
  const SidebarNavItem = (props) => {
184
184
  const { icon: Icon, title, routeRef } = props;
185
- const to = useRouteRef(routeRef)();
185
+ const to = useRouteRef(routeRef)({});
186
186
  return /* @__PURE__ */ React.createElement(SidebarItem, { to, icon: Icon, text: title });
187
187
  };
188
188
  const CoreNav = createExtension({
189
189
  id: "core.nav",
190
- at: "core.layout/nav",
190
+ attachTo: { id: "core.layout", input: "nav" },
191
191
  inputs: {
192
192
  items: createExtensionInput({
193
193
  target: coreExtensionData.navTarget
@@ -203,6 +203,31 @@ const CoreNav = createExtension({
203
203
  }
204
204
  });
205
205
 
206
+ var __defProp$2 = Object.defineProperty;
207
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
208
+ var __publicField$2 = (obj, key, value) => {
209
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
210
+ return value;
211
+ };
212
+ var __accessCheck = (obj, member, msg) => {
213
+ if (!member.has(obj))
214
+ throw TypeError("Cannot " + msg);
215
+ };
216
+ var __privateGet = (obj, member, getter) => {
217
+ __accessCheck(obj, member, "read from private field");
218
+ return getter ? getter.call(obj) : member.get(obj);
219
+ };
220
+ var __privateAdd = (obj, member, value) => {
221
+ if (member.has(obj))
222
+ throw TypeError("Cannot add the same private member more than once");
223
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
224
+ };
225
+ var __privateSet = (obj, member, value, setter) => {
226
+ __accessCheck(obj, member, "write to private field");
227
+ setter ? setter.call(obj, value) : member.set(obj, value);
228
+ return value;
229
+ };
230
+ var _extensionData;
206
231
  function resolveInputData(dataMap, attachment, inputName) {
207
232
  return mapValues(dataMap, (ref) => {
208
233
  const value = attachment.getData(ref);
@@ -240,6 +265,46 @@ function resolveInputs(inputMap, attachments) {
240
265
  );
241
266
  });
242
267
  }
268
+ function indent(str) {
269
+ return str.replace(/^/gm, " ");
270
+ }
271
+ class ExtensionInstanceImpl {
272
+ constructor(id, extensionData, attachments, source) {
273
+ __publicField$2(this, "$$type", "@backstage/ExtensionInstance");
274
+ __publicField$2(this, "id");
275
+ __privateAdd(this, _extensionData, void 0);
276
+ __publicField$2(this, "attachments");
277
+ __publicField$2(this, "source");
278
+ this.id = id;
279
+ __privateSet(this, _extensionData, extensionData);
280
+ this.attachments = attachments;
281
+ this.source = source;
282
+ }
283
+ getData(ref) {
284
+ return __privateGet(this, _extensionData).get(ref.id);
285
+ }
286
+ toJSON() {
287
+ return {
288
+ id: this.id,
289
+ output: __privateGet(this, _extensionData).size > 0 ? [...__privateGet(this, _extensionData).keys()] : void 0,
290
+ attachments: this.attachments.size > 0 ? Object.fromEntries(this.attachments) : void 0
291
+ };
292
+ }
293
+ toString() {
294
+ const out = __privateGet(this, _extensionData).size > 0 ? ` out=[${[...__privateGet(this, _extensionData).keys()].join(", ")}]` : "";
295
+ if (this.attachments.size === 0) {
296
+ return `<${this.id}${out} />`;
297
+ }
298
+ return [
299
+ `<${this.id}${out}>`,
300
+ ...[...this.attachments.entries()].map(
301
+ ([k, v]) => indent([`${k} [`, ...v.map((e) => indent(e.toString())), `]`].join("\n"))
302
+ ),
303
+ `</${this.id}>`
304
+ ].join("\n");
305
+ }
306
+ }
307
+ _extensionData = new WeakMap();
243
308
  function createExtensionInstance(options) {
244
309
  var _a;
245
310
  const { extension, config, source, attachments } = options;
@@ -277,17 +342,15 @@ function createExtensionInstance(options) {
277
342
  `Failed to instantiate extension '${extension.id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e}`}`
278
343
  );
279
344
  }
280
- return {
281
- $$type: "@backstage/ExtensionInstance",
282
- id: options.extension.id,
283
- getData(ref) {
284
- return extensionData.get(ref.id);
285
- },
286
- attachments
287
- };
345
+ return new ExtensionInstanceImpl(
346
+ options.extension.id,
347
+ extensionData,
348
+ attachments,
349
+ source
350
+ );
288
351
  }
289
352
 
290
- const knownExtensionParameters = ["at", "disabled", "config"];
353
+ const knownExtensionParameters = ["attachTo", "disabled", "config"];
291
354
  function readAppExtensionParameters(rootConfig) {
292
355
  const arr = rootConfig.getOptional("app.extensions");
293
356
  if (!Array.isArray(arr)) {
@@ -353,14 +416,28 @@ function expandShorthandExtensionParameters(arrayEntry, arrayIndex) {
353
416
  if (typeof value !== "object" || Array.isArray(value)) {
354
417
  throw new Error(errorMsg("value must be a boolean or object", id));
355
418
  }
356
- const at = value.at;
419
+ const attachTo = value.attachTo;
357
420
  const disabled = value.disabled;
358
421
  const config = value.config;
359
- if (at !== void 0 && typeof at !== "string") {
360
- throw new Error(errorMsg("must be a string", id, "at"));
361
- } else if (disabled !== void 0 && typeof disabled !== "boolean") {
422
+ if (attachTo !== void 0) {
423
+ if (attachTo === null || typeof attachTo !== "object" || Array.isArray(attachTo)) {
424
+ throw new Error(errorMsg("must be an object", id, "attachTo"));
425
+ }
426
+ if (typeof attachTo.id !== "string" || attachTo.id === "") {
427
+ throw new Error(
428
+ errorMsg("must be a non-empty string", id, "attachTo.id")
429
+ );
430
+ }
431
+ if (typeof attachTo.input !== "string" || attachTo.input === "") {
432
+ throw new Error(
433
+ errorMsg("must be a non-empty string", id, "attachTo.input")
434
+ );
435
+ }
436
+ }
437
+ if (disabled !== void 0 && typeof disabled !== "boolean") {
362
438
  throw new Error(errorMsg("must be a boolean", id, "disabled"));
363
- } else if (config !== void 0 && (typeof config !== "object" || config === null || Array.isArray(config))) {
439
+ }
440
+ if (config !== void 0 && (typeof config !== "object" || config === null || Array.isArray(config))) {
364
441
  throw new Error(errorMsg("must be an object", id, "config"));
365
442
  }
366
443
  const unknownKeys = Object.keys(value).filter(
@@ -379,7 +456,7 @@ function expandShorthandExtensionParameters(arrayEntry, arrayIndex) {
379
456
  }
380
457
  return {
381
458
  id,
382
- at,
459
+ attachTo,
383
460
  disabled,
384
461
  config
385
462
  };
@@ -402,7 +479,7 @@ function mergeExtensionParameters(options) {
402
479
  extension,
403
480
  params: {
404
481
  source,
405
- at: extension.at,
482
+ attachTo: extension.attachTo,
406
483
  disabled: extension.disabled,
407
484
  config: void 0
408
485
  }
@@ -411,7 +488,7 @@ function mergeExtensionParameters(options) {
411
488
  extension,
412
489
  params: {
413
490
  source: void 0,
414
- at: extension.at,
491
+ attachTo: extension.attachTo,
415
492
  disabled: extension.disabled,
416
493
  config: void 0
417
494
  }
@@ -456,8 +533,8 @@ function mergeExtensionParameters(options) {
456
533
  );
457
534
  if (existingIndex !== -1) {
458
535
  const existing = overrides[existingIndex];
459
- if (overrideParam.at) {
460
- existing.params.at = overrideParam.at;
536
+ if (overrideParam.attachTo) {
537
+ existing.params.attachTo = overrideParam.attachTo;
461
538
  }
462
539
  if (overrideParam.config) {
463
540
  existing.params.config = overrideParam.config;
@@ -475,31 +552,12 @@ function mergeExtensionParameters(options) {
475
552
  }
476
553
  return overrides.filter((override) => !override.params.disabled).map((param) => ({
477
554
  extension: param.extension,
478
- at: param.params.at,
555
+ attachTo: param.params.attachTo,
479
556
  source: param.params.source,
480
557
  config: param.params.config
481
558
  }));
482
559
  }
483
560
 
484
- const RoutingContext = createContext({
485
- resolve: () => () => ""
486
- });
487
- class RouteResolver {
488
- constructor(routePaths) {
489
- this.routePaths = routePaths;
490
- }
491
- resolve(anyRouteRef) {
492
- const basePath = this.routePaths.get(anyRouteRef);
493
- if (!basePath) {
494
- return void 0;
495
- }
496
- return () => basePath;
497
- }
498
- }
499
- function RoutingProvider(props) {
500
- return /* @__PURE__ */ React.createElement(RoutingContext.Provider, { value: new RouteResolver(props.routePaths) }, props.children);
501
- }
502
-
503
561
  function getAvailablePlugins() {
504
562
  var _a;
505
563
  const discovered = window["__@backstage/discovered__"];
@@ -817,6 +875,179 @@ function overrideBaseUrlConfigs(inputConfigs) {
817
875
  return configs;
818
876
  }
819
877
 
878
+ const routeRefType = getOrCreateGlobalSingleton(
879
+ "route-ref-type",
880
+ () => Symbol("route-ref-type")
881
+ );
882
+ function isRouteRef(routeRef) {
883
+ return routeRef[routeRefType] === "absolute";
884
+ }
885
+ function isSubRouteRef(routeRef) {
886
+ return routeRef[routeRefType] === "sub";
887
+ }
888
+ function isExternalRouteRef(routeRef) {
889
+ return routeRef[routeRefType] === "external";
890
+ }
891
+
892
+ function joinPaths$1(...paths) {
893
+ const normalized = paths.join("/").replace(/\/\/+/g, "/");
894
+ if (normalized !== "/" && normalized.endsWith("/")) {
895
+ return normalized.slice(0, -1);
896
+ }
897
+ return normalized;
898
+ }
899
+
900
+ function resolveTargetRef(anyRouteRef, routePaths, routeBindings) {
901
+ let targetRef;
902
+ let subRoutePath = "";
903
+ if (isRouteRef(anyRouteRef)) {
904
+ targetRef = anyRouteRef;
905
+ } else if (isSubRouteRef(anyRouteRef)) {
906
+ targetRef = anyRouteRef.parent;
907
+ subRoutePath = anyRouteRef.path;
908
+ } else if (isExternalRouteRef(anyRouteRef)) {
909
+ const resolvedRoute = routeBindings.get(anyRouteRef);
910
+ if (!resolvedRoute) {
911
+ return [void 0, ""];
912
+ }
913
+ if (isRouteRef(resolvedRoute)) {
914
+ targetRef = resolvedRoute;
915
+ } else if (isSubRouteRef(resolvedRoute)) {
916
+ targetRef = resolvedRoute.parent;
917
+ subRoutePath = resolvedRoute.path;
918
+ } else {
919
+ throw new Error(
920
+ `ExternalRouteRef was bound to invalid target, ${resolvedRoute}`
921
+ );
922
+ }
923
+ } else if (anyRouteRef[routeRefType]) {
924
+ throw new Error(
925
+ `Unknown or invalid route ref type, ${anyRouteRef[routeRefType]}`
926
+ );
927
+ } else {
928
+ throw new Error(`Unknown object passed to useRouteRef, got ${anyRouteRef}`);
929
+ }
930
+ if (!targetRef) {
931
+ return [void 0, ""];
932
+ }
933
+ const resolvedPath = routePaths.get(targetRef);
934
+ if (resolvedPath === void 0) {
935
+ return [void 0, ""];
936
+ }
937
+ const targetPath = joinPaths$1(resolvedPath, subRoutePath);
938
+ return [targetRef, targetPath];
939
+ }
940
+ function resolveBasePath(targetRef, sourceLocation, routePaths, routeParents, routeObjects) {
941
+ var _a;
942
+ const match = (_a = matchRoutes(routeObjects, sourceLocation)) != null ? _a : [];
943
+ const refDiffList = Array();
944
+ let matchIndex = -1;
945
+ for (let targetSearchRef = targetRef; targetSearchRef; targetSearchRef = routeParents.get(targetSearchRef)) {
946
+ matchIndex = match.findIndex(
947
+ (m) => m.route.routeRefs.has(targetSearchRef)
948
+ );
949
+ if (matchIndex !== -1) {
950
+ break;
951
+ }
952
+ refDiffList.unshift(targetSearchRef);
953
+ }
954
+ if (refDiffList.length === 0) {
955
+ matchIndex -= 1;
956
+ }
957
+ const parentPath = matchIndex === -1 ? "" : match[matchIndex].pathname;
958
+ const diffPaths = refDiffList.slice(0, -1).map((ref) => {
959
+ const path = routePaths.get(ref);
960
+ if (path === void 0) {
961
+ throw new Error(`No path for ${ref}`);
962
+ }
963
+ if (path.includes(":")) {
964
+ throw new Error(
965
+ `Cannot route to ${targetRef} with parent ${ref} as it has parameters`
966
+ );
967
+ }
968
+ return path;
969
+ });
970
+ return `${joinPaths$1(parentPath, ...diffPaths)}/`;
971
+ }
972
+ class RouteResolver {
973
+ constructor(routePaths, routeParents, routeObjects, routeBindings, appBasePath) {
974
+ this.routePaths = routePaths;
975
+ this.routeParents = routeParents;
976
+ this.routeObjects = routeObjects;
977
+ this.routeBindings = routeBindings;
978
+ this.appBasePath = appBasePath;
979
+ }
980
+ resolve(anyRouteRef, sourceLocation) {
981
+ const [targetRef, targetPath] = resolveTargetRef(
982
+ anyRouteRef,
983
+ this.routePaths,
984
+ this.routeBindings
985
+ );
986
+ if (!targetRef) {
987
+ return void 0;
988
+ }
989
+ let relativeSourceLocation;
990
+ if (typeof sourceLocation === "string") {
991
+ relativeSourceLocation = this.trimPath(sourceLocation);
992
+ } else if (sourceLocation.pathname) {
993
+ relativeSourceLocation = {
994
+ ...sourceLocation,
995
+ pathname: this.trimPath(sourceLocation.pathname)
996
+ };
997
+ } else {
998
+ relativeSourceLocation = sourceLocation;
999
+ }
1000
+ const basePath = this.appBasePath + resolveBasePath(
1001
+ targetRef,
1002
+ relativeSourceLocation,
1003
+ this.routePaths,
1004
+ this.routeParents,
1005
+ this.routeObjects
1006
+ );
1007
+ const routeFunc = (...[params]) => {
1008
+ const encodedParams = params && mapValues(params, (value) => {
1009
+ if (typeof value === "string") {
1010
+ return value.replaceAll(/[&?#;\/]/g, (c) => encodeURIComponent(c));
1011
+ }
1012
+ return value;
1013
+ });
1014
+ return joinPaths$1(basePath, generatePath(targetPath, encodedParams));
1015
+ };
1016
+ return routeFunc;
1017
+ }
1018
+ trimPath(targetPath) {
1019
+ if (!targetPath) {
1020
+ return targetPath;
1021
+ }
1022
+ if (targetPath.startsWith(this.appBasePath)) {
1023
+ return targetPath.slice(this.appBasePath.length);
1024
+ }
1025
+ return targetPath;
1026
+ }
1027
+ }
1028
+
1029
+ const RoutingContext = createVersionedContext(
1030
+ "routing-context"
1031
+ );
1032
+ const RoutingProvider = ({
1033
+ routePaths,
1034
+ routeParents,
1035
+ routeObjects,
1036
+ routeBindings,
1037
+ basePath = "",
1038
+ children
1039
+ }) => {
1040
+ const resolver = new RouteResolver(
1041
+ routePaths,
1042
+ routeParents,
1043
+ routeObjects,
1044
+ routeBindings,
1045
+ basePath
1046
+ );
1047
+ const versionedValue = createVersionedValueMap({ 1: resolver });
1048
+ return /* @__PURE__ */ React.createElement(RoutingContext.Provider, { value: versionedValue }, children);
1049
+ };
1050
+
820
1051
  const apis = [
821
1052
  createApiFactory({
822
1053
  api: discoveryApiRef,
@@ -1097,6 +1328,93 @@ const DarkTheme = createThemeExtension({
1097
1328
  Provider: ({ children }) => /* @__PURE__ */ React.createElement(UnifiedThemeProvider, { theme: themes.dark, children })
1098
1329
  });
1099
1330
 
1331
+ const MATCH_ALL_ROUTE = {
1332
+ caseSensitive: false,
1333
+ path: "*",
1334
+ element: "match-all",
1335
+ // These elements aren't used, so we add in a bit of debug information
1336
+ routeRefs: /* @__PURE__ */ new Set(),
1337
+ plugins: /* @__PURE__ */ new Set()
1338
+ };
1339
+ function joinPaths(...paths) {
1340
+ const normalized = paths.join("/").replace(/\/\/+/g, "/");
1341
+ if (normalized !== "/" && normalized.endsWith("/")) {
1342
+ return normalized.slice(0, -1);
1343
+ }
1344
+ return normalized;
1345
+ }
1346
+ function extractRouteInfoFromInstanceTree(roots) {
1347
+ const routePaths = /* @__PURE__ */ new Map();
1348
+ const routeParents = /* @__PURE__ */ new Map();
1349
+ const routeObjects = new Array();
1350
+ function visit(current, collectedPath, foundRefForCollectedPath = false, parentRef, candidateParentRef, parentObj) {
1351
+ var _a, _b;
1352
+ const routePath = (_a = current.getData(coreExtensionData.routePath)) == null ? void 0 : _a.replace(/^\//, "");
1353
+ const routeRef = current.getData(coreExtensionData.routeRef);
1354
+ const parentChildren = (_b = parentObj == null ? void 0 : parentObj.children) != null ? _b : routeObjects;
1355
+ let currentObj = parentObj;
1356
+ let newCollectedPath = collectedPath;
1357
+ let newFoundRefForCollectedPath = foundRefForCollectedPath;
1358
+ let newParentRef = parentRef;
1359
+ let newCandidateParentRef = candidateParentRef;
1360
+ if (routePath !== void 0) {
1361
+ currentObj = {
1362
+ path: routePath,
1363
+ element: "mounted",
1364
+ routeRefs: /* @__PURE__ */ new Set(),
1365
+ caseSensitive: false,
1366
+ children: [MATCH_ALL_ROUTE],
1367
+ plugins: /* @__PURE__ */ new Set()
1368
+ };
1369
+ parentChildren.push(currentObj);
1370
+ newParentRef = candidateParentRef;
1371
+ newCandidateParentRef = void 0;
1372
+ if (newFoundRefForCollectedPath) {
1373
+ newCollectedPath = routePath;
1374
+ newFoundRefForCollectedPath = false;
1375
+ } else {
1376
+ newCollectedPath = collectedPath ? joinPaths(collectedPath, routePath) : routePath;
1377
+ }
1378
+ }
1379
+ if (routeRef) {
1380
+ const routeRefId = routeRef.id;
1381
+ if (routeRefId !== current.id) {
1382
+ throw new Error(
1383
+ `Route ref '${routeRefId}' must have the same ID as extension '${current.id}'`
1384
+ );
1385
+ }
1386
+ if (!newCandidateParentRef) {
1387
+ newCandidateParentRef = routeRef;
1388
+ }
1389
+ if (newCollectedPath !== void 0) {
1390
+ routePaths.set(routeRef, newCollectedPath);
1391
+ newFoundRefForCollectedPath = true;
1392
+ }
1393
+ routeParents.set(routeRef, newParentRef);
1394
+ currentObj == null ? void 0 : currentObj.routeRefs.add(routeRef);
1395
+ if (current.source) {
1396
+ currentObj == null ? void 0 : currentObj.plugins.add(toLegacyPlugin(current.source));
1397
+ }
1398
+ }
1399
+ for (const children of current.attachments.values()) {
1400
+ for (const child of children) {
1401
+ visit(
1402
+ child,
1403
+ newCollectedPath,
1404
+ newFoundRefForCollectedPath,
1405
+ newParentRef,
1406
+ newCandidateParentRef,
1407
+ currentObj
1408
+ );
1409
+ }
1410
+ }
1411
+ }
1412
+ for (const root of roots) {
1413
+ visit(root);
1414
+ }
1415
+ return { routePaths, routeParents, routeObjects };
1416
+ }
1417
+
1100
1418
  function createExtensionTree(options) {
1101
1419
  const plugins = getAvailablePlugins();
1102
1420
  const { instances } = createInstances({
@@ -1128,7 +1446,7 @@ function createExtensionTree(options) {
1128
1446
  },
1129
1447
  getSidebarItems() {
1130
1448
  const RoutedSidebarItem = (props) => {
1131
- const location = useRouteRef$1(props.routeRef);
1449
+ const location = useRouteRef(props.routeRef);
1132
1450
  return /* @__PURE__ */ React.createElement(SidebarItem, { icon: props.icon, to: location(), text: props.title });
1133
1451
  };
1134
1452
  return this.getExtensionAttachments("core.nav", "items").map((node, index) => {
@@ -1166,7 +1484,8 @@ function createInstances(options) {
1166
1484
  });
1167
1485
  const attachmentMap = /* @__PURE__ */ new Map();
1168
1486
  for (const instanceParams of extensionParams) {
1169
- const [extensionId, pointId = "default"] = instanceParams.at.split("/");
1487
+ const extensionId = instanceParams.attachTo.id;
1488
+ const pointId = instanceParams.attachTo.input;
1170
1489
  let pointMap = attachmentMap.get(extensionId);
1171
1490
  if (!pointMap) {
1172
1491
  pointMap = /* @__PURE__ */ new Map();
@@ -1224,7 +1543,7 @@ function createApp(options) {
1224
1543
  plugins: allPlugins,
1225
1544
  config
1226
1545
  });
1227
- const routePaths = extractRouteInfoFromInstanceTree(rootInstances);
1546
+ const routeInfo = extractRouteInfoFromInstanceTree(rootInstances);
1228
1547
  const coreInstance = rootInstances.find(({ id }) => id === "core");
1229
1548
  if (!coreInstance) {
1230
1549
  throw Error("Unable to find core extension instance");
@@ -1232,7 +1551,9 @@ function createApp(options) {
1232
1551
  const apiHolder = createApiHolder(coreInstance, config);
1233
1552
  const appContext = createLegacyAppContext(allPlugins);
1234
1553
  const rootElements = rootInstances.map((e) => /* @__PURE__ */ React.createElement(React.Fragment, { key: e.id }, e.getData(coreExtensionData.reactElement))).filter((x) => !!x);
1235
- const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { routePaths }, /* @__PURE__ */ React.createElement(BrowserRouter, null, rootElements)))));
1554
+ 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__ */ new Map(
1555
+ /* TODO */
1556
+ ) }, /* @__PURE__ */ React.createElement(BrowserRouter, null, rootElements)))));
1236
1557
  return { default: App };
1237
1558
  }
1238
1559
  return {
@@ -1242,25 +1563,35 @@ function createApp(options) {
1242
1563
  }
1243
1564
  };
1244
1565
  }
1566
+ const legacyPluginStore = getOrCreateGlobalSingleton(
1567
+ "legacy-plugin-compatibility-store",
1568
+ () => /* @__PURE__ */ new WeakMap()
1569
+ );
1245
1570
  function toLegacyPlugin(plugin) {
1571
+ let legacy = legacyPluginStore.get(plugin);
1572
+ if (legacy) {
1573
+ return legacy;
1574
+ }
1246
1575
  const errorMsg = "Not implemented in legacy plugin compatibility layer";
1247
1576
  const notImplemented = () => {
1248
1577
  throw new Error(errorMsg);
1249
1578
  };
1250
- return {
1579
+ legacy = {
1251
1580
  getId() {
1252
1581
  return plugin.id;
1253
1582
  },
1254
1583
  get routes() {
1255
- throw new Error(errorMsg);
1584
+ return {};
1256
1585
  },
1257
1586
  get externalRoutes() {
1258
- throw new Error(errorMsg);
1587
+ return {};
1259
1588
  },
1260
1589
  getApis: notImplemented,
1261
1590
  getFeatureFlags: notImplemented,
1262
1591
  provide: notImplemented
1263
1592
  };
1593
+ legacyPluginStore.set(plugin, legacy);
1594
+ return legacy;
1264
1595
  }
1265
1596
  function createLegacyAppContext(plugins) {
1266
1597
  return {
@@ -1343,33 +1674,6 @@ function createApiHolder(coreExtension, configApi) {
1343
1674
  ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis());
1344
1675
  return new ApiResolver(factoryRegistry);
1345
1676
  }
1346
- function extractRouteInfoFromInstanceTree(roots) {
1347
- const results = /* @__PURE__ */ new Map();
1348
- function visit(current, basePath) {
1349
- var _a;
1350
- const routePath = (_a = current.getData(coreExtensionData.routePath)) != null ? _a : "";
1351
- const routeRef = current.getData(coreExtensionData.routeRef);
1352
- const fullPath = basePath + routePath;
1353
- if (routeRef) {
1354
- const routeRefId = routeRef.id;
1355
- if (routeRefId !== current.id) {
1356
- throw new Error(
1357
- `Route ref '${routeRefId}' must have the same ID as extension '${current.id}'`
1358
- );
1359
- }
1360
- results.set(routeRef, fullPath);
1361
- }
1362
- for (const children of current.attachments.values()) {
1363
- for (const child of children) {
1364
- visit(child, fullPath);
1365
- }
1366
- }
1367
- }
1368
- for (const root of roots) {
1369
- visit(root, "");
1370
- }
1371
- return results;
1372
- }
1373
1677
 
1374
1678
  export { createApp, createExtensionTree };
1375
1679
  //# sourceMappingURL=index.esm.js.map