From 1807df9dbd9bf33c5bf19513ffd48e29492a1082 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 13 Sep 2023 14:55:51 +0200 Subject: [PATCH 1/6] Add support for Pages and Sidebar items in existing app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: Patrik Oldsberg Co-authored-by: Camila Belo Co-authored-by: Philipp Hugenroth Signed-off-by: Johan Haals --- app-config.yaml | 3 ++ packages/app/package.json | 1 + packages/app/src/App.tsx | 21 ++++++-- packages/app/src/components/Root/Root.tsx | 11 ++-- .../src/extensions/CoreNav.tsx | 8 ++- .../frontend-app-api/src/wiring/createApp.tsx | 52 ++++++++++++++++++- .../src/extensions/createNavItemExtension.tsx | 49 +++++++++++++++++ .../src/extensions/index.ts | 1 + .../src/wiring/coreExtensionData.ts | 14 ++++- .../frontend-plugin-api/src/wiring/index.ts | 2 +- plugins/graphiql/api-report.md | 5 ++ plugins/graphiql/src/alpha.tsx | 25 ++++++++- yarn.lock | 1 + 13 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx diff --git a/app-config.yaml b/app-config.yaml index 37cb61f26e..9e153e5763 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -1,6 +1,9 @@ app: title: Backstage Example App baseUrl: http://localhost:3000 + experimental: + packages: all # ✨ + #datadogRum: # clientToken: '123456789' # applicationId: qwerty diff --git a/packages/app/package.json b/packages/app/package.json index f019199bff..a4fa62b216 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -20,6 +20,7 @@ "@backstage/core-app-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-app-api": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-adr": "workspace:^", "@backstage/plugin-airbrake": "workspace:^", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index df54f37dc6..7f761500c5 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -27,7 +27,13 @@ import { RELATION_PROVIDES_API, } from '@backstage/catalog-model'; import { createApp } from '@backstage/app-defaults'; -import { AppRouter, FeatureFlagged, FlatRoutes } from '@backstage/core-app-api'; +import { + AppRouter, + ConfigReader, + defaultConfigLoader, + FeatureFlagged, + FlatRoutes, +} from '@backstage/core-app-api'; import { AlertDisplay, OAuthRequestDialog, @@ -55,7 +61,6 @@ import { import { orgPlugin } from '@backstage/plugin-org'; import { ExplorePage } from '@backstage/plugin-explore'; import { GcpProjectsPage } from '@backstage/plugin-gcp-projects'; -import { GraphiQLPage } from '@backstage/plugin-graphiql'; import { HomepageCompositionRoot } from '@backstage/plugin-home'; import { LighthousePage } from '@backstage/plugin-lighthouse'; import { NewRelicPage } from '@backstage/plugin-newrelic'; @@ -112,6 +117,7 @@ import { PuppetDbPage } from '@backstage/plugin-puppetdb'; import { DevToolsPage } from '@backstage/plugin-devtools'; import { customDevToolsPage } from './components/devtools/CustomDevToolsPage'; import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities'; +import { createExtensionTree } from '@backstage/frontend-app-api'; const app = createApp({ apis, @@ -158,6 +164,11 @@ const app = createApp({ }, }); +/* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ +const extensionTree = createExtensionTree({ + config: ConfigReader.fromConfigs(await defaultConfigLoader()), +}); + const routes = ( } /> @@ -271,7 +282,9 @@ const routes = ( path="/tech-radar" element={} /> - } /> + { + /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree.getRootRoutes() + } } /> } /> } /> @@ -310,7 +323,7 @@ export default app.createRoot( - {routes} + {routes} , ); diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index ffaf72296a..bfa2263aa5 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -27,7 +27,6 @@ import MenuIcon from '@material-ui/icons/Menu'; import MoneyIcon from '@material-ui/icons/MonetizationOn'; import LogoFull from './LogoFull'; import LogoIcon from './LogoIcon'; -import { GraphiQLIcon } from '@backstage/plugin-graphiql'; import { Settings as SidebarSettings, UserSettingsSignInAvatar, @@ -53,6 +52,7 @@ import { SearchModal } from '../search/SearchModal'; import Score from '@material-ui/icons/Score'; import { useApp } from '@backstage/core-plugin-api'; import BuildIcon from '@material-ui/icons/Build'; +import { ExtensionTree } from '@backstage/frontend-app-api'; const useSidebarLogoStyles = makeStyles({ root: { @@ -82,7 +82,10 @@ const SidebarLogo = () => { ); }; -export const Root = ({ children }: PropsWithChildren<{}>) => ( +export const Root = ({ + children, + extensionTree, +}: PropsWithChildren<{ extensionTree: ExtensionTree }>) => ( @@ -163,7 +166,9 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( to="cost-insights" text="Cost Insights" /> - + { + /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree.getSidebarItems() + } diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 4dc3636a29..da709d1eb3 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -65,7 +65,13 @@ const SidebarLogo = () => { export const CoreNav = createExtension({ id: 'core.nav', at: 'core.layout/nav', - inputs: {}, + inputs: { + targets: { + extensionData: { + path: coreExtensionData.navTarget, + }, + }, + }, output: { element: coreExtensionData.reactElement, }, diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 23b7b4ca11..44d534f702 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -47,6 +47,8 @@ import { RouteRef, BackstagePlugin as LegacyBackstagePlugin, featureFlagsApiRef, + attachComponentData, + useRouteRef, } from '@backstage/core-plugin-api'; import { getAvailablePlugins } from './discovery'; import { @@ -74,7 +76,8 @@ import { icons as defaultIcons, themes as defaultThemes, } from '../../../app-defaults/src/defaults'; -import { BrowserRouter } from 'react-router-dom'; +import { BrowserRouter, Route } from 'react-router-dom'; +import { SidebarItem } from '@backstage/core-components'; /** @public */ export interface ExtensionTreeNode { @@ -86,6 +89,8 @@ export interface ExtensionTreeNode { export interface ExtensionTree { getExtension(id: string): ExtensionTreeNode | undefined; getExtensionAttachments(id: string, inputName: string): ExtensionTreeNode[]; + getRootRoutes(): JSX.Element[]; + getSidebarItems(): JSX.Element[]; } /** @public */ @@ -108,6 +113,51 @@ export function createExtensionTree(options: { ): ExtensionTreeNode[] { return instances.get(id)?.attachments.get(inputName) ?? []; }, + getRootRoutes(): JSX.Element[] { + return this.getExtensionAttachments('core.routes', 'routes').map(node => { + const path = node.getData(coreExtensionData.routePath); + const element = node.getData(coreExtensionData.reactElement); + const routeRef = node.getData(coreExtensionData.routeRef); + if (!path || !element) { + throw new Error(`Invalid route extension: ${node.id}`); + } + const Component = () => { + return element; + }; + attachComponentData(Component, 'core.mountPoint', routeRef); + + return } />; + }); + }, + getSidebarItems(): JSX.Element[] { + const RoutedSidebarItem = (props: { + title: string; + routeRef: RouteRef; + icon: IconComponent; + }): React.JSX.Element => { + const location = useRouteRef(props.routeRef); + return ( + + ); + }; + + return this.getExtensionAttachments('core.nav', 'items') + .map((node, index) => { + const target = node.getData(coreExtensionData.navTarget); + if (!target) { + return null; + } + return ( + + ); + }) + .filter((x): x is JSX.Element => !!x); + }, }; } diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx new file mode 100644 index 0000000000..d3eaa53c66 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -0,0 +1,49 @@ +/* + * 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 { IconComponent, RouteRef } from '@backstage/core-plugin-api'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData, createExtension } from '../wiring'; + +export function createNavItemExtension(options: { + id: string; + routeRef: RouteRef; + title: string; + icon: IconComponent; +}) { + const { id, routeRef, title, icon } = options; + return createExtension({ + id, + at: 'core.nav/items', + configSchema: createSchemaFromZod(z => + z.object({ + title: z.string().default(title), + }), + ), + output: { + navTarget: coreExtensionData.navTarget, + }, + factory: ({ bind, config }) => { + bind({ + navTarget: { + title: config.title, + icon, + routeRef, + }, + }); + }, + }); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index fa6e60894f..0ec0cdf652 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -16,3 +16,4 @@ export { createApiExtension } from './createApiExtension'; export { createPageExtension } from './createPageExtension'; +export { createNavItemExtension } from './createNavItemExtension'; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 0f370855e1..079d5bcb18 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -14,14 +14,26 @@ * limitations under the License. */ -import { AnyApiFactory, RouteRef } from '@backstage/core-plugin-api'; import { JSX } from 'react'; +import { + AnyApiFactory, + IconComponent, + RouteRef, +} from '@backstage/core-plugin-api'; import { createExtensionDataRef } from './createExtensionDataRef'; +/** @public */ +export type NavTarget = { + title: string; + icon: IconComponent; + routeRef: RouteRef<{}>; +}; + /** @public */ export const coreExtensionData = { reactElement: createExtensionDataRef('core.reactElement'), routePath: createExtensionDataRef('core.routing.path'), apiFactory: createExtensionDataRef('core.api.factory'), routeRef: createExtensionDataRef('core.routing.ref'), + navTarget: createExtensionDataRef('core.nav.target'), }; diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 175200cf0c..4177ffbfcc 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { coreExtensionData } from './coreExtensionData'; +export { coreExtensionData, type NavTarget } from './coreExtensionData'; export { createExtension, type CreateExtensionOptions, diff --git a/plugins/graphiql/api-report.md b/plugins/graphiql/api-report.md index cbecc37006..e6c6ebe193 100644 --- a/plugins/graphiql/api-report.md +++ b/plugins/graphiql/api-report.md @@ -7,6 +7,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/frontend-plugin-api'; import { ErrorApi } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -15,6 +16,10 @@ import { OAuthApi } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; +// @alpha (undocumented) +const _default: BackstagePlugin_2; +export default _default; + // @public export type EndpointConfig = { id: string; diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 4d2abc12e7..1b095c32c9 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -19,6 +19,7 @@ import { createApiExtension, createExtension, createExtensionDataRef, + createNavItemExtension, createPageExtension, createPlugin, createSchemaFromZod, @@ -29,15 +30,30 @@ import { GraphQLEndpoints, GraphQLEndpoint, } from '@backstage/plugin-graphiql'; -import { createApiFactory } from '@backstage/core-plugin-api'; +import GraphiQLIcon from './assets/graphiql.icon.svg'; +import { + createApiFactory, + createRouteRef, + IconComponent, +} from '@backstage/core-plugin-api'; + +const graphiqlRouteRef = createRouteRef({ id: 'graphiql' }); /** @alpha */ export const GraphiqlPage = createPageExtension({ id: 'plugin.graphiql.page', defaultPath: '/graphiql', + routeRef: graphiqlRouteRef, loader: () => import('./components').then(m => ), }); +export const graphiqlPageSidebarItem = createNavItemExtension({ + id: 'plugin.graphiql.nav.index', + title: 'GraphiQL', + icon: GraphiQLIcon as IconComponent, + routeRef: graphiqlRouteRef, +}); + /** @internal */ const endpointDataRef = createExtensionDataRef( 'plugin.graphiql.endpoint', @@ -103,5 +119,10 @@ const gitlabGraphiQLBrowseExtension = createEndpointExtension({ /** @alpha */ export default createPlugin({ id: 'graphiql', - extensions: [GraphiqlPage, graphiqlBrowseApi, gitlabGraphiQLBrowseExtension], + extensions: [ + GraphiqlPage, + graphiqlBrowseApi, + gitlabGraphiQLBrowseExtension, + graphiqlPageSidebarItem, + ], }); diff --git a/yarn.lock b/yarn.lock index 0176682861..548b7d1ee5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25847,6 +25847,7 @@ __metadata: "@backstage/core-app-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" + "@backstage/frontend-app-api": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-adr": "workspace:^" "@backstage/plugin-airbrake": "workspace:^" From 219b46ae1a50f12d3e145e3929faf243d3a78df1 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 13 Sep 2023 15:06:42 +0200 Subject: [PATCH 2/6] Include default alpha export during package detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: Patrik Oldsberg Co-authored-by: Camila Belo Co-authored-by: Philipp Hugenroth Signed-off-by: Johan Haals --- .changeset/wise-boxes-kiss.md | 5 +++++ packages/cli/src/lib/bundler/packageDetection.ts | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/wise-boxes-kiss.md diff --git a/.changeset/wise-boxes-kiss.md b/.changeset/wise-boxes-kiss.md new file mode 100644 index 0000000000..ea3abd594d --- /dev/null +++ b/.changeset/wise-boxes-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Include default alpha export during package detection diff --git a/packages/cli/src/lib/bundler/packageDetection.ts b/packages/cli/src/lib/bundler/packageDetection.ts index 46cffdceb0..10686f7c86 100644 --- a/packages/cli/src/lib/bundler/packageDetection.ts +++ b/packages/cli/src/lib/bundler/packageDetection.ts @@ -70,6 +70,11 @@ async function detectPackages( depPackageJson.backstage?.role ?? '', ) ) { + // Include alpha entry point if available. If there's no default export it will be ignored + const exp = depPackageJson.exports; + if (exp && typeof exp === 'object' && './alpha' in exp) { + return [depName, `${depName}/alpha`]; + } return [depName]; } return []; From 5d4c45580c86da34d69eaa4ab3a521528e36337e Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 13 Sep 2023 15:12:07 +0200 Subject: [PATCH 3/6] Do not create extensionTree during tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: Patrik Oldsberg Co-authored-by: Camila Belo Co-authored-by: Philipp Hugenroth Signed-off-by: Johan Haals --- packages/app/src/App.tsx | 17 ++++++++++++----- packages/app/src/components/Root/Root.tsx | 5 +++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 7f761500c5..77cf96bf7b 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -117,7 +117,10 @@ import { PuppetDbPage } from '@backstage/plugin-puppetdb'; import { DevToolsPage } from '@backstage/plugin-devtools'; import { customDevToolsPage } from './components/devtools/CustomDevToolsPage'; import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities'; -import { createExtensionTree } from '@backstage/frontend-app-api'; +import { + createExtensionTree, + ExtensionTree, +} from '@backstage/frontend-app-api'; const app = createApp({ apis, @@ -165,9 +168,12 @@ const app = createApp({ }); /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ -const extensionTree = createExtensionTree({ - config: ConfigReader.fromConfigs(await defaultConfigLoader()), -}); +let extensionTree: ExtensionTree | undefined; +if (process.env.NODE_ENV === 'test') { + extensionTree = createExtensionTree({ + config: ConfigReader.fromConfigs(await defaultConfigLoader()), + }); +} const routes = ( @@ -283,7 +289,8 @@ const routes = ( element={} /> { - /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree.getRootRoutes() + /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree?.getRootRoutes() ?? + null } } /> } /> diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index bfa2263aa5..066ba4d05b 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -85,7 +85,7 @@ const SidebarLogo = () => { export const Root = ({ children, extensionTree, -}: PropsWithChildren<{ extensionTree: ExtensionTree }>) => ( +}: PropsWithChildren<{ extensionTree?: ExtensionTree }>) => ( @@ -167,7 +167,8 @@ export const Root = ({ text="Cost Insights" /> { - /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree.getSidebarItems() + /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ extensionTree?.getSidebarItems() ?? + null } From 0edd307a696c6544546a01fe6d25ffb1cf1bcd8c Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 13 Sep 2023 15:34:36 +0200 Subject: [PATCH 4/6] Fix exports and api reports Signed-off-by: Johan Haals --- packages/frontend-app-api/api-report.md | 4 ++++ packages/frontend-plugin-api/api-report.md | 19 +++++++++++++++++++ .../src/extensions/createNavItemExtension.tsx | 4 ++++ plugins/graphiql/alpha-api-report.md | 5 +++++ plugins/graphiql/api-report.md | 5 ----- plugins/graphiql/src/alpha.tsx | 1 + 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 04f30c2616..12cf853f9d 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -26,6 +26,10 @@ export interface ExtensionTree { getExtension(id: string): ExtensionTreeNode | undefined; // (undocumented) getExtensionAttachments(id: string, inputName: string): ExtensionTreeNode[]; + // (undocumented) + getRootRoutes(): JSX_2.Element[]; + // (undocumented) + getSidebarItems(): JSX_2.Element[]; } // @public (undocumented) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 4e0d44669f..abba3e7f2f 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -7,6 +7,7 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; @@ -53,6 +54,7 @@ export const coreExtensionData: { routePath: ConfigurableExtensionDataRef; apiFactory: ConfigurableExtensionDataRef; routeRef: ConfigurableExtensionDataRef, {}>; + navTarget: ConfigurableExtensionDataRef; }; // @public (undocumented) @@ -133,6 +135,16 @@ export interface CreateExtensionOptions< output: TOutput; } +// @public +export function createNavItemExtension(options: { + id: string; + routeRef: RouteRef; + title: string; + icon: IconComponent; +}): Extension<{ + title: string; +}>; + // @public export function createPageExtension< TConfig extends { @@ -271,6 +283,13 @@ export type ExtensionDataRef< $$type: '@backstage/ExtensionDataRef'; }; +// @public (undocumented) +export type NavTarget = { + title: string; + icon: IconComponent; + routeRef: RouteRef<{}>; +}; + // @public (undocumented) export interface PluginOptions { // (undocumented) diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index d3eaa53c66..8c55531866 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -18,6 +18,10 @@ import { IconComponent, RouteRef } from '@backstage/core-plugin-api'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; import { coreExtensionData, createExtension } from '../wiring'; +/** + * Helper for creating extensions for a nav item. + * @public + */ export function createNavItemExtension(options: { id: string; routeRef: RouteRef; diff --git a/plugins/graphiql/alpha-api-report.md b/plugins/graphiql/alpha-api-report.md index 665bf1464e..28537cfb15 100644 --- a/plugins/graphiql/alpha-api-report.md +++ b/plugins/graphiql/alpha-api-report.md @@ -30,5 +30,10 @@ export const GraphiqlPage: Extension<{ path: string; }>; +// @alpha (undocumented) +export const graphiqlPageSidebarItem: Extension<{ + title: string; +}>; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/graphiql/api-report.md b/plugins/graphiql/api-report.md index e6c6ebe193..cbecc37006 100644 --- a/plugins/graphiql/api-report.md +++ b/plugins/graphiql/api-report.md @@ -7,7 +7,6 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/frontend-plugin-api'; import { ErrorApi } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -16,10 +15,6 @@ import { OAuthApi } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; -// @alpha (undocumented) -const _default: BackstagePlugin_2; -export default _default; - // @public export type EndpointConfig = { id: string; diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 1b095c32c9..7c6cb8f07f 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -47,6 +47,7 @@ export const GraphiqlPage = createPageExtension({ loader: () => import('./components').then(m => ), }); +/** @alpha */ export const graphiqlPageSidebarItem = createNavItemExtension({ id: 'plugin.graphiql.nav.index', title: 'GraphiQL', From 4223e183d2fada8270ba56332eff37d522c52ba6 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Thu, 14 Sep 2023 11:09:27 +0200 Subject: [PATCH 5/6] chore: do not load in tests Signed-off-by: Johan Haals --- packages/app/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 77cf96bf7b..6371182221 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -169,7 +169,7 @@ const app = createApp({ /* HIGHLY EXPERIMENTAL. DO NOT USE THIS IN YOUR APP */ let extensionTree: ExtensionTree | undefined; -if (process.env.NODE_ENV === 'test') { +if (process.env.NODE_ENV !== 'test') { extensionTree = createExtensionTree({ config: ConfigReader.fromConfigs(await defaultConfigLoader()), }); From 2c39b7d57a4668a9d606b5e2a03f1d6009ecc76f Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Thu, 14 Sep 2023 13:42:42 +0200 Subject: [PATCH 6/6] Set routeRef id Signed-off-by: Johan Haals --- plugins/graphiql/src/alpha.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 7c6cb8f07f..3d1bf839af 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -37,7 +37,7 @@ import { IconComponent, } from '@backstage/core-plugin-api'; -const graphiqlRouteRef = createRouteRef({ id: 'graphiql' }); +const graphiqlRouteRef = createRouteRef({ id: 'plugin.graphiql.page' }); /** @alpha */ export const GraphiqlPage = createPageExtension({