@backstage/frontend-plugin-api 0.3.0 → 0.4.0-next.1

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/dist/index.esm.js CHANGED
@@ -1,14 +1,189 @@
1
- import { createApiRef, useApp, AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api';
2
- import React, { Component, Suspense, useEffect, lazy, useMemo } from 'react';
1
+ import { createVersionedContext, createVersionedValueMap, getOrCreateGlobalSingleton, useVersionedContext } from '@backstage/version-bridge';
2
+ import React, { useContext, useRef, Component, Suspense, useEffect, lazy, useMemo } from 'react';
3
+ import { createApiRef, useApi, AnalyticsContext as AnalyticsContext$1, useAnalytics as useAnalytics$1 } from '@backstage/core-plugin-api';
4
+ export { SessionState, alertApiRef, appThemeApiRef, atlassianAuthApiRef, bitbucketAuthApiRef, bitbucketServerAuthApiRef, configApiRef, createApiFactory, createApiRef, discoveryApiRef, errorApiRef, featureFlagsApiRef, fetchApiRef, githubAuthApiRef, gitlabAuthApiRef, googleAuthApiRef, identityApiRef, microsoftAuthApiRef, oauthRequestApiRef, oktaAuthApiRef, oneloginAuthApiRef, storageApiRef, useApi, useApiHolder, withApis } from '@backstage/core-plugin-api';
3
5
  import { Button } from '@material-ui/core';
4
6
  import { ErrorPanel } from '@backstage/core-components';
5
- import { getOrCreateGlobalSingleton, useVersionedContext } from '@backstage/version-bridge';
6
7
  import { z } from 'zod';
7
8
  import zodToJsonSchema from 'zod-to-json-schema';
8
9
  import { useLocation, useParams } from 'react-router-dom';
9
10
 
11
+ const AnalyticsReactContext = createVersionedContext("analytics-context");
12
+ const useAnalyticsContext = () => {
13
+ const theContext = useContext(AnalyticsReactContext);
14
+ if (theContext === void 0) {
15
+ return {
16
+ pluginId: "root",
17
+ extensionId: "App"
18
+ };
19
+ }
20
+ const theValue = theContext.atVersion(1);
21
+ if (theValue === void 0) {
22
+ throw new Error("No context found for version 1.");
23
+ }
24
+ return theValue;
25
+ };
26
+ const AnalyticsContext = (options) => {
27
+ const { attributes, children } = options;
28
+ const parentValues = useAnalyticsContext();
29
+ const combinedValue = {
30
+ ...parentValues,
31
+ ...attributes
32
+ };
33
+ const versionedCombinedValue = createVersionedValueMap({ 1: combinedValue });
34
+ return /* @__PURE__ */ React.createElement(AnalyticsReactContext.Provider, { value: versionedCombinedValue }, children);
35
+ };
36
+
10
37
  const appTreeApiRef = createApiRef({ id: "core.app-tree" });
11
38
 
39
+ const componentsApiRef = createApiRef({
40
+ id: "core.components"
41
+ });
42
+
43
+ const analyticsApiRef = createApiRef({
44
+ id: "core.analytics"
45
+ });
46
+
47
+ const globalEvents = getOrCreateGlobalSingleton(
48
+ "core-plugin-api:analytics-tracker-events",
49
+ () => ({
50
+ mostRecentGatheredNavigation: void 0,
51
+ mostRecentRoutableExtensionRender: void 0,
52
+ beforeUnloadRegistered: false
53
+ })
54
+ );
55
+ const routableExtensionRenderedEvent$1 = "_ROUTABLE-EXTENSION-RENDERED";
56
+ class Tracker {
57
+ constructor(analyticsApi, context = {
58
+ pluginId: "root",
59
+ extensionId: "App"
60
+ }) {
61
+ this.analyticsApi = analyticsApi;
62
+ this.context = context;
63
+ if (!globalEvents.beforeUnloadRegistered) {
64
+ addEventListener(
65
+ "beforeunload",
66
+ () => {
67
+ if (globalEvents.mostRecentGatheredNavigation) {
68
+ this.analyticsApi.captureEvent({
69
+ ...globalEvents.mostRecentGatheredNavigation,
70
+ ...globalEvents.mostRecentRoutableExtensionRender
71
+ });
72
+ globalEvents.mostRecentGatheredNavigation = void 0;
73
+ globalEvents.mostRecentRoutableExtensionRender = void 0;
74
+ }
75
+ },
76
+ { once: true, passive: true }
77
+ );
78
+ globalEvents.beforeUnloadRegistered = true;
79
+ }
80
+ }
81
+ setContext(context) {
82
+ this.context = context;
83
+ }
84
+ captureEvent(action, subject, {
85
+ value,
86
+ attributes
87
+ } = {}) {
88
+ const context = this.context;
89
+ if (action === routableExtensionRenderedEvent$1) {
90
+ if (globalEvents.mostRecentGatheredNavigation) {
91
+ globalEvents.mostRecentRoutableExtensionRender = {
92
+ context: {
93
+ ...context,
94
+ extensionId: "App"
95
+ }
96
+ };
97
+ }
98
+ return;
99
+ }
100
+ if (globalEvents.mostRecentGatheredNavigation) {
101
+ try {
102
+ this.analyticsApi.captureEvent({
103
+ ...globalEvents.mostRecentGatheredNavigation,
104
+ ...globalEvents.mostRecentRoutableExtensionRender
105
+ });
106
+ } catch (e) {
107
+ console.warn("Error during analytics event capture. %o", e);
108
+ }
109
+ globalEvents.mostRecentGatheredNavigation = void 0;
110
+ globalEvents.mostRecentRoutableExtensionRender = void 0;
111
+ }
112
+ if (action === "navigate" && context.pluginId === "root") {
113
+ globalEvents.mostRecentGatheredNavigation = {
114
+ action,
115
+ subject,
116
+ value,
117
+ attributes,
118
+ context
119
+ };
120
+ return;
121
+ }
122
+ try {
123
+ this.analyticsApi.captureEvent({
124
+ action,
125
+ subject,
126
+ value,
127
+ attributes,
128
+ context
129
+ });
130
+ } catch (e) {
131
+ console.warn("Error during analytics event capture. %o", e);
132
+ }
133
+ }
134
+ }
135
+
136
+ function useAnalyticsApi() {
137
+ try {
138
+ return useApi(analyticsApiRef);
139
+ } catch {
140
+ return { captureEvent: () => {
141
+ } };
142
+ }
143
+ }
144
+ function useAnalytics() {
145
+ const trackerRef = useRef(null);
146
+ const context = useAnalyticsContext();
147
+ const analyticsApi = useAnalyticsApi();
148
+ function getTracker() {
149
+ if (trackerRef.current === null) {
150
+ trackerRef.current = new Tracker(analyticsApi);
151
+ }
152
+ return trackerRef.current;
153
+ }
154
+ const tracker = getTracker();
155
+ tracker.setContext(context);
156
+ return tracker;
157
+ }
158
+
159
+ function createComponentRef(options) {
160
+ const { id } = options;
161
+ return {
162
+ id,
163
+ get T() {
164
+ throw new Error(`tried to read ComponentRef.T of ${id}`);
165
+ }
166
+ };
167
+ }
168
+ const coreProgressComponentRef = createComponentRef({
169
+ id: "core.components.progress"
170
+ });
171
+ const coreBootErrorPageComponentRef = createComponentRef({
172
+ id: "core.components.bootErrorPage"
173
+ });
174
+ const coreNotFoundErrorPageComponentRef = createComponentRef({
175
+ id: "core.components.notFoundErrorPage"
176
+ });
177
+ const coreErrorBoundaryFallbackComponentRef = createComponentRef({
178
+ id: "core.components.errorBoundaryFallback"
179
+ });
180
+ const coreComponentsRefs = {
181
+ progress: coreProgressComponentRef,
182
+ bootErrorPage: coreBootErrorPageComponentRef,
183
+ notFoundErrorPage: coreNotFoundErrorPageComponentRef,
184
+ errorBoundaryFallback: coreErrorBoundaryFallbackComponentRef
185
+ };
186
+
12
187
  var __defProp$3 = Object.defineProperty;
13
188
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
189
  var __publicField$3 = (obj, key, value) => {
@@ -51,13 +226,6 @@ class ErrorBoundary extends Component {
51
226
  }
52
227
  }
53
228
 
54
- function ExtensionSuspense(props) {
55
- const { children } = props;
56
- const app = useApp();
57
- const { Progress } = app.getComponents();
58
- return /* @__PURE__ */ React.createElement(Suspense, { fallback: /* @__PURE__ */ React.createElement(Progress, null) }, children);
59
- }
60
-
61
229
  getOrCreateGlobalSingleton(
62
230
  "core-plugin-api:analytics-tracker-events",
63
231
  () => ({
@@ -70,7 +238,7 @@ const routableExtensionRenderedEvent = "_ROUTABLE-EXTENSION-RENDERED";
70
238
 
71
239
  const RouteTracker = (props) => {
72
240
  const { disableTracking, children } = props;
73
- const analytics = useAnalytics();
241
+ const analytics = useAnalytics$1();
74
242
  useEffect(() => {
75
243
  if (disableTracking)
76
244
  return;
@@ -79,12 +247,13 @@ const RouteTracker = (props) => {
79
247
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
80
248
  };
81
249
  function ExtensionBoundary(props) {
82
- const { id, source, routable, children } = props;
250
+ var _a;
251
+ const { node, routable, children } = props;
83
252
  const attributes = {
84
- extension: id,
85
- pluginId: source == null ? void 0 : source.id
253
+ extension: node.spec.id,
254
+ pluginId: (_a = node.spec.source) == null ? void 0 : _a.id
86
255
  };
87
- return /* @__PURE__ */ React.createElement(ExtensionSuspense, null, /* @__PURE__ */ React.createElement(ErrorBoundary, { plugin: source }, /* @__PURE__ */ React.createElement(AnalyticsContext, { attributes }, /* @__PURE__ */ React.createElement(RouteTracker, { disableTracking: !routable }, children))));
256
+ return /* @__PURE__ */ React.createElement(Suspense, { fallback: "Loading..." }, /* @__PURE__ */ React.createElement(ErrorBoundary, { plugin: node.spec.source }, /* @__PURE__ */ React.createElement(AnalyticsContext$1, { attributes }, /* @__PURE__ */ React.createElement(RouteTracker, { disableTracking: !routable }, children))));
88
257
  }
89
258
 
90
259
  function createExtensionDataRef(id) {
@@ -104,7 +273,9 @@ const coreExtensionData = {
104
273
  apiFactory: createExtensionDataRef("core.api.factory"),
105
274
  routeRef: createExtensionDataRef("core.routing.ref"),
106
275
  navTarget: createExtensionDataRef("core.nav.target"),
107
- theme: createExtensionDataRef("core.theme")
276
+ theme: createExtensionDataRef("core.theme"),
277
+ logoElements: createExtensionDataRef("core.logos"),
278
+ component: createExtensionDataRef("component.ref")
108
279
  };
109
280
 
110
281
  function createExtension(options) {
@@ -135,21 +306,25 @@ function createExtensionInput(extensionData, config) {
135
306
  }
136
307
 
137
308
  function createPlugin(options) {
138
- var _a, _b, _c;
309
+ var _a, _b, _c, _d;
139
310
  return {
140
- ...options,
311
+ $$type: "@backstage/BackstagePlugin",
312
+ version: "v1",
313
+ id: options.id,
141
314
  routes: (_a = options.routes) != null ? _a : {},
142
315
  externalRoutes: (_b = options.externalRoutes) != null ? _b : {},
143
316
  extensions: (_c = options.extensions) != null ? _c : [],
144
- $$type: "@backstage/BackstagePlugin"
317
+ featureFlags: (_d = options.featureFlags) != null ? _d : []
145
318
  };
146
319
  }
147
320
 
148
321
  function createExtensionOverrides(options) {
322
+ var _a;
149
323
  return {
150
324
  $$type: "@backstage/ExtensionOverrides",
151
325
  version: "v1",
152
- extensions: options.extensions
326
+ extensions: options.extensions,
327
+ featureFlags: (_a = options.featureFlags) != null ? _a : []
153
328
  };
154
329
  }
155
330
 
@@ -219,14 +394,14 @@ function createPageExtension(options) {
219
394
  path: coreExtensionData.routePath,
220
395
  routeRef: coreExtensionData.routeRef.optional()
221
396
  },
222
- factory({ config, inputs, source }) {
397
+ factory({ config, inputs, node }) {
223
398
  const ExtensionComponent = lazy(
224
399
  () => options.loader({ config, inputs }).then((element) => ({ default: () => element }))
225
400
  );
226
401
  return {
227
402
  path: config.path,
228
403
  routeRef: options.routeRef,
229
- element: /* @__PURE__ */ React.createElement(ExtensionBoundary, { id, source, routable: true }, /* @__PURE__ */ React.createElement(ExtensionComponent, null))
404
+ element: /* @__PURE__ */ React.createElement(ExtensionBoundary, { node, routable: true }, /* @__PURE__ */ React.createElement(ExtensionComponent, null))
230
405
  };
231
406
  }
232
407
  });
@@ -255,6 +430,30 @@ function createNavItemExtension(options) {
255
430
  });
256
431
  }
257
432
 
433
+ const signInPageComponentDataRef = createExtensionDataRef("core.signInPage");
434
+ function createSignInPageExtension(options) {
435
+ var _a;
436
+ const { id } = options;
437
+ return createExtension({
438
+ id,
439
+ attachTo: (_a = options.attachTo) != null ? _a : { id: "core.router", input: "signInPage" },
440
+ configSchema: options.configSchema,
441
+ inputs: options.inputs,
442
+ disabled: options.disabled,
443
+ output: {
444
+ component: signInPageComponentDataRef
445
+ },
446
+ factory({ config, inputs, node }) {
447
+ const ExtensionComponent = lazy(
448
+ () => options.loader({ config, inputs }).then((component) => ({ default: component }))
449
+ );
450
+ return {
451
+ component: (props) => /* @__PURE__ */ React.createElement(ExtensionBoundary, { node, routable: true }, /* @__PURE__ */ React.createElement(ExtensionComponent, { ...props }))
452
+ };
453
+ }
454
+ });
455
+ }
456
+
258
457
  function createThemeExtension(theme) {
259
458
  return createExtension({
260
459
  id: `themes.${theme.id}`,
@@ -266,6 +465,37 @@ function createThemeExtension(theme) {
266
465
  });
267
466
  }
268
467
 
468
+ function createComponentExtension(options) {
469
+ const id = options.ref.id;
470
+ return createExtension({
471
+ id,
472
+ attachTo: { id: "core", input: "components" },
473
+ inputs: options.inputs,
474
+ disabled: options.disabled,
475
+ configSchema: options.configSchema,
476
+ output: {
477
+ component: coreExtensionData.component
478
+ },
479
+ factory({ config, inputs, node }) {
480
+ let ExtensionComponent;
481
+ if ("sync" in options.component) {
482
+ ExtensionComponent = options.component.sync({ config, inputs });
483
+ } else {
484
+ const loader = options.component.lazy({ config, inputs });
485
+ ExtensionComponent = lazy(
486
+ () => loader.then((component) => ({ default: component }))
487
+ );
488
+ }
489
+ return {
490
+ component: {
491
+ ref: options.ref,
492
+ impl: (props) => /* @__PURE__ */ React.createElement(ExtensionBoundary, { node }, /* @__PURE__ */ React.createElement(ExtensionComponent, { ...props }))
493
+ }
494
+ };
495
+ }
496
+ });
497
+ }
498
+
269
499
  const MESSAGE_MARKER = "eHgtF5hmbrXyiEvo";
270
500
  function describeParentCallSite(ErrorConstructor = Error) {
271
501
  const { stack } = new ErrorConstructor(MESSAGE_MARKER);
@@ -504,5 +734,5 @@ function useRouteRefParams(_routeRef) {
504
734
  return useParams();
505
735
  }
506
736
 
507
- export { ExtensionBoundary, appTreeApiRef, coreExtensionData, createApiExtension, createExtension, createExtensionDataRef, createExtensionInput, createExtensionOverrides, createExternalRouteRef, createNavItemExtension, createPageExtension, createPlugin, createRouteRef, createSchemaFromZod, createSubRouteRef, createThemeExtension, useRouteRef, useRouteRefParams };
737
+ export { AnalyticsContext, ExtensionBoundary, analyticsApiRef, appTreeApiRef, componentsApiRef, coreComponentsRefs, coreExtensionData, createApiExtension, createComponentExtension, createExtension, createExtensionDataRef, createExtensionInput, createExtensionOverrides, createExternalRouteRef, createNavItemExtension, createPageExtension, createPlugin, createRouteRef, createSchemaFromZod, createSignInPageExtension, createSubRouteRef, createThemeExtension, useAnalytics, useRouteRef, useRouteRefParams };
508
738
  //# sourceMappingURL=index.esm.js.map