diff --git a/.changeset/silent-horses-raise.md b/.changeset/silent-horses-raise.md new file mode 100644 index 0000000000..de2671c3da --- /dev/null +++ b/.changeset/silent-horses-raise.md @@ -0,0 +1,7 @@ +--- +'@backstage/frontend-plugin-api': patch +'@backstage/frontend-test-utils': patch +'@backstage/frontend-app-api': patch +--- + +Added `elements` and `wrappers` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension` and `createAppRootWrapperExtension` extension creator, respectively, to conveniently create such extensions. diff --git a/.changeset/unlucky-bottles-run.md b/.changeset/unlucky-bottles-run.md new file mode 100644 index 0000000000..63c6ff1249 --- /dev/null +++ b/.changeset/unlucky-bottles-run.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app-visualizer': minor +--- + +Initial release of the app visualizer plugin. diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 4d77e35ad9..fe9b81f6db 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -21,6 +21,7 @@ "@backstage/plugin-airbrake": "workspace:^", "@backstage/plugin-apache-airflow": "workspace:^", "@backstage/plugin-api-docs": "workspace:^", + "@backstage/plugin-app-visualizer": "workspace:^", "@backstage/plugin-azure-devops": "workspace:^", "@backstage/plugin-azure-sites": "workspace:^", "@backstage/plugin-badges": "workspace:^", @@ -74,7 +75,6 @@ "@backstage/plugin-techdocs-react": "workspace:^", "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", - "@backstage/plugin-visualizer": "workspace:^", "@backstage/theme": "workspace:^", "@circleci/backstage-plugin": "^0.1.1", "@material-ui/core": "^4.12.2", diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 747576533a..ec333ce38f 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -32,7 +32,7 @@ import { createExtensionOverrides, } from '@backstage/frontend-plugin-api'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; -import appVisualizerPlugin from '@backstage/plugin-visualizer'; +import appVisualizerPlugin from '@backstage/plugin-app-visualizer'; import { homePage } from './HomePage'; import { convertLegacyApp } from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; diff --git a/packages/frontend-app-api/src/extensions/AppRoot.tsx b/packages/frontend-app-api/src/extensions/AppRoot.tsx index 0894287541..883074ca00 100644 --- a/packages/frontend-app-api/src/extensions/AppRoot.tsx +++ b/packages/frontend-app-api/src/extensions/AppRoot.tsx @@ -14,9 +14,16 @@ * limitations under the License. */ -import React, { ComponentType, ReactNode, useContext, useState } from 'react'; +import React, { + ComponentType, + Fragment, + ReactNode, + useContext, + useState, +} from 'react'; import { coreExtensionData, + createAppRootWrapperExtension, createExtension, createExtensionInput, createSignInPageExtension, @@ -40,26 +47,41 @@ export const AppRoot = createExtension({ attachTo: { id: 'app', input: 'root' }, inputs: { signInPage: createExtensionInput( - { - component: createSignInPageExtension.componentDataRef, - }, + { component: createSignInPageExtension.componentDataRef }, { singleton: true, optional: true }, ), children: createExtensionInput( - { - element: coreExtensionData.reactElement, - }, + { element: coreExtensionData.reactElement }, { singleton: true }, ), + elements: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + wrappers: createExtensionInput({ + component: createAppRootWrapperExtension.componentDataRef, + }), }, output: { element: coreExtensionData.reactElement, }, factory({ inputs }) { + let content: React.ReactNode = ( + <> + {inputs.elements.map(el => ( + {el.output.element} + ))} + {inputs.children.output.element} + + ); + + for (const wrapper of inputs.wrappers) { + content = {content}; + } + return { element: ( - {inputs.children.output.element} + {content} ), }; diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 2260db334f..6113c946ee 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -67,6 +67,7 @@ import { OpenIdConnectApi } from '@backstage/core-plugin-api'; import { PendingOAuthRequest } from '@backstage/core-plugin-api'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; +import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { SessionApi } from '@backstage/core-plugin-api'; @@ -390,6 +391,61 @@ export { createApiFactory }; export { createApiRef }; +// @public +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX_2.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX_2.Element); +}): ExtensionDefinition; + +// @public +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createAppRootWrapperExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + {} + >; +} + // @public (undocumented) export function createComponentExtension< TProps extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx new file mode 100644 index 0000000000..c8bf6ee355 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx @@ -0,0 +1,107 @@ +/* + * 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 { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootElementExtension } from './createAppRootElementExtension'; + +describe('createAppRootElementExtension', () => { + it('works with simple options and just an element', async () => { + const extension = createAppRootElementExtension({ + element:
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + attachTo: { id: 'app/root', input: 'elements' }, + disabled: false, + inputs: {}, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension).render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and a callback', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootElementExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + attachTo: { id: 'other', input: 'slot' }, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + element: ({ inputs, config }) => ( +
+ Hello, {config.name}, {inputs.children.length} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + namespace: 'ns', + name: 'test', + attachTo: { id: 'other', input: 'slot' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-root-element:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect( + screen.findByText('Hello, Robin, 1'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts new file mode 100644 index 0000000000..8be82d5540 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts @@ -0,0 +1,71 @@ +/* + * 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 { JSX } from 'react'; +import { PortableSchema } from '../schema/types'; +import { Expand } from '../types'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; + +/** + * Creates an extension that renders a React element at the app root, outside of + * the app layout. This is useful for example for shared popups and similar. + * + * @public + */ +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX.Element); +}): ExtensionDefinition { + return createExtension({ + kind: 'app-root-element', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'elements' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs, config }) { + return { + element: + typeof options.element === 'function' + ? options.element({ inputs, config }) + : options.element, + }; + }, + }); +} diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx new file mode 100644 index 0000000000..d21cfa7583 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx @@ -0,0 +1,119 @@ +/* + * 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 { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +import { createPageExtension } from './createPageExtension'; + +describe('createAppRootWrapperExtension', () => { + it('works with simple options and no props', async () => { + const extension = createAppRootWrapperExtension({ + Component: () =>
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-wrapper', + attachTo: { id: 'app/root', input: 'wrappers' }, + disabled: false, + inputs: {}, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
, + }), + ) + .add(extension) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and props', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootWrapperExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + Component: ({ inputs, config, children }) => ( +
+ {children} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-wrapper', + namespace: 'ns', + name: 'test', + attachTo: { id: 'app/root', input: 'wrappers' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
Hello
, + }), + ) + .add(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-root-wrapper:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + await expect(screen.findByTestId('Robin-1')).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx new file mode 100644 index 0000000000..bbc51806af --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -0,0 +1,84 @@ +/* + * 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, { ComponentType, PropsWithChildren } from 'react'; +import { PortableSchema } from '../schema/types'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; +import { createExtensionDataRef } from '../wiring/createExtensionDataRef'; +import { Expand } from '../types'; + +/** + * Creates an extension that renders a React wrapper at the app root, enclosing + * the app layout. This is useful for example for adding global React contexts + * and similar. + * + * @public + */ +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition { + return createExtension({ + kind: 'app-root-wrapper', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'wrappers' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + component: createAppRootWrapperExtension.componentDataRef, + }, + factory({ inputs, config }) { + const Component = (props: PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + return { + component: Component, + }; + }, + }); +} + +/** @public */ +export namespace createAppRootWrapperExtension { + export const componentDataRef = + createExtensionDataRef>>( + 'app.root.wrapper', + ); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index fd2e38de49..40e9f6f56d 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -15,6 +15,8 @@ */ export { createApiExtension } from './createApiExtension'; +export { createAppRootElementExtension } from './createAppRootElementExtension'; +export { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; export { createNavLogoExtension } from './createNavLogoExtension'; diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index 1a4ebbac48..2984af9dbf 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -14,7 +14,13 @@ * limitations under the License. */ -import React, { ComponentType, ReactNode, useContext, useState } from 'react'; +import React, { + ComponentType, + Fragment, + ReactNode, + useContext, + useState, +} from 'react'; import { MemoryRouter, Link } from 'react-router-dom'; import { RenderResult, render } from '@testing-library/react'; import { createSpecializedApp } from '@backstage/frontend-app-api'; @@ -25,6 +31,7 @@ import { RouteRef, configApiRef, coreExtensionData, + createAppRootWrapperExtension, createExtension, createExtensionInput, createExtensionOverrides, @@ -63,7 +70,7 @@ const NavItem = (props: { ); }; -const TestCoreNavExtension = createExtension({ +const TestAppNavExtension = createExtension({ namespace: 'app', name: 'nav', attachTo: { id: 'app/layout', input: 'nav' }, @@ -149,36 +156,52 @@ const AuthenticationProvider = (props: { return children; }; -const TestCoreRouterExtension = createExtension({ +const TestAppRootExtension = createExtension({ namespace: 'app', name: 'root', attachTo: { id: 'app', input: 'root' }, inputs: { signInPage: createExtensionInput( - { - component: createSignInPageExtension.componentDataRef, - }, + { component: createSignInPageExtension.componentDataRef }, { singleton: true, optional: true }, ), children: createExtensionInput( - { - element: coreExtensionData.reactElement, - }, + { element: coreExtensionData.reactElement }, { singleton: true }, ), + elements: createExtensionInput( + { element: coreExtensionData.reactElement }, + { optional: true }, + ), + wrappers: createExtensionInput( + { component: createAppRootWrapperExtension.componentDataRef }, + { optional: true }, + ), }, output: { element: coreExtensionData.reactElement, }, factory({ inputs }) { const SignInPage = inputs.signInPage?.output.component; - const children = inputs.children.output.element; + + let content: React.ReactNode = ( + <> + {inputs.elements.map(el => ( + {el.output.element} + ))} + {inputs.children.output.element} + + ); + + for (const wrapper of inputs.wrappers) { + content = {content}; + } return { element: ( - {children} + {content} ), @@ -278,8 +301,8 @@ export class ExtensionTester { createExtensionOverrides({ extensions: [ ...this.#extensions.map(extension => extension.definition), - TestCoreNavExtension, - TestCoreRouterExtension, + TestAppNavExtension, + TestAppRootExtension, ], }), ], diff --git a/plugins/visualizer/.eslintrc.js b/plugins/app-visualizer/.eslintrc.js similarity index 100% rename from plugins/visualizer/.eslintrc.js rename to plugins/app-visualizer/.eslintrc.js diff --git a/plugins/app-visualizer/README.md b/plugins/app-visualizer/README.md new file mode 100644 index 0000000000..865cd66746 --- /dev/null +++ b/plugins/app-visualizer/README.md @@ -0,0 +1,10 @@ +# @backstage/plugin-app-visualizer + +A plugin to help explore the structure of your Backstage app. + +This plugin provides the following extensions: + +| ID | Type | Description | Default Config | +| ------------------------- | --------- | ------------------------------------ | ------------------------- | +| `page:app-visualizer` | `Page` | The app visualizer page | `{ path: '/visualizer' }` | +| `nav-item:app-visualizer` | `NavItem` | Nav item for the app visualizer page | | diff --git a/plugins/visualizer/api-report.md b/plugins/app-visualizer/api-report.md similarity index 85% rename from plugins/visualizer/api-report.md rename to plugins/app-visualizer/api-report.md index 0cd9eface0..764caa7190 100644 --- a/plugins/visualizer/api-report.md +++ b/plugins/app-visualizer/api-report.md @@ -1,4 +1,4 @@ -## API Report File for "@backstage/plugin-visualizer" +## API Report File for "@backstage/plugin-app-visualizer" > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). diff --git a/plugins/visualizer/catalog-info.yaml b/plugins/app-visualizer/catalog-info.yaml similarity index 70% rename from plugins/visualizer/catalog-info.yaml rename to plugins/app-visualizer/catalog-info.yaml index f9cedddf87..cb444af524 100644 --- a/plugins/visualizer/catalog-info.yaml +++ b/plugins/app-visualizer/catalog-info.yaml @@ -1,8 +1,8 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: backstage-plugin-visualizer - title: '@backstage/plugin-visualizer' + name: backstage-plugin-app-visualizer + title: '@backstage/plugin-app-visualizer' description: Visualizes the Backstage app structure spec: lifecycle: experimental diff --git a/plugins/visualizer/package.json b/plugins/app-visualizer/package.json similarity index 87% rename from plugins/visualizer/package.json rename to plugins/app-visualizer/package.json index 8482cca16f..2d220e7633 100644 --- a/plugins/visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,8 +1,7 @@ { - "name": "@backstage/plugin-visualizer", + "name": "@backstage/plugin-app-visualizer", "description": "Visualizes the Backstage app structure", - "private": true, - "version": "0.0.2-next.2", + "version": "0.0.0", "publishConfig": { "access": "public" }, @@ -27,8 +26,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/icons": "^4.9.1", - "@types/react": "^16.13.1 || ^17.0.0" + "@material-ui/icons": "^4.9.1" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0", @@ -36,7 +34,8 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ "dist" diff --git a/plugins/visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx similarity index 100% rename from plugins/visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx rename to plugins/app-visualizer/src/components/AppVisualizerPage/AppVisualizerPage.tsx diff --git a/plugins/visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx similarity index 100% rename from plugins/visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx rename to plugins/app-visualizer/src/components/AppVisualizerPage/DetailedVisualizer.tsx diff --git a/plugins/visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx similarity index 100% rename from plugins/visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx rename to plugins/app-visualizer/src/components/AppVisualizerPage/TextVisualizer.tsx diff --git a/plugins/visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx b/plugins/app-visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx similarity index 100% rename from plugins/visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx rename to plugins/app-visualizer/src/components/AppVisualizerPage/TreeVisualizer.tsx diff --git a/plugins/visualizer/src/components/AppVisualizerPage/index.ts b/plugins/app-visualizer/src/components/AppVisualizerPage/index.ts similarity index 100% rename from plugins/visualizer/src/components/AppVisualizerPage/index.ts rename to plugins/app-visualizer/src/components/AppVisualizerPage/index.ts diff --git a/plugins/visualizer/src/index.ts b/plugins/app-visualizer/src/index.ts similarity index 100% rename from plugins/visualizer/src/index.ts rename to plugins/app-visualizer/src/index.ts diff --git a/plugins/visualizer/src/plugin.tsx b/plugins/app-visualizer/src/plugin.tsx similarity index 86% rename from plugins/visualizer/src/plugin.tsx rename to plugins/app-visualizer/src/plugin.tsx index 0aa8053604..9a726ecc99 100644 --- a/plugins/visualizer/src/plugin.tsx +++ b/plugins/app-visualizer/src/plugin.tsx @@ -25,14 +25,14 @@ import React from 'react'; const rootRouteRef = createRouteRef(); -const visualizerPage = createPageExtension({ +const appVisualizerPage = createPageExtension({ defaultPath: '/visualizer', routeRef: rootRouteRef, loader: () => import('./components/AppVisualizerPage').then(m => ), }); -export const visualizerNavItem = createNavItemExtension({ +export const appVisualizerNavItem = createNavItemExtension({ title: 'Visualizer', icon: VisualizerIcon, routeRef: rootRouteRef, @@ -40,6 +40,6 @@ export const visualizerNavItem = createNavItemExtension({ /** @public */ export const visualizerPlugin = createPlugin({ - id: 'visualizer', - extensions: [visualizerPage, visualizerNavItem], + id: 'app-visualizer', + extensions: [appVisualizerPage, appVisualizerNavItem], }); diff --git a/plugins/visualizer/CHANGELOG.md b/plugins/visualizer/CHANGELOG.md deleted file mode 100644 index 824b909935..0000000000 --- a/plugins/visualizer/CHANGELOG.md +++ /dev/null @@ -1,36 +0,0 @@ -# @backstage/plugin-visualizer - -## 0.0.2-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/frontend-plugin-api@0.4.1-next.2 - -## 0.0.2-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/core-plugin-api@1.8.2-next.0 - - @backstage/core-components@0.13.10-next.1 - - @backstage/frontend-plugin-api@0.4.1-next.1 - -## 0.0.2-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/core-components@0.13.10-next.0 - - @backstage/frontend-plugin-api@0.4.1-next.0 - - @backstage/core-plugin-api@1.8.1 - -## 0.0.1 - -### Patch Changes - -- Updated dependencies - - @backstage/core-plugin-api@1.8.1 - - @backstage/frontend-plugin-api@0.4.0 - - @backstage/core-components@0.13.9 - - @backstage/theme@0.5.0 diff --git a/plugins/visualizer/README.md b/plugins/visualizer/README.md deleted file mode 100644 index dd6f081a18..0000000000 --- a/plugins/visualizer/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @backstage/plugin-visualizer - -A plugin to help visualize the structure of your Backstage app. diff --git a/yarn.lock b/yarn.lock index edb50887c1..230f6d3e8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4644,6 +4644,24 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-app-visualizer@workspace:^, @backstage/plugin-app-visualizer@workspace:plugins/app-visualizer": + version: 0.0.0-use.local + resolution: "@backstage/plugin-app-visualizer@workspace:plugins/app-visualizer" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@types/react": ^16.13.1 || ^17.0.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + "@backstage/plugin-auth-backend-module-atlassian-provider@workspace:^, @backstage/plugin-auth-backend-module-atlassian-provider@workspace:plugins/auth-backend-module-atlassian-provider": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-backend-module-atlassian-provider@workspace:plugins/auth-backend-module-atlassian-provider" @@ -9563,24 +9581,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-visualizer@workspace:^, @backstage/plugin-visualizer@workspace:plugins/visualizer": - version: 0.0.0-use.local - resolution: "@backstage/plugin-visualizer@workspace:plugins/visualizer" - dependencies: - "@backstage/cli": "workspace:^" - "@backstage/core-components": "workspace:^" - "@backstage/core-plugin-api": "workspace:^" - "@backstage/frontend-plugin-api": "workspace:^" - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - languageName: unknown - linkType: soft - "@backstage/plugin-xcmetrics@workspace:plugins/xcmetrics": version: 0.0.0-use.local resolution: "@backstage/plugin-xcmetrics@workspace:plugins/xcmetrics" @@ -26383,6 +26383,7 @@ __metadata: "@backstage/plugin-airbrake": "workspace:^" "@backstage/plugin-apache-airflow": "workspace:^" "@backstage/plugin-api-docs": "workspace:^" + "@backstage/plugin-app-visualizer": "workspace:^" "@backstage/plugin-azure-devops": "workspace:^" "@backstage/plugin-azure-sites": "workspace:^" "@backstage/plugin-badges": "workspace:^" @@ -26436,7 +26437,6 @@ __metadata: "@backstage/plugin-techdocs-react": "workspace:^" "@backstage/plugin-todo": "workspace:^" "@backstage/plugin-user-settings": "workspace:^" - "@backstage/plugin-visualizer": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@circleci/backstage-plugin": ^0.1.1