@backstage/frontend-app-api 0.4.1-next.2 → 0.5.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/index.esm.js +104 -41
- package/dist/index.esm.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @backstage/frontend-app-api
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`.
|
|
8
|
+
- 074dfe3: Attaching extensions to an input that does not exist is now a warning rather than an error.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map.
|
|
13
|
+
- 516fd3e: Updated README to reflect release status
|
|
14
|
+
- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI).
|
|
15
|
+
- 5fe6600: add oauth dialog and alert display to the root elements
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @backstage/frontend-plugin-api@0.5.0
|
|
18
|
+
- @backstage/core-components@0.13.10
|
|
19
|
+
- @backstage/core-plugin-api@1.8.2
|
|
20
|
+
- @backstage/config@1.1.1
|
|
21
|
+
- @backstage/core-app-api@1.11.3
|
|
22
|
+
- @backstage/errors@1.2.3
|
|
23
|
+
- @backstage/theme@0.5.0
|
|
24
|
+
- @backstage/types@1.1.1
|
|
25
|
+
- @backstage/version-bridge@1.0.7
|
|
26
|
+
|
|
3
27
|
## 0.4.1-next.2
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.esm.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React, { useMemo, useState, useEffect, createContext, useContext } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useEffect, createContext, Fragment, useContext } from 'react';
|
|
2
2
|
import { ConfigReader } from '@backstage/config';
|
|
3
|
-
import { createExtension, createExtensionInput, createApiExtension, createThemeExtension, createComponentExtension, createTranslationExtension, coreExtensionData, useComponentRef, coreComponentRefs, createNavItemExtension, createNavLogoExtension, useRouteRef, AnalyticsContext, useAnalytics, createSignInPageExtension, appTreeApiRef, componentsApiRef } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { createExtension, createExtensionInput, createApiExtension, createThemeExtension, createComponentExtension, createTranslationExtension, coreExtensionData, useComponentRef, coreComponentRefs, createNavItemExtension, createNavLogoExtension, useRouteRef, createAppRootElementExtension, createSchemaFromZod, AnalyticsContext, useAnalytics, createRouterExtension, createSignInPageExtension, createAppRootWrapperExtension, appTreeApiRef, componentsApiRef } from '@backstage/frontend-plugin-api';
|
|
4
4
|
import { useRoutes, BrowserRouter, useInRouterContext, MemoryRouter, matchRoutes, generatePath, useLocation, Route } from 'react-router-dom';
|
|
5
|
-
import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel } from '@backstage/core-components';
|
|
5
|
+
import { SidebarPage, sidebarConfig, Sidebar, SidebarDivider, useSidebarOpenState, Link, SidebarItem, Progress, ErrorPage, ErrorPanel, OAuthRequestDialog, AlertDisplay } from '@backstage/core-components';
|
|
6
6
|
import { makeStyles, Button as Button$1 } from '@material-ui/core';
|
|
7
7
|
import { 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';
|
|
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';
|
|
@@ -40,7 +40,7 @@ import { appLanguageApiRef, translationApiRef } from '@backstage/core-plugin-api
|
|
|
40
40
|
import mapValues from 'lodash/mapValues';
|
|
41
41
|
import { stringifyError } from '@backstage/errors';
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const App = createExtension({
|
|
44
44
|
namespace: "app",
|
|
45
45
|
attachTo: { id: "root", input: "default" },
|
|
46
46
|
// ignored
|
|
@@ -74,7 +74,7 @@ const Core = createExtension({
|
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
const
|
|
77
|
+
const AppRoutes = createExtension({
|
|
78
78
|
namespace: "app",
|
|
79
79
|
name: "routes",
|
|
80
80
|
attachTo: { id: "app/layout", input: "content" },
|
|
@@ -111,10 +111,10 @@ const CoreRoutes = createExtension({
|
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
const
|
|
114
|
+
const AppLayout = createExtension({
|
|
115
115
|
namespace: "app",
|
|
116
116
|
name: "layout",
|
|
117
|
-
attachTo: { id: "app/
|
|
117
|
+
attachTo: { id: "app/root", input: "children" },
|
|
118
118
|
inputs: {
|
|
119
119
|
nav: createExtensionInput(
|
|
120
120
|
{
|
|
@@ -220,7 +220,7 @@ const SidebarNavItem = (props) => {
|
|
|
220
220
|
const to = useRouteRef(routeRef)();
|
|
221
221
|
return /* @__PURE__ */ React.createElement(SidebarItem, { to, icon: Icon, text: title });
|
|
222
222
|
};
|
|
223
|
-
const
|
|
223
|
+
const AppNav = createExtension({
|
|
224
224
|
namespace: "app",
|
|
225
225
|
name: "nav",
|
|
226
226
|
attachTo: { id: "app/layout", input: "nav" },
|
|
@@ -1106,11 +1106,15 @@ function resolveExtensionDefinition(definition, context) {
|
|
|
1106
1106
|
`Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`
|
|
1107
1107
|
);
|
|
1108
1108
|
}
|
|
1109
|
+
const id = kind ? `${kind}:${namePart}` : namePart;
|
|
1109
1110
|
return {
|
|
1110
1111
|
...rest,
|
|
1111
1112
|
$$type: "@backstage/Extension",
|
|
1112
1113
|
version: "v1",
|
|
1113
|
-
id
|
|
1114
|
+
id,
|
|
1115
|
+
toString() {
|
|
1116
|
+
return `Extension{id=${id}}`;
|
|
1117
|
+
}
|
|
1114
1118
|
};
|
|
1115
1119
|
}
|
|
1116
1120
|
|
|
@@ -1367,6 +1371,26 @@ const DarkTheme = createThemeExtension({
|
|
|
1367
1371
|
Provider: ({ children }) => /* @__PURE__ */ React.createElement(UnifiedThemeProvider, { theme: themes.dark, children })
|
|
1368
1372
|
});
|
|
1369
1373
|
|
|
1374
|
+
const oauthRequestDialogAppRootElement = createAppRootElementExtension({
|
|
1375
|
+
namespace: "app",
|
|
1376
|
+
name: "oauth-request-dialog",
|
|
1377
|
+
element: /* @__PURE__ */ React.createElement(OAuthRequestDialog, null)
|
|
1378
|
+
});
|
|
1379
|
+
const alertDisplayAppRootElement = createAppRootElementExtension({
|
|
1380
|
+
namespace: "app",
|
|
1381
|
+
name: "alert-display",
|
|
1382
|
+
configSchema: createSchemaFromZod(
|
|
1383
|
+
(z) => z.object({
|
|
1384
|
+
transientTimeoutMs: z.number().default(5e3),
|
|
1385
|
+
anchorOrigin: z.object({
|
|
1386
|
+
vertical: z.enum(["top", "bottom"]).default("top"),
|
|
1387
|
+
horizontal: z.enum(["left", "center", "right"]).default("center")
|
|
1388
|
+
}).default({})
|
|
1389
|
+
})
|
|
1390
|
+
),
|
|
1391
|
+
element: ({ config }) => /* @__PURE__ */ React.createElement(AlertDisplay, { ...config })
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1370
1394
|
const legacyPluginStore = getOrCreateGlobalSingleton(
|
|
1371
1395
|
"legacy-plugin-compatibility-store",
|
|
1372
1396
|
() => /* @__PURE__ */ new WeakMap()
|
|
@@ -1731,9 +1755,14 @@ function collectRouteIds(features) {
|
|
|
1731
1755
|
if (routesById.has(refId)) {
|
|
1732
1756
|
throw new Error(`Unexpected duplicate route '${refId}'`);
|
|
1733
1757
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1758
|
+
if (isRouteRef(ref)) {
|
|
1759
|
+
const internalRef = toInternalRouteRef(ref);
|
|
1760
|
+
internalRef.setId(refId);
|
|
1761
|
+
routesById.set(refId, ref);
|
|
1762
|
+
} else {
|
|
1763
|
+
const internalRef = toInternalSubRouteRef(ref);
|
|
1764
|
+
routesById.set(refId, internalRef);
|
|
1765
|
+
}
|
|
1737
1766
|
}
|
|
1738
1767
|
for (const [name, ref] of Object.entries(feature.externalRoutes)) {
|
|
1739
1768
|
const refId = `plugin.${feature.id}.externalRoutes.${name}`;
|
|
@@ -2144,16 +2173,22 @@ function resolveInputData(dataMap, attachment, inputName) {
|
|
|
2144
2173
|
return value;
|
|
2145
2174
|
});
|
|
2146
2175
|
}
|
|
2147
|
-
function resolveInputs(inputMap, attachments) {
|
|
2176
|
+
function resolveInputs(id, inputMap, attachments) {
|
|
2148
2177
|
const undeclaredAttachments = Array.from(attachments.entries()).filter(
|
|
2149
2178
|
([inputName]) => inputMap[inputName] === void 0
|
|
2150
2179
|
);
|
|
2151
|
-
if (
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2180
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2181
|
+
const inputNames = Object.keys(inputMap);
|
|
2182
|
+
for (const [name, nodes] of undeclaredAttachments) {
|
|
2183
|
+
const pl = nodes.length > 1;
|
|
2184
|
+
console.warn(
|
|
2185
|
+
[
|
|
2186
|
+
`The extension${pl ? "s" : ""} '${nodes.map((n) => n.spec.id).join("', '")}' ${pl ? "are" : "is"}`,
|
|
2187
|
+
`attached to the input '${name}' of the extension '${id}', but it`,
|
|
2188
|
+
inputNames.length === 0 ? "has no inputs" : `has no such input (candidates are '${inputNames.join("', '")}')`
|
|
2189
|
+
].join(" ")
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2157
2192
|
}
|
|
2158
2193
|
return mapValues(inputMap, (input, inputName) => {
|
|
2159
2194
|
var _a;
|
|
@@ -2206,7 +2241,7 @@ function createAppNodeInstance(options) {
|
|
|
2206
2241
|
const namedOutputs = internalExtension.factory({
|
|
2207
2242
|
node,
|
|
2208
2243
|
config: parsedConfig,
|
|
2209
|
-
inputs: resolveInputs(internalExtension.inputs, attachments)
|
|
2244
|
+
inputs: resolveInputs(id, internalExtension.inputs, attachments)
|
|
2210
2245
|
});
|
|
2211
2246
|
for (const [name, output] of Object.entries(namedOutputs)) {
|
|
2212
2247
|
const ref = internalExtension.output[name];
|
|
@@ -2367,31 +2402,48 @@ const RouteTracker = ({
|
|
|
2367
2402
|
));
|
|
2368
2403
|
};
|
|
2369
2404
|
|
|
2370
|
-
const
|
|
2405
|
+
const AppRoot = createExtension({
|
|
2371
2406
|
namespace: "app",
|
|
2372
|
-
name: "
|
|
2407
|
+
name: "root",
|
|
2373
2408
|
attachTo: { id: "app", input: "root" },
|
|
2374
2409
|
inputs: {
|
|
2410
|
+
router: createExtensionInput(
|
|
2411
|
+
{ component: createRouterExtension.componentDataRef },
|
|
2412
|
+
{ singleton: true, optional: true }
|
|
2413
|
+
),
|
|
2375
2414
|
signInPage: createExtensionInput(
|
|
2376
|
-
{
|
|
2377
|
-
component: createSignInPageExtension.componentDataRef
|
|
2378
|
-
},
|
|
2415
|
+
{ component: createSignInPageExtension.componentDataRef },
|
|
2379
2416
|
{ singleton: true, optional: true }
|
|
2380
2417
|
),
|
|
2381
2418
|
children: createExtensionInput(
|
|
2382
|
-
{
|
|
2383
|
-
element: coreExtensionData.reactElement
|
|
2384
|
-
},
|
|
2419
|
+
{ element: coreExtensionData.reactElement },
|
|
2385
2420
|
{ singleton: true }
|
|
2386
|
-
)
|
|
2421
|
+
),
|
|
2422
|
+
elements: createExtensionInput({
|
|
2423
|
+
element: coreExtensionData.reactElement
|
|
2424
|
+
}),
|
|
2425
|
+
wrappers: createExtensionInput({
|
|
2426
|
+
component: createAppRootWrapperExtension.componentDataRef
|
|
2427
|
+
})
|
|
2387
2428
|
},
|
|
2388
2429
|
output: {
|
|
2389
2430
|
element: coreExtensionData.reactElement
|
|
2390
2431
|
},
|
|
2391
2432
|
factory({ inputs }) {
|
|
2392
|
-
var _a;
|
|
2433
|
+
var _a, _b;
|
|
2434
|
+
let content = /* @__PURE__ */ React.createElement(React.Fragment, null, inputs.elements.map((el) => /* @__PURE__ */ React.createElement(Fragment, { key: el.node.spec.id }, el.output.element)), inputs.children.output.element);
|
|
2435
|
+
for (const wrapper of inputs.wrappers) {
|
|
2436
|
+
content = /* @__PURE__ */ React.createElement(wrapper.output.component, null, content);
|
|
2437
|
+
}
|
|
2393
2438
|
return {
|
|
2394
|
-
element: /* @__PURE__ */ React.createElement(
|
|
2439
|
+
element: /* @__PURE__ */ React.createElement(
|
|
2440
|
+
AppRouter,
|
|
2441
|
+
{
|
|
2442
|
+
SignInPageComponent: (_a = inputs.signInPage) == null ? void 0 : _a.output.component,
|
|
2443
|
+
RouterComponent: (_b = inputs.router) == null ? void 0 : _b.output.component
|
|
2444
|
+
},
|
|
2445
|
+
content
|
|
2446
|
+
)
|
|
2395
2447
|
};
|
|
2396
2448
|
}
|
|
2397
2449
|
});
|
|
@@ -2421,8 +2473,17 @@ function SignInPageWrapper({
|
|
|
2421
2473
|
});
|
|
2422
2474
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
|
|
2423
2475
|
}
|
|
2476
|
+
function DefaultRouter(props) {
|
|
2477
|
+
const configApi = useApi(configApiRef);
|
|
2478
|
+
const basePath = getBasePath(configApi);
|
|
2479
|
+
return /* @__PURE__ */ React.createElement(BrowserRouter, { basename: basePath }, props.children);
|
|
2480
|
+
}
|
|
2424
2481
|
function AppRouter(props) {
|
|
2425
|
-
const {
|
|
2482
|
+
const {
|
|
2483
|
+
children,
|
|
2484
|
+
SignInPageComponent,
|
|
2485
|
+
RouterComponent = DefaultRouter
|
|
2486
|
+
} = props;
|
|
2426
2487
|
const configApi = useApi(configApiRef);
|
|
2427
2488
|
const basePath = getBasePath(configApi);
|
|
2428
2489
|
const internalAppContext = useContext(InternalAppContext);
|
|
@@ -2454,9 +2515,9 @@ function AppRouter(props) {
|
|
|
2454
2515
|
},
|
|
2455
2516
|
{ signOutTargetUrl: basePath || "/" }
|
|
2456
2517
|
);
|
|
2457
|
-
return /* @__PURE__ */ React.createElement(
|
|
2518
|
+
return /* @__PURE__ */ React.createElement(RouterComponent, null, /* @__PURE__ */ React.createElement(RouteTracker, { routeObjects }), children);
|
|
2458
2519
|
}
|
|
2459
|
-
return /* @__PURE__ */ React.createElement(
|
|
2520
|
+
return /* @__PURE__ */ React.createElement(RouterComponent, null, /* @__PURE__ */ React.createElement(RouteTracker, { routeObjects }), /* @__PURE__ */ React.createElement(
|
|
2460
2521
|
SignInPageWrapper,
|
|
2461
2522
|
{
|
|
2462
2523
|
component: SignInPageComponent,
|
|
@@ -2502,16 +2563,18 @@ _components = new WeakMap();
|
|
|
2502
2563
|
|
|
2503
2564
|
const DefaultApis = apis.map((factory) => createApiExtension({ factory }));
|
|
2504
2565
|
const builtinExtensions = [
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2566
|
+
App,
|
|
2567
|
+
AppRoot,
|
|
2568
|
+
AppRoutes,
|
|
2569
|
+
AppNav,
|
|
2570
|
+
AppLayout,
|
|
2510
2571
|
DefaultProgressComponent,
|
|
2511
2572
|
DefaultErrorBoundaryComponent,
|
|
2512
2573
|
DefaultNotFoundErrorPageComponent,
|
|
2513
2574
|
LightTheme,
|
|
2514
2575
|
DarkTheme,
|
|
2576
|
+
oauthRequestDialogAppRootElement,
|
|
2577
|
+
alertDisplayAppRootElement,
|
|
2515
2578
|
...DefaultApis
|
|
2516
2579
|
].map((def) => resolveExtensionDefinition(def));
|
|
2517
2580
|
function createExtensionTree(options) {
|
|
@@ -2666,7 +2729,7 @@ function createSpecializedApp(options) {
|
|
|
2666
2729
|
collectRouteIds(features)
|
|
2667
2730
|
);
|
|
2668
2731
|
const rootEl = tree.root.instance.getData(coreExtensionData.reactElement);
|
|
2669
|
-
const
|
|
2732
|
+
const AppComponent = () => /* @__PURE__ */ React.createElement(ApiProvider, { apis: apiHolder }, /* @__PURE__ */ React.createElement(AppThemeProvider, null, /* @__PURE__ */ React.createElement(RoutingProvider, { ...routeInfo, routeBindings }, /* @__PURE__ */ React.createElement(
|
|
2670
2733
|
InternalAppContext.Provider,
|
|
2671
2734
|
{
|
|
2672
2735
|
value: { appIdentityProxy, routeObjects: routeInfo.routeObjects }
|
|
@@ -2675,7 +2738,7 @@ function createSpecializedApp(options) {
|
|
|
2675
2738
|
))));
|
|
2676
2739
|
return {
|
|
2677
2740
|
createRoot() {
|
|
2678
|
-
return /* @__PURE__ */ React.createElement(
|
|
2741
|
+
return /* @__PURE__ */ React.createElement(AppComponent, null);
|
|
2679
2742
|
}
|
|
2680
2743
|
};
|
|
2681
2744
|
}
|