@backstage/frontend-app-api 0.4.0-next.3 → 0.4.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 +41 -0
- package/dist/index.d.ts +30 -11
- package/dist/index.esm.js +123 -108
- package/dist/index.esm.js.map +1 -1
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @backstage/frontend-app-api
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e539735: Updated core extension structure to make space for the sign-in page by adding `core.router`.
|
|
8
|
+
- 44735df: Removed `featureLoader` from `createApp`, `features` instead accepts both `FrontendFeature` and `CreateAppFeatureLoader`
|
|
9
|
+
- af7bc3e: Switched all core extensions to instead use the namespace `'app'`.
|
|
10
|
+
- 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`.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 5eb6b8a: Added the nav logo extension for customization of sidebar logo
|
|
15
|
+
- aeb8008: Add support for translation extensions.
|
|
16
|
+
- 1f12fb7: Create a core components extension that allows adopters to override core app components such as `Progress`, `BootErrorPage`, `NotFoundErrorPage` and `ErrorBoundaryFallback`.
|
|
17
|
+
- a379243: Leverage the new `FrontendFeature` type to simplify interfaces
|
|
18
|
+
- 60d6eb5: Removed `@backstage/plugin-graphiql` dependency.
|
|
19
|
+
- b7adf24: Use the new plugin type for error boundary components.
|
|
20
|
+
- 5970928: Collect and register feature flags from plugins and extension overrides.
|
|
21
|
+
- 9ad4039: Bringing over apis from core-plugin-api
|
|
22
|
+
- 8f5d6c1: Updates to match the new extension input wrapping.
|
|
23
|
+
- c35036b: A `configLoader` passed to `createApp` now returns an object, to make room for future expansion
|
|
24
|
+
- f27ee7d: Migrate analytics route tracker component.
|
|
25
|
+
- b8cb780: Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded.
|
|
26
|
+
- c36e0b9: Renamed `AppRouteBinder` to `CreateAppRouteBinder`
|
|
27
|
+
- cb4197a: Forward ` node`` instead of `extensionId` to resolved extension inputs.
|
|
28
|
+
- 8837a96: Updates to match the introduction of `ExtensionDefinition` and new extension ID naming patterns.
|
|
29
|
+
- a5a0473: Updates to provide `node` to extension factories instead of `id` and `source`.
|
|
30
|
+
- 5cdf2b3: Updated usage of `Extension` and `ExtensionDefinition` as they are now opaque.
|
|
31
|
+
- f9ef632: Updates to match the new `coreExtensionData` structure.
|
|
32
|
+
- f1183b7: Renamed the `component` option of `createComponentExtension` to `loader`.
|
|
33
|
+
- Updated dependencies
|
|
34
|
+
- @backstage/core-plugin-api@1.8.1
|
|
35
|
+
- @backstage/frontend-plugin-api@0.4.0
|
|
36
|
+
- @backstage/core-components@0.13.9
|
|
37
|
+
- @backstage/theme@0.5.0
|
|
38
|
+
- @backstage/core-app-api@1.11.2
|
|
39
|
+
- @backstage/config@1.1.1
|
|
40
|
+
- @backstage/errors@1.2.3
|
|
41
|
+
- @backstage/types@1.1.1
|
|
42
|
+
- @backstage/version-bridge@1.0.7
|
|
43
|
+
|
|
3
44
|
## 0.4.0-next.3
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExternalRouteRef, RouteRef, SubRouteRef, ExtensionDataRef,
|
|
1
|
+
import { ExternalRouteRef, RouteRef, SubRouteRef, ExtensionDataRef, FrontendFeature } from '@backstage/frontend-plugin-api';
|
|
2
2
|
import { JSX } from 'react';
|
|
3
3
|
import { Config } from '@backstage/config';
|
|
4
4
|
import { ConfigApi } from '@backstage/core-plugin-api';
|
|
@@ -37,7 +37,7 @@ type TargetRouteMap<ExternalRoutes extends {
|
|
|
37
37
|
*
|
|
38
38
|
* @public
|
|
39
39
|
*/
|
|
40
|
-
type
|
|
40
|
+
type CreateAppRouteBinder = <TExternalRoutes extends {
|
|
41
41
|
[name: string]: ExternalRouteRef;
|
|
42
42
|
}>(externalRoutes: TExternalRoutes, targetRoutes: PartialKeys<TargetRouteMap<TExternalRoutes>, KeysWithType<TExternalRoutes, ExternalRouteRef<any, true>>>) => void;
|
|
43
43
|
|
|
@@ -57,32 +57,51 @@ interface ExtensionTree {
|
|
|
57
57
|
declare function createExtensionTree(options: {
|
|
58
58
|
config: Config;
|
|
59
59
|
}): ExtensionTree;
|
|
60
|
+
/**
|
|
61
|
+
* A source of dynamically loaded frontend features.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
interface CreateAppFeatureLoader {
|
|
66
|
+
/**
|
|
67
|
+
* Returns name of this loader. suitable for showing to users.
|
|
68
|
+
*/
|
|
69
|
+
getLoaderName(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Loads a number of features dynamically.
|
|
72
|
+
*/
|
|
73
|
+
load(options: {
|
|
74
|
+
config: ConfigApi;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
features: FrontendFeature[];
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
60
79
|
/** @public */
|
|
61
80
|
declare function createApp(options?: {
|
|
62
|
-
features?: (
|
|
63
|
-
configLoader?: () => Promise<
|
|
81
|
+
features?: (FrontendFeature | CreateAppFeatureLoader)[];
|
|
82
|
+
configLoader?: () => Promise<{
|
|
83
|
+
config: ConfigApi;
|
|
84
|
+
}>;
|
|
64
85
|
bindRoutes?(context: {
|
|
65
|
-
bind:
|
|
86
|
+
bind: CreateAppRouteBinder;
|
|
66
87
|
}): void;
|
|
67
|
-
featureLoader?: (ctx: {
|
|
68
|
-
config: ConfigApi;
|
|
69
|
-
}) => Promise<(BackstagePlugin | ExtensionOverrides)[]>;
|
|
70
88
|
}): {
|
|
71
89
|
createRoot(): JSX.Element;
|
|
72
90
|
};
|
|
73
91
|
/**
|
|
74
92
|
* Synchronous version of {@link createApp}, expecting all features and
|
|
75
93
|
* config to have been loaded already.
|
|
94
|
+
*
|
|
76
95
|
* @public
|
|
77
96
|
*/
|
|
78
97
|
declare function createSpecializedApp(options?: {
|
|
79
|
-
features?:
|
|
98
|
+
features?: FrontendFeature[];
|
|
80
99
|
config?: ConfigApi;
|
|
81
100
|
bindRoutes?(context: {
|
|
82
|
-
bind:
|
|
101
|
+
bind: CreateAppRouteBinder;
|
|
83
102
|
}): void;
|
|
84
103
|
}): {
|
|
85
104
|
createRoot(): JSX.Element;
|
|
86
105
|
};
|
|
87
106
|
|
|
88
|
-
export {
|
|
107
|
+
export { CreateAppFeatureLoader, CreateAppRouteBinder, ExtensionTree, ExtensionTreeNode, createApp, createExtensionTree, createSpecializedApp };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useMemo, useState, useEffect, createContext, useContext } from 'react';
|
|
2
2
|
import { ConfigReader } from '@backstage/config';
|
|
3
|
-
import { createExtension, createExtensionInput,
|
|
3
|
+
import { createExtension, createExtensionInput, createApiExtension, createThemeExtension, createComponentExtension, createTranslationExtension, coreExtensionData, useComponentRef, coreComponentRefs, createNavItemExtension, createNavLogoExtension, useRouteRef, AnalyticsContext, useAnalytics, createSignInPageExtension, 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
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,
|
|
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';
|
|
9
9
|
import useObservable from 'react-use/lib/useObservable';
|
|
10
10
|
import ObservableImpl from 'zen-observable';
|
|
@@ -38,20 +38,21 @@ import LightIcon from '@material-ui/icons/WbSunny';
|
|
|
38
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
|
+
import { stringifyError } from '@backstage/errors';
|
|
41
42
|
|
|
42
43
|
const Core = createExtension({
|
|
43
|
-
namespace: "
|
|
44
|
+
namespace: "app",
|
|
44
45
|
attachTo: { id: "root", input: "default" },
|
|
45
46
|
// ignored
|
|
46
47
|
inputs: {
|
|
47
48
|
apis: createExtensionInput({
|
|
48
|
-
api:
|
|
49
|
+
api: createApiExtension.factoryDataRef
|
|
49
50
|
}),
|
|
50
51
|
themes: createExtensionInput({
|
|
51
|
-
theme:
|
|
52
|
+
theme: createThemeExtension.themeDataRef
|
|
52
53
|
}),
|
|
53
54
|
components: createExtensionInput({
|
|
54
|
-
component:
|
|
55
|
+
component: createComponentExtension.componentDataRef
|
|
55
56
|
}),
|
|
56
57
|
translations: createExtensionInput({
|
|
57
58
|
translation: createTranslationExtension.translationDataRef
|
|
@@ -74,9 +75,9 @@ const Core = createExtension({
|
|
|
74
75
|
});
|
|
75
76
|
|
|
76
77
|
const CoreRoutes = createExtension({
|
|
77
|
-
namespace: "
|
|
78
|
+
namespace: "app",
|
|
78
79
|
name: "routes",
|
|
79
|
-
attachTo: { id: "
|
|
80
|
+
attachTo: { id: "app/layout", input: "content" },
|
|
80
81
|
inputs: {
|
|
81
82
|
routes: createExtensionInput({
|
|
82
83
|
path: coreExtensionData.routePath,
|
|
@@ -111,9 +112,9 @@ const CoreRoutes = createExtension({
|
|
|
111
112
|
});
|
|
112
113
|
|
|
113
114
|
const CoreLayout = createExtension({
|
|
114
|
-
namespace: "
|
|
115
|
+
namespace: "app",
|
|
115
116
|
name: "layout",
|
|
116
|
-
attachTo: { id: "
|
|
117
|
+
attachTo: { id: "app/router", input: "children" },
|
|
117
118
|
inputs: {
|
|
118
119
|
nav: createExtensionInput(
|
|
119
120
|
{
|
|
@@ -220,16 +221,16 @@ const SidebarNavItem = (props) => {
|
|
|
220
221
|
return /* @__PURE__ */ React.createElement(SidebarItem, { to, icon: Icon, text: title });
|
|
221
222
|
};
|
|
222
223
|
const CoreNav = createExtension({
|
|
223
|
-
namespace: "
|
|
224
|
+
namespace: "app",
|
|
224
225
|
name: "nav",
|
|
225
|
-
attachTo: { id: "
|
|
226
|
+
attachTo: { id: "app/layout", input: "nav" },
|
|
226
227
|
inputs: {
|
|
227
228
|
items: createExtensionInput({
|
|
228
|
-
target:
|
|
229
|
+
target: createNavItemExtension.targetDataRef
|
|
229
230
|
}),
|
|
230
231
|
logos: createExtensionInput(
|
|
231
232
|
{
|
|
232
|
-
elements:
|
|
233
|
+
elements: createNavLogoExtension.logoElementsDataRef
|
|
233
234
|
},
|
|
234
235
|
{
|
|
235
236
|
singleton: true,
|
|
@@ -1065,10 +1066,40 @@ registerDefaults_fn = function(internalRef) {
|
|
|
1065
1066
|
};
|
|
1066
1067
|
let I18nextTranslationApi = _I18nextTranslationApi;
|
|
1067
1068
|
|
|
1069
|
+
function toInternalExtensionDefinition(overrides) {
|
|
1070
|
+
const internal = overrides;
|
|
1071
|
+
if (internal.$$type !== "@backstage/ExtensionDefinition") {
|
|
1072
|
+
throw new Error(
|
|
1073
|
+
`Invalid extension definition instance, bad type '${internal.$$type}'`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
if (internal.version !== "v1") {
|
|
1077
|
+
throw new Error(
|
|
1078
|
+
`Invalid extension definition instance, bad version '${internal.version}'`
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
return internal;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function toInternalExtension(overrides) {
|
|
1085
|
+
const internal = overrides;
|
|
1086
|
+
if (internal.$$type !== "@backstage/Extension") {
|
|
1087
|
+
throw new Error(
|
|
1088
|
+
`Invalid extension instance, bad type '${internal.$$type}'`
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
if (internal.version !== "v1") {
|
|
1092
|
+
throw new Error(
|
|
1093
|
+
`Invalid extension instance, bad version '${internal.version}'`
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
return internal;
|
|
1097
|
+
}
|
|
1068
1098
|
function resolveExtensionDefinition(definition, context) {
|
|
1069
1099
|
var _a;
|
|
1070
|
-
const
|
|
1071
|
-
const
|
|
1100
|
+
const internalDefinition = toInternalExtensionDefinition(definition);
|
|
1101
|
+
const { name, kind, namespace: _, ...rest } = internalDefinition;
|
|
1102
|
+
const namespace = (_a = internalDefinition.namespace) != null ? _a : context == null ? void 0 : context.namespace;
|
|
1072
1103
|
const namePart = name && namespace ? `${namespace}/${name}` : namespace || name;
|
|
1073
1104
|
if (!namePart) {
|
|
1074
1105
|
throw new Error(
|
|
@@ -1077,8 +1108,9 @@ function resolveExtensionDefinition(definition, context) {
|
|
|
1077
1108
|
}
|
|
1078
1109
|
return {
|
|
1079
1110
|
...rest,
|
|
1080
|
-
|
|
1081
|
-
|
|
1111
|
+
$$type: "@backstage/Extension",
|
|
1112
|
+
version: "v1",
|
|
1113
|
+
id: kind ? `${kind}:${namePart}` : namePart
|
|
1082
1114
|
};
|
|
1083
1115
|
}
|
|
1084
1116
|
|
|
@@ -1988,40 +2020,47 @@ function resolveAppNodeSpecs(options) {
|
|
|
1988
2020
|
);
|
|
1989
2021
|
}
|
|
1990
2022
|
const configuredExtensions = [
|
|
1991
|
-
...pluginExtensions.map(({ source, ...extension }) =>
|
|
1992
|
-
extension
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2023
|
+
...pluginExtensions.map(({ source, ...extension }) => {
|
|
2024
|
+
const internalExtension = toInternalExtension(extension);
|
|
2025
|
+
return {
|
|
2026
|
+
extension: internalExtension,
|
|
2027
|
+
params: {
|
|
2028
|
+
source,
|
|
2029
|
+
attachTo: internalExtension.attachTo,
|
|
2030
|
+
disabled: internalExtension.disabled,
|
|
2031
|
+
config: void 0
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
}),
|
|
2035
|
+
...builtinExtensions.map((extension) => {
|
|
2036
|
+
const internalExtension = toInternalExtension(extension);
|
|
2037
|
+
return {
|
|
2038
|
+
extension: internalExtension,
|
|
2039
|
+
params: {
|
|
2040
|
+
source: void 0,
|
|
2041
|
+
attachTo: internalExtension.attachTo,
|
|
2042
|
+
disabled: internalExtension.disabled,
|
|
2043
|
+
config: void 0
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
})
|
|
2009
2047
|
];
|
|
2010
2048
|
for (const extension of overrideExtensions) {
|
|
2049
|
+
const internalExtension = toInternalExtension(extension);
|
|
2011
2050
|
const index = configuredExtensions.findIndex(
|
|
2012
2051
|
(e) => e.extension.id === extension.id
|
|
2013
2052
|
);
|
|
2014
2053
|
if (index !== -1) {
|
|
2015
|
-
configuredExtensions[index].extension =
|
|
2016
|
-
configuredExtensions[index].params.attachTo =
|
|
2017
|
-
configuredExtensions[index].params.disabled =
|
|
2054
|
+
configuredExtensions[index].extension = internalExtension;
|
|
2055
|
+
configuredExtensions[index].params.attachTo = internalExtension.attachTo;
|
|
2056
|
+
configuredExtensions[index].params.disabled = internalExtension.disabled;
|
|
2018
2057
|
} else {
|
|
2019
2058
|
configuredExtensions.push({
|
|
2020
|
-
extension,
|
|
2059
|
+
extension: internalExtension,
|
|
2021
2060
|
params: {
|
|
2022
2061
|
source: void 0,
|
|
2023
|
-
attachTo:
|
|
2024
|
-
disabled:
|
|
2062
|
+
attachTo: internalExtension.attachTo,
|
|
2063
|
+
disabled: internalExtension.disabled,
|
|
2025
2064
|
config: void 0
|
|
2026
2065
|
}
|
|
2027
2066
|
});
|
|
@@ -2163,13 +2202,14 @@ function createAppNodeInstance(options) {
|
|
|
2163
2202
|
);
|
|
2164
2203
|
}
|
|
2165
2204
|
try {
|
|
2166
|
-
const
|
|
2205
|
+
const internalExtension = toInternalExtension(extension);
|
|
2206
|
+
const namedOutputs = internalExtension.factory({
|
|
2167
2207
|
node,
|
|
2168
2208
|
config: parsedConfig,
|
|
2169
|
-
inputs: resolveInputs(
|
|
2209
|
+
inputs: resolveInputs(internalExtension.inputs, attachments)
|
|
2170
2210
|
});
|
|
2171
2211
|
for (const [name, output] of Object.entries(namedOutputs)) {
|
|
2172
|
-
const ref =
|
|
2212
|
+
const ref = internalExtension.output[name];
|
|
2173
2213
|
if (!ref) {
|
|
2174
2214
|
throw new Error(`unknown output provided via '${name}'`);
|
|
2175
2215
|
}
|
|
@@ -2227,12 +2267,12 @@ function instantiateAppNodeTree(rootNode) {
|
|
|
2227
2267
|
|
|
2228
2268
|
function createAppTree(options) {
|
|
2229
2269
|
const tree = resolveAppTree(
|
|
2230
|
-
"
|
|
2270
|
+
"app",
|
|
2231
2271
|
resolveAppNodeSpecs({
|
|
2232
2272
|
features: options.features,
|
|
2233
2273
|
builtinExtensions: options.builtinExtensions,
|
|
2234
2274
|
parameters: readAppExtensionsConfig(options.config),
|
|
2235
|
-
forbidden: /* @__PURE__ */ new Set(["
|
|
2275
|
+
forbidden: /* @__PURE__ */ new Set(["app"])
|
|
2236
2276
|
})
|
|
2237
2277
|
);
|
|
2238
2278
|
instantiateAppNodeTree(tree.root);
|
|
@@ -2241,15 +2281,15 @@ function createAppTree(options) {
|
|
|
2241
2281
|
|
|
2242
2282
|
const DefaultProgressComponent = createComponentExtension({
|
|
2243
2283
|
ref: coreComponentRefs.progress,
|
|
2244
|
-
|
|
2284
|
+
loader: { sync: () => components.Progress }
|
|
2245
2285
|
});
|
|
2246
2286
|
const DefaultNotFoundErrorPageComponent = createComponentExtension({
|
|
2247
2287
|
ref: coreComponentRefs.notFoundErrorPage,
|
|
2248
|
-
|
|
2288
|
+
loader: { sync: () => components.NotFoundErrorPage }
|
|
2249
2289
|
});
|
|
2250
2290
|
const DefaultErrorBoundaryComponent = createComponentExtension({
|
|
2251
2291
|
ref: coreComponentRefs.errorBoundaryFallback,
|
|
2252
|
-
|
|
2292
|
+
loader: {
|
|
2253
2293
|
sync: () => (props) => {
|
|
2254
2294
|
const { plugin, error, resetError } = props;
|
|
2255
2295
|
const title = `Error in ${plugin == null ? void 0 : plugin.id}`;
|
|
@@ -2260,38 +2300,6 @@ const DefaultErrorBoundaryComponent = createComponentExtension({
|
|
|
2260
2300
|
|
|
2261
2301
|
const InternalAppContext = createContext(void 0);
|
|
2262
2302
|
|
|
2263
|
-
getOrCreateGlobalSingleton(
|
|
2264
|
-
"core-plugin-api:analytics-tracker-events",
|
|
2265
|
-
() => ({
|
|
2266
|
-
mostRecentGatheredNavigation: void 0,
|
|
2267
|
-
mostRecentRoutableExtensionRender: void 0,
|
|
2268
|
-
beforeUnloadRegistered: false
|
|
2269
|
-
})
|
|
2270
|
-
);
|
|
2271
|
-
|
|
2272
|
-
createApiRef({ id: "core.app-tree" });
|
|
2273
|
-
|
|
2274
|
-
createApiRef({
|
|
2275
|
-
id: "core.components"
|
|
2276
|
-
});
|
|
2277
|
-
|
|
2278
|
-
createApiRef({
|
|
2279
|
-
id: "core.analytics"
|
|
2280
|
-
});
|
|
2281
|
-
|
|
2282
|
-
function createExtensionDataRef(id) {
|
|
2283
|
-
return {
|
|
2284
|
-
id,
|
|
2285
|
-
$$type: "@backstage/ExtensionDataRef",
|
|
2286
|
-
config: {},
|
|
2287
|
-
optional() {
|
|
2288
|
-
return { ...this, config: { ...this.config, optional: true } };
|
|
2289
|
-
}
|
|
2290
|
-
};
|
|
2291
|
-
}
|
|
2292
|
-
|
|
2293
|
-
const signInPageComponentDataRef = createExtensionDataRef("core.signInPage");
|
|
2294
|
-
|
|
2295
2303
|
const getExtensionContext = (pathname, routes) => {
|
|
2296
2304
|
var _a, _b;
|
|
2297
2305
|
try {
|
|
@@ -2360,13 +2368,13 @@ const RouteTracker = ({
|
|
|
2360
2368
|
};
|
|
2361
2369
|
|
|
2362
2370
|
const CoreRouter = createExtension({
|
|
2363
|
-
namespace: "
|
|
2371
|
+
namespace: "app",
|
|
2364
2372
|
name: "router",
|
|
2365
|
-
attachTo: { id: "
|
|
2373
|
+
attachTo: { id: "app", input: "root" },
|
|
2366
2374
|
inputs: {
|
|
2367
2375
|
signInPage: createExtensionInput(
|
|
2368
2376
|
{
|
|
2369
|
-
component:
|
|
2377
|
+
component: createSignInPageExtension.componentDataRef
|
|
2370
2378
|
},
|
|
2371
2379
|
{ singleton: true, optional: true }
|
|
2372
2380
|
),
|
|
@@ -2492,6 +2500,7 @@ class DefaultComponentsApi {
|
|
|
2492
2500
|
}
|
|
2493
2501
|
_components = new WeakMap();
|
|
2494
2502
|
|
|
2503
|
+
const DefaultApis = apis.map((factory) => createApiExtension({ factory }));
|
|
2495
2504
|
const builtinExtensions = [
|
|
2496
2505
|
Core,
|
|
2497
2506
|
CoreRouter,
|
|
@@ -2502,7 +2511,8 @@ const builtinExtensions = [
|
|
|
2502
2511
|
DefaultErrorBoundaryComponent,
|
|
2503
2512
|
DefaultNotFoundErrorPageComponent,
|
|
2504
2513
|
LightTheme,
|
|
2505
|
-
DarkTheme
|
|
2514
|
+
DarkTheme,
|
|
2515
|
+
...DefaultApis
|
|
2506
2516
|
].map((def) => resolveExtensionDefinition(def));
|
|
2507
2517
|
function createExtensionTree(options) {
|
|
2508
2518
|
const features = getAvailableFeatures(options.config);
|
|
@@ -2529,7 +2539,7 @@ function createExtensionTree(options) {
|
|
|
2529
2539
|
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 : [];
|
|
2530
2540
|
},
|
|
2531
2541
|
getRootRoutes() {
|
|
2532
|
-
return this.getExtensionAttachments("
|
|
2542
|
+
return this.getExtensionAttachments("app/routes", "routes").map((node) => {
|
|
2533
2543
|
const path = node.getData(coreExtensionData.routePath);
|
|
2534
2544
|
const element = node.getData(coreExtensionData.reactElement);
|
|
2535
2545
|
const routeRef = node.getData(coreExtensionData.routeRef);
|
|
@@ -2548,8 +2558,8 @@ function createExtensionTree(options) {
|
|
|
2548
2558
|
const location = useRouteRef(props.routeRef);
|
|
2549
2559
|
return /* @__PURE__ */ React.createElement(SidebarItem, { icon: props.icon, to: location(), text: props.title });
|
|
2550
2560
|
};
|
|
2551
|
-
return this.getExtensionAttachments("
|
|
2552
|
-
const target = node.getData(
|
|
2561
|
+
return this.getExtensionAttachments("app/nav", "items").map((node, index) => {
|
|
2562
|
+
const target = node.getData(createNavItemExtension.targetDataRef);
|
|
2553
2563
|
if (!target) {
|
|
2554
2564
|
return null;
|
|
2555
2565
|
}
|
|
@@ -2582,19 +2592,31 @@ function deduplicateFeatures(allFeatures) {
|
|
|
2582
2592
|
}
|
|
2583
2593
|
function createApp(options) {
|
|
2584
2594
|
async function appLoader() {
|
|
2585
|
-
var _a, _b, _c
|
|
2586
|
-
const config = (_b = await ((_a = options == null ? void 0 : options.configLoader) == null ? void 0 : _a.call(options))) != null ? _b : ConfigReader.fromConfigs(
|
|
2595
|
+
var _a, _b, _c;
|
|
2596
|
+
const config = (_b = await ((_a = options == null ? void 0 : options.configLoader) == null ? void 0 : _a.call(options).then((c) => c.config))) != null ? _b : ConfigReader.fromConfigs(
|
|
2587
2597
|
overrideBaseUrlConfigs(defaultConfigLoaderSync())
|
|
2588
2598
|
);
|
|
2589
2599
|
const discoveredFeatures = getAvailableFeatures(config);
|
|
2590
|
-
const
|
|
2600
|
+
const providedFeatures = [];
|
|
2601
|
+
for (const entry of (_c = options == null ? void 0 : options.features) != null ? _c : []) {
|
|
2602
|
+
if ("load" in entry) {
|
|
2603
|
+
try {
|
|
2604
|
+
const result = await entry.load({ config });
|
|
2605
|
+
providedFeatures.push(...result.features);
|
|
2606
|
+
} catch (e) {
|
|
2607
|
+
throw new Error(
|
|
2608
|
+
`Failed to read frontend features from loader '${entry.getLoaderName()}', ${stringifyError(
|
|
2609
|
+
e
|
|
2610
|
+
)}`
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
} else {
|
|
2614
|
+
providedFeatures.push(entry);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2591
2617
|
const app = createSpecializedApp({
|
|
2592
2618
|
config,
|
|
2593
|
-
features: [
|
|
2594
|
-
...discoveredFeatures,
|
|
2595
|
-
...loadedFeatures,
|
|
2596
|
-
...(_e = options == null ? void 0 : options.features) != null ? _e : []
|
|
2597
|
-
],
|
|
2619
|
+
features: [...discoveredFeatures, ...providedFeatures],
|
|
2598
2620
|
bindRoutes: options == null ? void 0 : options.bindRoutes
|
|
2599
2621
|
}).createRoot();
|
|
2600
2622
|
return { default: () => app };
|
|
@@ -2662,11 +2684,11 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
|
|
|
2662
2684
|
const factoryRegistry = new ApiFactoryRegistry();
|
|
2663
2685
|
const pluginApis = (_b = (_a = tree.root.edges.attachments.get("apis")) == null ? void 0 : _a.map((e) => {
|
|
2664
2686
|
var _a2;
|
|
2665
|
-
return (_a2 = e.instance) == null ? void 0 : _a2.getData(
|
|
2687
|
+
return (_a2 = e.instance) == null ? void 0 : _a2.getData(createApiExtension.factoryDataRef);
|
|
2666
2688
|
}).filter((x) => !!x)) != null ? _b : [];
|
|
2667
2689
|
const themeExtensions = (_d = (_c = tree.root.edges.attachments.get("themes")) == null ? void 0 : _c.map((e) => {
|
|
2668
2690
|
var _a2;
|
|
2669
|
-
return (_a2 = e.instance) == null ? void 0 : _a2.getData(
|
|
2691
|
+
return (_a2 = e.instance) == null ? void 0 : _a2.getData(createThemeExtension.themeDataRef);
|
|
2670
2692
|
}).filter((x) => !!x)) != null ? _d : [];
|
|
2671
2693
|
const translationResources = (_f = (_e = tree.root.edges.attachments.get("translations")) == null ? void 0 : _e.map(
|
|
2672
2694
|
(e) => {
|
|
@@ -2676,7 +2698,7 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
|
|
|
2676
2698
|
).filter(
|
|
2677
2699
|
(x) => !!x
|
|
2678
2700
|
)) != null ? _f : [];
|
|
2679
|
-
for (const factory of
|
|
2701
|
+
for (const factory of pluginApis) {
|
|
2680
2702
|
factoryRegistry.register("default", factory);
|
|
2681
2703
|
}
|
|
2682
2704
|
factoryRegistry.register("default", {
|
|
@@ -2698,7 +2720,7 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
|
|
|
2698
2720
|
});
|
|
2699
2721
|
const componentsExtensions = (_h = (_g = tree.root.edges.attachments.get("components")) == null ? void 0 : _g.map((e) => {
|
|
2700
2722
|
var _a2;
|
|
2701
|
-
return (_a2 = e.instance) == null ? void 0 : _a2.getData(
|
|
2723
|
+
return (_a2 = e.instance) == null ? void 0 : _a2.getData(createComponentExtension.componentDataRef);
|
|
2702
2724
|
}).filter((x) => !!x)) != null ? _h : [];
|
|
2703
2725
|
const componentsMap = componentsExtensions.reduce(
|
|
2704
2726
|
(components, component) => component ? components.set(component.ref, component == null ? void 0 : component.impl) : components,
|
|
@@ -2738,13 +2760,6 @@ function createApiHolder(tree, configApi, appIdentityProxy) {
|
|
|
2738
2760
|
resources: translationResources
|
|
2739
2761
|
})
|
|
2740
2762
|
});
|
|
2741
|
-
for (const factory of apis) {
|
|
2742
|
-
if (!factoryRegistry.register("app", factory)) {
|
|
2743
|
-
throw new Error(
|
|
2744
|
-
`Duplicate or forbidden API factory for ${factory.api} in app`
|
|
2745
|
-
);
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
2763
|
ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis());
|
|
2749
2764
|
return new ApiResolver(factoryRegistry);
|
|
2750
2765
|
}
|