From c737484eecaffb0e113693303c3b752b66fb8646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 29 Aug 2023 14:26:12 +0200 Subject: [PATCH] Add createPageExtension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Co-authored-by: Johan Haals Signed-off-by: Fredrik Adelöw --- .../app-next/src/examples/graphiqlPlugin.tsx | 24 ++---- packages/frontend-plugin-api/api-report.md | 34 ++++++++ .../src/createPageExtension.tsx | 83 +++++++++++++++++++ packages/frontend-plugin-api/src/index.ts | 29 +++---- 4 files changed, 139 insertions(+), 31 deletions(-) create mode 100644 packages/frontend-plugin-api/src/createPageExtension.tsx diff --git a/packages/app-next/src/examples/graphiqlPlugin.tsx b/packages/app-next/src/examples/graphiqlPlugin.tsx index c40b78fc97..d6c0d71fe7 100644 --- a/packages/app-next/src/examples/graphiqlPlugin.tsx +++ b/packages/app-next/src/examples/graphiqlPlugin.tsx @@ -15,25 +15,15 @@ */ import { - createExtension, + createPageExtension, createPlugin, - coreExtensionData, - createSchemaFromZod, } from '@backstage/frontend-plugin-api'; -import { Router as GraphiQLPage } from '@backstage/plugin-graphiql'; +import React from 'react'; -export const GraphiqlPageExtension = createExtension({ - output: { - component: coreExtensionData.reactComponent, - path: coreExtensionData.routePath, - }, - configSchema: createSchemaFromZod(z => - z.object({ path: z.string().default('/graphiql') }), - ), - factory({ bind, config }) { - bind.component(GraphiQLPage); - bind.path(config.path); - }, +export const GraphiqlPage = createPageExtension({ + defaultPath: '/graphiql', + component: () => + import('@backstage/plugin-graphiql').then(({ Router }) => ), }); export const graphiqlPlugin = createPlugin({ @@ -42,7 +32,7 @@ export const graphiqlPlugin = createPlugin({ { id: 'graphiql.page', at: 'core.router/routes', - extension: GraphiqlPageExtension, + extension: GraphiqlPage, }, ], }); diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index a86597d7bd..34ca6fdb5a 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + import { ComponentType } from 'react'; import { JsonObject } from '@backstage/types'; import { z } from 'zod'; @@ -77,6 +79,38 @@ export interface CreateExtensionOptions< output: TData; } +// @public +export function createPageExtension< + TConfig extends { + path: string; + }, + TInputs extends Record< + string, + { + extensionData: AnyExtensionDataMap; + } + >, +>( + options: ( + | { + defaultPath: string; + } + | { + configSchema: PortableSchema; + } + ) & { + inputs?: TInputs; + component: (props: { + config: TConfig; + inputs: { + [pointName in keyof TInputs]: ExtensionDataValue< + TInputs[pointName]['extensionData'] + >[]; + }; + }) => Promise; + }, +): Extension; + // @public (undocumented) export function createPlugin(options: BackstagePluginOptions): BackstagePlugin; diff --git a/packages/frontend-plugin-api/src/createPageExtension.tsx b/packages/frontend-plugin-api/src/createPageExtension.tsx new file mode 100644 index 0000000000..78674282a3 --- /dev/null +++ b/packages/frontend-plugin-api/src/createPageExtension.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { createSchemaFromZod, PortableSchema } from './createSchemaFromZod'; +import { + AnyExtensionDataMap, + coreExtensionData, + createExtension, + Extension, + ExtensionDataValue, +} from './types'; + +/** + * Helper for creating extensions for a routable React page component. + * + * @public + */ +export function createPageExtension< + TConfig extends { path: string }, + TInputs extends Record, +>( + options: ( + | { + defaultPath: string; + } + | { + configSchema: PortableSchema; + } + ) & { + inputs?: TInputs; + component: (props: { + config: TConfig; + inputs: { + [pointName in keyof TInputs]: ExtensionDataValue< + TInputs[pointName]['extensionData'] + >[]; + }; + }) => Promise; + }, +): Extension { + const configSchema = + 'configSchema' in options + ? options.configSchema + : (createSchemaFromZod(z => + z.object({ path: z.string().default(options.defaultPath) }), + ) as PortableSchema); + + return createExtension({ + output: { + component: coreExtensionData.reactComponent, + path: coreExtensionData.routePath, + }, + inputs: options.inputs, + configSchema, + factory({ bind, config, inputs }) { + const LazyComponent = React.lazy(() => + options + .component({ config, inputs }) + .then(element => ({ default: () => element })), + ); + bind.path(config.path); + bind.component(() => ( + + + + )); + }, + }); +} diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index f70c77abcc..46ff503121 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -20,21 +20,22 @@ * @packageDocumentation */ -export { - createExtension, - coreExtensionData, - createPlugin, - type ExtensionInstanceParameters, - type BackstagePlugin, - type Extension, - type AnyExtensionDataMap, - type BackstagePluginOptions, - type CreateExtensionOptions, - type ExtensionDataBind, - type ExtensionDataRef, - type ExtensionDataValue, -} from './types'; +export { createPageExtension } from './createPageExtension'; export { createSchemaFromZod, type PortableSchema, } from './createSchemaFromZod'; +export { + coreExtensionData, + createExtension, + createPlugin, + type AnyExtensionDataMap, + type BackstagePlugin, + type BackstagePluginOptions, + type CreateExtensionOptions, + type Extension, + type ExtensionDataBind, + type ExtensionDataRef, + type ExtensionDataValue, + type ExtensionInstanceParameters, +} from './types';