@backstage/frontend-app-api 0.3.0-next.0 → 0.3.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,38 @@
1
1
  # @backstage/frontend-app-api
2
2
 
3
+ ## 0.3.0-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#20999](https://github.com/backstage/backstage/pull/20999) [`fdc348d5d3`](https://github.com/backstage/backstage/commit/fdc348d5d30a98b52d8a756daba29d616418da93) Thanks [@Rugvip](https://github.com/Rugvip)! - The options parameter of `createApp` is now optional.
8
+
9
+ - [#20888](https://github.com/backstage/backstage/pull/20888) [`733bd95746`](https://github.com/backstage/backstage/commit/733bd95746b99ad8cdb4a7b87e8dc3e16d3b764a) Thanks [@Rugvip](https://github.com/Rugvip)! - Implement new `AppTreeApi`
10
+
11
+ - [#20999](https://github.com/backstage/backstage/pull/20999) [`fa28d4e6df`](https://github.com/backstage/backstage/commit/fa28d4e6dfcbee2bc8695b7b24289a401df96acd) Thanks [@Rugvip](https://github.com/Rugvip)! - No longer throw error on invalid input if the child is disabled.
12
+
13
+ - Updated dependencies
14
+ - @backstage/core-components@0.13.8-next.2
15
+ - @backstage/frontend-plugin-api@0.3.0-next.2
16
+ - @backstage/plugin-graphiql@0.3.0-next.2
17
+
18
+ ## 0.3.0-next.1
19
+
20
+ ### Patch Changes
21
+
22
+ - fe6d09953d: Fix for app node output IDs not being serialized correctly.
23
+ - 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`.
24
+ - 4d6fa921db: Internal refactor to rename the app graph to app tree
25
+ - Updated dependencies
26
+ - @backstage/frontend-plugin-api@0.3.0-next.1
27
+ - @backstage/plugin-graphiql@0.3.0-next.1
28
+ - @backstage/core-components@0.13.8-next.1
29
+ - @backstage/config@1.1.1
30
+ - @backstage/core-app-api@1.11.1-next.0
31
+ - @backstage/core-plugin-api@1.8.0-next.0
32
+ - @backstage/theme@0.4.4-next.0
33
+ - @backstage/types@1.1.1
34
+ - @backstage/version-bridge@1.0.7-next.0
35
+
3
36
  ## 0.3.0-next.0
4
37
 
5
38
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -58,7 +58,7 @@ declare function createExtensionTree(options: {
58
58
  config: Config;
59
59
  }): ExtensionTree;
60
60
  /** @public */
61
- declare function createApp(options: {
61
+ declare function createApp(options?: {
62
62
  features?: (BackstagePlugin | ExtensionOverrides)[];
63
63
  configLoader?: () => Promise<ConfigApi>;
64
64
  bindRoutes?(context: {
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
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';
3
+ import { createExtension, createExtensionInput, coreExtensionData, useRouteRef, createThemeExtension, appTreeApiRef } from '@backstage/frontend-plugin-api';
4
4
  import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, matchRoutes, generatePath, Route } from 'react-router-dom';
5
5
  import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
6
6
  import { makeStyles } from '@material-ui/core';
@@ -60,10 +60,10 @@ const Core = createExtension({
60
60
  output: {
61
61
  root: coreExtensionData.reactElement
62
62
  },
63
- factory({ bind, inputs }) {
64
- bind({
63
+ factory({ inputs }) {
64
+ return {
65
65
  root: inputs.root.element
66
- });
66
+ };
67
67
  }
68
68
  });
69
69
 
@@ -80,7 +80,7 @@ const CoreRoutes = createExtension({
80
80
  output: {
81
81
  element: coreExtensionData.reactElement
82
82
  },
83
- factory({ bind, inputs }) {
83
+ factory({ inputs }) {
84
84
  const Routes = () => {
85
85
  const element = useRoutes(
86
86
  inputs.routes.map((route) => ({
@@ -90,9 +90,9 @@ const CoreRoutes = createExtension({
90
90
  );
91
91
  return element;
92
92
  };
93
- bind({
93
+ return {
94
94
  element: /* @__PURE__ */ React.createElement(Routes, null)
95
- });
95
+ };
96
96
  }
97
97
  });
98
98
 
@@ -116,10 +116,10 @@ const CoreLayout = createExtension({
116
116
  output: {
117
117
  element: coreExtensionData.reactElement
118
118
  },
119
- factory({ bind, inputs }) {
120
- bind({
119
+ factory({ inputs }) {
120
+ return {
121
121
  element: /* @__PURE__ */ React.createElement(SidebarPage, null, inputs.nav.element, inputs.content.element)
122
- });
122
+ };
123
123
  }
124
124
  });
125
125
 
@@ -214,10 +214,10 @@ const CoreNav = createExtension({
214
214
  output: {
215
215
  element: coreExtensionData.reactElement
216
216
  },
217
- factory({ bind, inputs }) {
218
- bind({
217
+ factory({ inputs }) {
218
+ return {
219
219
  element: /* @__PURE__ */ React.createElement(Sidebar, null, /* @__PURE__ */ React.createElement(SidebarLogo, null), /* @__PURE__ */ React.createElement(SidebarDivider, null), inputs.items.map((item, index) => /* @__PURE__ */ React.createElement(SidebarNavItem, { ...item.target, key: index })))
220
- });
220
+ };
221
221
  }
222
222
  });
223
223
 
@@ -1827,7 +1827,7 @@ class SerializableAppNode {
1827
1827
  }
1828
1828
  toString() {
1829
1829
  const dataRefs = this.instance && [...this.instance.getDataRefs()];
1830
- const out = dataRefs && dataRefs.length > 0 ? ` out=[${[...dataRefs.keys()].join(", ")}]` : "";
1830
+ const out = dataRefs && dataRefs.length > 0 ? ` out=[${[...dataRefs].map((r) => r.id).join(", ")}]` : "";
1831
1831
  if (this.edges.attachments.size === 0) {
1832
1832
  return `<${this.spec.id}${out} />`;
1833
1833
  }
@@ -1840,7 +1840,7 @@ class SerializableAppNode {
1840
1840
  ].join("\n");
1841
1841
  }
1842
1842
  }
1843
- function resolveAppGraph(rootNodeId, specs) {
1843
+ function resolveAppTree(rootNodeId, specs) {
1844
1844
  const nodes = /* @__PURE__ */ new Map();
1845
1845
  let rootNode = void 0;
1846
1846
  const orphansByParent = /* @__PURE__ */ new Map();
@@ -1874,7 +1874,7 @@ function resolveAppGraph(rootNodeId, specs) {
1874
1874
  }
1875
1875
  }
1876
1876
  if (!rootNode) {
1877
- throw new Error(`No root node with id '${rootNodeId}' found in app graph`);
1877
+ throw new Error(`No root node with id '${rootNodeId}' found in app tree`);
1878
1878
  }
1879
1879
  return {
1880
1880
  root: rootNode,
@@ -2035,7 +2035,7 @@ function resolveAppNodeSpecs(options) {
2035
2035
  throw new Error(`Extension ${extensionId} does not exist`);
2036
2036
  }
2037
2037
  }
2038
- return configuredExtensions.filter((override) => !override.params.disabled).map((param) => ({
2038
+ return configuredExtensions.map((param) => ({
2039
2039
  id: param.extension.id,
2040
2040
  attachTo: param.params.attachTo,
2041
2041
  extension: param.extension,
@@ -2106,26 +2106,24 @@ function createAppNodeInstance(options) {
2106
2106
  );
2107
2107
  }
2108
2108
  try {
2109
- extension.factory({
2109
+ const namedOutputs = extension.factory({
2110
2110
  source,
2111
2111
  config: parsedConfig,
2112
- bind: (namedOutputs) => {
2113
- for (const [name, output] of Object.entries(namedOutputs)) {
2114
- const ref = extension.output[name];
2115
- if (!ref) {
2116
- throw new Error(`unknown output provided via '${name}'`);
2117
- }
2118
- if (extensionData.has(ref.id)) {
2119
- throw new Error(
2120
- `duplicate extension data '${ref.id}' received via output '${name}'`
2121
- );
2122
- }
2123
- extensionData.set(ref.id, output);
2124
- extensionDataRefs.add(ref);
2125
- }
2126
- },
2127
2112
  inputs: resolveInputs(extension.inputs, attachments)
2128
2113
  });
2114
+ for (const [name, output] of Object.entries(namedOutputs)) {
2115
+ const ref = extension.output[name];
2116
+ if (!ref) {
2117
+ throw new Error(`unknown output provided via '${name}'`);
2118
+ }
2119
+ if (extensionData.has(ref.id)) {
2120
+ throw new Error(
2121
+ `duplicate extension data '${ref.id}' received via output '${name}'`
2122
+ );
2123
+ }
2124
+ extensionData.set(ref.id, output);
2125
+ extensionDataRefs.add(ref);
2126
+ }
2129
2127
  } catch (e) {
2130
2128
  throw new Error(
2131
2129
  `Failed to instantiate extension '${id}'${e.name === "Error" ? `, ${e.message}` : `; caused by ${e}`}`
@@ -2157,7 +2155,9 @@ function instantiateAppNodeTree(rootNode) {
2157
2155
  }
2158
2156
  return [{ id: child.spec.id, instance: childInstance }];
2159
2157
  });
2160
- instantiatedAttachments.set(input, instantiatedChildren);
2158
+ if (instantiatedChildren.length > 0) {
2159
+ instantiatedAttachments.set(input, instantiatedChildren);
2160
+ }
2161
2161
  }
2162
2162
  node.instance = createAppNodeInstance({
2163
2163
  spec: node.spec,
@@ -2168,8 +2168,8 @@ function instantiateAppNodeTree(rootNode) {
2168
2168
  createInstance(rootNode);
2169
2169
  }
2170
2170
 
2171
- function createAppGraph(options) {
2172
- const appGraph = resolveAppGraph(
2171
+ function createAppTree(options) {
2172
+ const tree = resolveAppTree(
2173
2173
  "core",
2174
2174
  resolveAppNodeSpecs({
2175
2175
  features: options.features,
@@ -2178,8 +2178,8 @@ function createAppGraph(options) {
2178
2178
  forbidden: /* @__PURE__ */ new Set(["core"])
2179
2179
  })
2180
2180
  );
2181
- instantiateAppNodeTree(appGraph.root);
2182
- return appGraph;
2181
+ instantiateAppNodeTree(tree.root);
2182
+ return tree;
2183
2183
  }
2184
2184
 
2185
2185
  const builtinExtensions = [
@@ -2192,7 +2192,7 @@ const builtinExtensions = [
2192
2192
  ];
2193
2193
  function createExtensionTree(options) {
2194
2194
  const features = getAvailableFeatures(options.config);
2195
- const graph = createAppGraph({
2195
+ const tree = createAppTree({
2196
2196
  features,
2197
2197
  builtinExtensions,
2198
2198
  config: options.config
@@ -2208,11 +2208,11 @@ function createExtensionTree(options) {
2208
2208
  }
2209
2209
  return {
2210
2210
  getExtension(id) {
2211
- return convertNode(graph.nodes.get(id));
2211
+ return convertNode(tree.nodes.get(id));
2212
2212
  },
2213
2213
  getExtensionAttachments(id, inputName) {
2214
2214
  var _a, _b, _c;
2215
- return (_c = (_b = (_a = graph.nodes.get(id)) == null ? void 0 : _a.edges.attachments.get(inputName)) == null ? void 0 : _b.map(convertNode).filter((node) => Boolean(node))) != null ? _c : [];
2215
+ 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 : [];
2216
2216
  },
2217
2217
  getRootRoutes() {
2218
2218
  return this.getExtensionAttachments("core.routes", "routes").map((node) => {
@@ -2273,13 +2273,13 @@ function createApp(options) {
2273
2273
  overrideBaseUrlConfigs(defaultConfigLoaderSync())
2274
2274
  );
2275
2275
  const discoveredFeatures = getAvailableFeatures(config);
2276
- const loadedFeatures = (_d = await ((_c = options.featureLoader) == null ? void 0 : _c.call(options, { config }))) != null ? _d : [];
2276
+ const loadedFeatures = (_d = await ((_c = options == null ? void 0 : options.featureLoader) == null ? void 0 : _c.call(options, { config }))) != null ? _d : [];
2277
2277
  const allFeatures = deduplicateFeatures([
2278
2278
  ...discoveredFeatures,
2279
2279
  ...loadedFeatures,
2280
- ...(_e = options.features) != null ? _e : []
2280
+ ...(_e = options == null ? void 0 : options.features) != null ? _e : []
2281
2281
  ]);
2282
- const appGraph = createAppGraph({
2282
+ const tree = createAppTree({
2283
2283
  features: allFeatures,
2284
2284
  builtinExtensions,
2285
2285
  config
@@ -2290,19 +2290,17 @@ function createApp(options) {
2290
2290
  )
2291
2291
  );
2292
2292
  const routeIds = collectRouteIds(allFeatures);
2293
- const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: createApiHolder(appGraph.root, config) }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(
2293
+ const App = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: createApiHolder(tree, config) }, /* @__PURE__ */ React.createElement(AppContextProvider, { appContext }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(
2294
2294
  RoutingProvider,
2295
2295
  {
2296
- ...extractRouteInfoFromAppNode(appGraph.root),
2296
+ ...extractRouteInfoFromAppNode(tree.root),
2297
2297
  routeBindings: resolveRouteBindings(
2298
- options.bindRoutes,
2298
+ options == null ? void 0 : options.bindRoutes,
2299
2299
  config,
2300
2300
  routeIds
2301
2301
  )
2302
2302
  },
2303
- /* @__PURE__ */ React.createElement(BrowserRouter, null, appGraph.root.instance.getData(
2304
- coreExtensionData.reactElement
2305
- ))
2303
+ /* @__PURE__ */ React.createElement(BrowserRouter, null, tree.root.instance.getData(coreExtensionData.reactElement))
2306
2304
  ))));
2307
2305
  return { default: App };
2308
2306
  }
@@ -2359,14 +2357,14 @@ function createLegacyAppContext(plugins) {
2359
2357
  }
2360
2358
  };
2361
2359
  }
2362
- function createApiHolder(core, configApi) {
2360
+ function createApiHolder(tree, configApi) {
2363
2361
  var _a, _b, _c, _d;
2364
2362
  const factoryRegistry = new ApiFactoryRegistry();
2365
- const pluginApis = (_b = (_a = core.edges.attachments.get("apis")) == null ? void 0 : _a.map((e) => {
2363
+ const pluginApis = (_b = (_a = tree.root.edges.attachments.get("apis")) == null ? void 0 : _a.map((e) => {
2366
2364
  var _a2;
2367
2365
  return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.apiFactory);
2368
2366
  }).filter((x) => !!x)) != null ? _b : [];
2369
- const themeExtensions = (_d = (_c = core.edges.attachments.get("themes")) == null ? void 0 : _c.map((e) => {
2367
+ const themeExtensions = (_d = (_c = tree.root.edges.attachments.get("themes")) == null ? void 0 : _c.map((e) => {
2370
2368
  var _a2;
2371
2369
  return (_a2 = e.instance) == null ? void 0 : _a2.getData(coreExtensionData.theme);
2372
2370
  }).filter((x) => !!x)) != null ? _d : [];
@@ -2409,6 +2407,13 @@ function createApiHolder(core, configApi) {
2409
2407
  return appIdentityProxy;
2410
2408
  }
2411
2409
  });
2410
+ factoryRegistry.register("static", {
2411
+ api: appTreeApiRef,
2412
+ deps: {},
2413
+ factory: () => ({
2414
+ getTree: () => ({ tree })
2415
+ })
2416
+ });
2412
2417
  factoryRegistry.register("static", {
2413
2418
  api: appThemeApiRef,
2414
2419
  deps: {},