feat(frontend-plugin-api): use extension boundary and suspense

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2023-10-19 10:05:37 +02:00
parent 055b7aec3d
commit 103b405746
@@ -14,18 +14,21 @@
* limitations under the License.
*/
import React from 'react';
import { ExtensionBoundary } from '../components';
import React, { lazy, useEffect } from 'react';
import { useAnalytics } from '@backstage/core-plugin-api';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { routableExtensionRenderedEvent } from '../../../core-plugin-api/src/analytics/Tracker';
import { ExtensionBoundary, ExtensionSuspense } from '../components';
import { createSchemaFromZod, PortableSchema } from '../schema';
import {
coreExtensionData,
createExtension,
Extension,
ExtensionInputValues,
AnyExtensionInputMap,
} from '../wiring';
import { AnyExtensionInputMap } from '../wiring/createExtension';
import { Expand } from '../types';
import { RouteRef } from '../routing';
import { Expand } from '../types';
/**
* Helper for creating extensions for a routable React page component.
@@ -55,6 +58,10 @@ export function createPageExtension<
}) => Promise<JSX.Element>;
},
): Extension<TConfig> {
const { id, routeRef } = options;
const attachTo = options.attachTo ?? { id: 'core.routes', input: 'routes' };
const configSchema =
'configSchema' in options
? options.configSchema
@@ -63,33 +70,49 @@ export function createPageExtension<
) as PortableSchema<TConfig>);
return createExtension({
id: options.id,
attachTo: options.attachTo ?? { id: 'core.routes', input: 'routes' },
id,
attachTo,
configSchema,
inputs: options.inputs,
disabled: options.disabled,
output: {
element: coreExtensionData.reactElement,
path: coreExtensionData.routePath,
routeRef: coreExtensionData.routeRef.optional(),
},
inputs: options.inputs,
configSchema,
factory({ bind, config, inputs, source }) {
const LazyComponent = React.lazy(() =>
const { path } = config;
const PageComponent = lazy(() =>
options
.loader({ config, inputs })
.then(element => ({ default: () => element })),
);
const ExtensionComponent = () => {
const analytics = useAnalytics();
// This event, never exposed to end-users of the analytics API,
// helps inform which extension metadata gets associated with a
// navigation event when the route navigated to is a gathered
// mountpoint.
useEffect(() => {
analytics.captureEvent(routableExtensionRenderedEvent, '');
}, [analytics]);
return <PageComponent />;
};
bind({
path: config.path,
path,
routeRef,
element: (
<ExtensionBoundary source={source}>
<React.Suspense fallback="...">
<LazyComponent />
</React.Suspense>
<ExtensionBoundary id={id} source={source} routeRef={routeRef}>
<ExtensionSuspense>
<ExtensionComponent />
</ExtensionSuspense>
</ExtensionBoundary>
),
routeRef: options.routeRef,
});
},
});