From 236089c6cd04b36b350932506a128d0b9cb0862c Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 29 Mar 2022 20:09:17 +0200 Subject: [PATCH] feat(techdocs): delete addons plugin Co-authored-by: Emma Indal Signed-off-by: Camila Belo --- plugins/techdocs-addons/.eslintrc.js | 1 - plugins/techdocs-addons/README.md | 64 ----- plugins/techdocs-addons/api-report.md | 86 ------- plugins/techdocs-addons/package.json | 53 ----- plugins/techdocs-addons/src/addons.tsx | 153 ------------ .../TechDocsReaderPage/TechDocsReaderPage.tsx | 75 ------ .../components/TechDocsReaderPage/index.ts | 18 -- .../TechDocsReaderPageContent.tsx | 98 -------- .../TechDocsReaderPageContent/index.ts | 17 -- .../TechDocsReaderPageHeader.tsx | 61 ----- .../TechDocsReaderPageHeader/index.ts | 17 -- .../TechDocsReaderPageSubheader.tsx | 49 ---- .../TechDocsReaderPageSubheader/index.ts | 17 -- .../techdocs-addons/src/components/index.ts | 17 -- plugins/techdocs-addons/src/context.test.tsx | 146 ------------ plugins/techdocs-addons/src/context.tsx | 148 ------------ plugins/techdocs-addons/src/hooks.test.ts | 51 ---- plugins/techdocs-addons/src/hooks.ts | 51 ---- plugins/techdocs-addons/src/index.ts | 37 --- .../techdocs-addons/src/test-utils/index.ts | 17 -- .../techdocs-addons/src/test-utils/mocks.ts | 29 --- .../src/test-utils/test-utils.tsx | 219 ------------------ plugins/techdocs-addons/src/types.ts | 99 -------- 23 files changed, 1523 deletions(-) delete mode 100644 plugins/techdocs-addons/.eslintrc.js delete mode 100644 plugins/techdocs-addons/README.md delete mode 100644 plugins/techdocs-addons/api-report.md delete mode 100644 plugins/techdocs-addons/package.json delete mode 100644 plugins/techdocs-addons/src/addons.tsx delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPage/TechDocsReaderPage.tsx delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPage/index.ts delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageContent/index.ts delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/index.ts delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx delete mode 100644 plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/index.ts delete mode 100644 plugins/techdocs-addons/src/components/index.ts delete mode 100644 plugins/techdocs-addons/src/context.test.tsx delete mode 100644 plugins/techdocs-addons/src/context.tsx delete mode 100644 plugins/techdocs-addons/src/hooks.test.ts delete mode 100644 plugins/techdocs-addons/src/hooks.ts delete mode 100644 plugins/techdocs-addons/src/index.ts delete mode 100644 plugins/techdocs-addons/src/test-utils/index.ts delete mode 100644 plugins/techdocs-addons/src/test-utils/mocks.ts delete mode 100644 plugins/techdocs-addons/src/test-utils/test-utils.tsx delete mode 100644 plugins/techdocs-addons/src/types.ts diff --git a/plugins/techdocs-addons/.eslintrc.js b/plugins/techdocs-addons/.eslintrc.js deleted file mode 100644 index e2a53a6ad2..0000000000 --- a/plugins/techdocs-addons/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/techdocs-addons/README.md b/plugins/techdocs-addons/README.md deleted file mode 100644 index 0ee88f84d0..0000000000 --- a/plugins/techdocs-addons/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# @backstage/plugin-techdocs-addons - -Package encapsulating the TechDocs Addon framework. - -## What is an addon? - -An addon is a isolated piece of functionality that one can use to augment the -TechDocs experience at render-time. For example: an issue counter showing the -number of issues reported on the documentation, or the top contributors to the -documentation. - -## Create a new addon - -To create a new addon, you can use the `createTechDocsAddon` factory exported -from this plugin. Normally, addons are provided by Backstage plugins, which can -then be composed within a Backstage app. - -When you create a new Addon, it requires three things. - -1. A `name` for debugging and analytics purposes) -2. A `location`, indicating where/how the addon will be rendered. Valid - locations include: `header`, `subheader`, `primary sidebar`, - `secondary sidebar`, `content`, and `component`. Values are available on an - enumerable `TechDocsAddonLocations` and are type-hinted. -3. A `component`, encapsulating the addon's logic and functionality - -```tsx -import { - createTechDocsAddon, - TechDocsAddonLocations, -} from '@backstage/plugin-techdocs-addons'; -import { StackOverflowSecondarySidebarAddon } from './components'; - -export const StackOverflowSecondarySidebar = yourBackstagePlugin.provide( - createTechDocsAddon({ - name: 'StackOverflowSecondarySidebar', - location: TechDocsAddonLocations.SECONDARY_SIDEBAR, - component: StackOverflowSecondarySidebarAddon, - }), -); -``` - -## Compose your app with addons - -To configure which addons will augment the TechDocs experience in your -Backstage app, you need two things: - -- The `TechDocsAddons` component, which is responsible for registering the - addons. -- A list of the addons themselves, as exported by their respective plugins. - -```tsx -import { - TechDocsAddons, - TechDocsReaderPage, -} from '@backstage/plugin-techdocs-addons'; -import { StackOverflowSecondarySidebar } from '@backstage/plugin-soe'; - -}> - - - -; -``` diff --git a/plugins/techdocs-addons/api-report.md b/plugins/techdocs-addons/api-report.md deleted file mode 100644 index 77c9f4d276..0000000000 --- a/plugins/techdocs-addons/api-report.md +++ /dev/null @@ -1,86 +0,0 @@ -## API Report File for "@backstage/plugin-techdocs-addons" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { AsyncState } from 'react-use/lib/useAsyncFn'; -import { ComponentType } from 'react'; -import { Entity } from '@backstage/catalog-model'; -import { Extension } from '@backstage/core-plugin-api'; -import { default as React_2 } from 'react'; - -// @public -export function createTechDocsAddon( - options: TechDocsAddonOptions, -): Extension>; - -// @public -export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; - -// @public -export type TechDocsAddonAsyncMetadata = AsyncState; - -// @public -export enum TechDocsAddonLocations { - COMPONENT = 'component', - CONTENT = 'content', - HEADER = 'header', - PRIMARY_SIDEBAR = 'primary sidebar', - SECONDARY_SIDEBAR = 'secondary sidebar', - SUBHEADER = 'subheader', -} - -// @public -export type TechDocsAddonOptions = { - name: string; - location: TechDocsAddonLocations; - component: ComponentType; -}; - -// @public -export const TechDocsAddons: React_2.ComponentType; - -// @public -export type TechDocsEntityMetadata = Entity & { - locationMetadata?: { - type: string; - target: string; - }; -}; - -// @public -export type TechDocsMetadata = { - site_name: string; - site_description: string; -}; - -// @public -export const TechDocsReaderPage: ( - props: TechDocsReaderPageProps, -) => JSX.Element; - -// @public (undocumented) -export type TechDocsReaderPageProps = { - hideHeader?: boolean; - addonConfig?: React_2.ReactNode; - dom: Element | null; - asyncEntityMetadata: AsyncState; - asyncTechDocsMetadata: AsyncState; -}; - -// @public -export const useEntityMetadata: () => TechDocsAddonAsyncMetadata; - -// @public -export const useShadowRoot: () => ShadowRoot | undefined; - -// @public -export const useShadowRootElements: < - TReturnedElement extends HTMLElement = HTMLElement, ->( - selectors: string[], -) => TReturnedElement[]; - -// @public -export const useTechDocsMetadata: () => TechDocsAddonAsyncMetadata; -``` diff --git a/plugins/techdocs-addons/package.json b/plugins/techdocs-addons/package.json deleted file mode 100644 index 3e441eb56e..0000000000 --- a/plugins/techdocs-addons/package.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "@backstage/plugin-techdocs-addons", - "version": "0.0.0", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" - }, - "backstage": { - "role": "frontend-plugin" - }, - "scripts": { - "start": "backstage-cli package start", - "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", - "clean": "backstage-cli package clean", - "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" - }, - "dependencies": { - "@backstage/catalog-model": "^0.13.0", - "@backstage/core-components": "^0.9.1", - "@backstage/core-plugin-api": "^0.8.0", - "@backstage/test-utils": "^0.3.0", - "@material-ui/core": "^4.12.2", - "@material-ui/lab": "4.0.0-alpha.57", - "@material-ui/styles": "^4.11.0", - "jss": "~10.8.2", - "lodash.debounce": "^4.0.8", - "react-dom": "^17.0.2", - "react-helmet": "6.1.0", - "react-router-dom": "6.0.0-beta.0", - "react-use": "^17.2.4", - "testing-library__dom": "^7.29.4-beta.1", - "@testing-library/react": "^12.1.3" - }, - "peerDependencies": { - "@types/react": "^16.13.1 || ^17.0.0", - "react": "^16.13.1 || ^17.0.0" - }, - "devDependencies": { - "@testing-library/react-hooks": "^7.0.2", - "@testing-library/jest-dom": "^5.10.1", - "@types/lodash.debounce": "^4.0.6" - }, - "files": [ - "dist" - ] -} diff --git a/plugins/techdocs-addons/src/addons.tsx b/plugins/techdocs-addons/src/addons.tsx deleted file mode 100644 index 2151abd948..0000000000 --- a/plugins/techdocs-addons/src/addons.tsx +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2022 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 { - attachComponentData, - createReactExtension, - ElementCollection, - Extension, - useElementFilter, -} from '@backstage/core-plugin-api'; -import React, { - ComponentType, - createContext, - PropsWithChildren, - useCallback, - useContext, -} from 'react'; -import { useOutlet } from 'react-router-dom'; - -import { TechDocsAddonLocations, TechDocsAddonOptions } from './types'; - -export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; - -/** - * Marks the registry component. - * @public - */ -export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; - -/** - * TechDocs Addon registry. - * @public - */ -export const TechDocsAddons: React.ComponentType = () => null; - -attachComponentData(TechDocsAddons, TECHDOCS_ADDONS_WRAPPER_KEY, true); - -const getDataKeyByName = (name: string) => { - return `${TECHDOCS_ADDONS_KEY}.${name.toLocaleLowerCase('en-US')}`; -}; - -/** - * Create a TechDocs addon. - * @public - */ -export function createTechDocsAddon( - options: TechDocsAddonOptions, -): Extension> { - const { name, component: TechDocsAddon } = options; - return createReactExtension({ - name, - component: { - sync: (props: TComponentProps) => , - }, - data: { - [TECHDOCS_ADDONS_KEY]: options, - [getDataKeyByName(name)]: true, - }, - }); -} - -const getTechDocsAddonByName = (collection: ElementCollection, key: string) => { - return collection.selectByComponentData({ key }).getElements()[0]; -}; - -const getAllTechDocsAddons = (collection: ElementCollection) => { - return collection - .selectByComponentData({ - key: TECHDOCS_ADDONS_WRAPPER_KEY, - }) - .selectByComponentData({ - key: TECHDOCS_ADDONS_KEY, - }); -}; - -const getAllTechDocsAddonsData = (collection: ElementCollection) => { - return collection - .selectByComponentData({ - key: TECHDOCS_ADDONS_WRAPPER_KEY, - }) - .findComponentData({ - key: TECHDOCS_ADDONS_KEY, - }); -}; - -type TechDocsAddonConfig = { - config?: React.ReactNode | null; -}; - -const TechDocsAddonConfigContext = createContext({}); - -export const TechDocsAddonConfigProvider = ( - props: PropsWithChildren<{ config?: React.ReactNode }>, -) => { - const fromOutlet = useOutlet(); - const config = props.config ?? fromOutlet; - return ( - - {props.children} - - ); -}; - -const useTechDocsAddonsConfig = (): React.ReactNode | null => { - return useContext(TechDocsAddonConfigContext).config || null; -}; - -export const useTechDocsAddons = () => { - const node = useTechDocsAddonsConfig(); - - const collection = useElementFilter(node, getAllTechDocsAddons); - const options = useElementFilter(node, getAllTechDocsAddonsData); - - const findAddonByData = useCallback( - (data: TechDocsAddonOptions | undefined) => { - if (!collection || !data) return null; - const nameKey = getDataKeyByName(data.name); - return getTechDocsAddonByName(collection, nameKey) ?? null; - }, - [collection], - ); - - const renderComponentByName = useCallback( - (name: string) => { - const data = options.find(option => option.name === name); - return data ? findAddonByData(data) : null; - }, - [options, findAddonByData], - ); - - const renderComponentsByLocation = useCallback( - (location: TechDocsAddonLocations) => { - const data = options.filter(option => option.location === location); - return data.length ? data.map(findAddonByData) : null; - }, - [options, findAddonByData], - ); - - return { renderComponentByName, renderComponentsByLocation }; -}; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPage/TechDocsReaderPage.tsx b/plugins/techdocs-addons/src/components/TechDocsReaderPage/TechDocsReaderPage.tsx deleted file mode 100644 index 2941278feb..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPage/TechDocsReaderPage.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2022 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 { Page } from '@backstage/core-components'; -import React from 'react'; -import { useParams } from 'react-router-dom'; -import { AsyncState } from 'react-use/lib/useAsyncFn'; -import { TechDocsAddonConfigProvider } from '../../addons'; - -import { - TechDocsMetadataProvider, - TechDocsEntityProvider, - TechDocsReaderPageProvider, -} from '../../context'; -import { TechDocsEntityMetadata, TechDocsMetadata } from '../../types'; -import { TechDocsReaderPageContent } from '../TechDocsReaderPageContent'; -import { TechDocsReaderPageHeader } from '../TechDocsReaderPageHeader'; -import { TechDocsReaderPageSubheader } from '../TechDocsReaderPageSubheader'; - -/** - * @public - */ -export type TechDocsReaderPageProps = { - hideHeader?: boolean; - addonConfig?: React.ReactNode; - dom: Element | null; - asyncEntityMetadata: AsyncState; - asyncTechDocsMetadata: AsyncState; -}; - -/** - * An addon-aware implementation of the TechDocsReaderPage. - * @public - */ -export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { - const { - addonConfig, - asyncEntityMetadata, - asyncTechDocsMetadata, - dom, - hideHeader = false, - } = props; - const { namespace, kind, name } = useParams(); - const entityName = { namespace, kind, name }; - return ( - - - - - - {!hideHeader && } - - {/* todo(backstage/techdocs-core): handle state indicator */} - {/* */} - - - - - - - ); -}; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPage/index.ts b/plugins/techdocs-addons/src/components/TechDocsReaderPage/index.ts deleted file mode 100644 index 3055a865df..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPage/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export { TechDocsReaderPage } from './TechDocsReaderPage'; -export type { TechDocsReaderPageProps } from './TechDocsReaderPage'; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx b/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx deleted file mode 100644 index 6e3ec99b21..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2022 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 { Content, Progress } from '@backstage/core-components'; -import { Portal } from '@material-ui/core'; -import { StylesProvider, jssPreset } from '@material-ui/styles'; -import React, { useEffect, useRef, useState } from 'react'; -import { create } from 'jss'; - -import { useTechDocsAddons } from '../../addons'; -import { useTechDocsReaderPage } from '../../context'; -import { TechDocsAddonLocations as locations } from '../../types'; - -export const TechDocsReaderPageContent = ({ dom }: { dom: Element | null }) => { - const ref = useRef(null); - const [jss, setJss] = useState( - create({ - ...jssPreset(), - insertionPoint: undefined, - }), - ); - - const addons = useTechDocsAddons(); - const { setShadowRoot } = useTechDocsReaderPage(); - - useEffect(() => { - const shadowHost = ref.current; - if (!dom || !shadowHost || shadowHost.shadowRoot) return; - - setJss( - create({ - ...jssPreset(), - insertionPoint: dom.querySelector('head') || undefined, - }), - ); - - const shadowRoot = shadowHost.attachShadow({ mode: 'open' }); - shadowRoot.innerHTML = ''; - shadowRoot.appendChild(dom); - setShadowRoot(shadowRoot); - }, [dom, setShadowRoot]); - - const contentElement = ref.current?.shadowRoot?.querySelector( - '[data-md-component="container"]', - ); - const primarySidebarElement = ref.current?.shadowRoot?.querySelector( - 'div[data-md-component="sidebar"][data-md-type="navigation"], div[data-md-component="navigation"]', - ); - const secondarySidebarElement = ref.current?.shadowRoot?.querySelector( - 'div[data-md-component="sidebar"][data-md-type="toc"], div[data-md-component="toc"]', - ); - - const primarySidebarAddonLocation = document.createElement('div'); - primarySidebarElement?.prepend(primarySidebarAddonLocation); - - const secondarySidebarAddonLocation = document.createElement('div'); - secondarySidebarElement?.prepend(secondarySidebarAddonLocation); - - // do not return content until dom is ready - if (!dom) { - return ( - - - - ); - } - - return ( - - {/* sheetsManager={new Map()} is needed in order to deduplicate the injection of CSS in the page. */} - -
- - {addons.renderComponentsByLocation(locations.PRIMARY_SIDEBAR)} - - - {addons.renderComponentsByLocation(locations.CONTENT)} - - - {addons.renderComponentsByLocation(locations.SECONDARY_SIDEBAR)} - - - - ); -}; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/index.ts b/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/index.ts deleted file mode 100644 index 6ad45cd281..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageContent/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export { TechDocsReaderPageContent } from './TechDocsReaderPageContent'; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx b/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx deleted file mode 100644 index 6a8322e57e..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2022 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 { Header } from '@backstage/core-components'; -import { configApiRef, useApi } from '@backstage/core-plugin-api'; -// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs -import { Skeleton } from '@material-ui/lab'; -import React, { useEffect } from 'react'; -import Helmet from 'react-helmet'; - -import { useTechDocsAddons } from '../../addons'; -import { useTechDocsMetadata, useTechDocsReaderPage } from '../../context'; -import { TechDocsAddonLocations as locations } from '../../types'; - -const skeleton = ; - -export const TechDocsReaderPageHeader = () => { - const addons = useTechDocsAddons(); - const configApi = useApi(configApiRef); - - const { value: metadata } = useTechDocsMetadata(); - - const { title, setTitle, subtitle, setSubtitle } = useTechDocsReaderPage(); - - useEffect(() => { - if (!metadata) return; - setTitle(prevTitle => prevTitle || metadata.site_name); - setSubtitle( - prevSubtitle => prevSubtitle || metadata.site_description || 'Home', - ); - }, [metadata, setTitle, setSubtitle]); - - const appTitle = configApi.getOptional('app.title') || 'Backstage'; - const tabTitle = [subtitle, title, appTitle].filter(Boolean).join(' | '); - - return ( -
- - {tabTitle} - - {addons.renderComponentsByLocation(locations.HEADER)} -
- ); -}; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/index.ts b/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/index.ts deleted file mode 100644 index 741a8e9af1..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageHeader/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader'; diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx b/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx deleted file mode 100644 index 9e323cce3f..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2022 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 { Box, Toolbar, ToolbarProps, withStyles } from '@material-ui/core'; -import React from 'react'; - -import { useTechDocsAddons } from '../../addons'; -import { TechDocsAddonLocations as locations } from '../../types'; - -export const TechDocsReaderPageSubheader = withStyles(theme => ({ - root: { - gridArea: 'pageSubheader', - flexDirection: 'column', - minHeight: 'auto', - padding: theme.spacing(3, 3, 0), - }, -}))(({ ...rest }: ToolbarProps) => { - const addons = useTechDocsAddons(); - - if (!addons.renderComponentsByLocation(locations.SUBHEADER)) return null; - - return ( - - {addons.renderComponentsByLocation(locations.SUBHEADER) && ( - - {addons.renderComponentsByLocation(locations.SUBHEADER)} - - )} - - ); -}); diff --git a/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/index.ts b/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/index.ts deleted file mode 100644 index 78f270e191..0000000000 --- a/plugins/techdocs-addons/src/components/TechDocsReaderPageSubheader/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export { TechDocsReaderPageSubheader } from './TechDocsReaderPageSubheader'; diff --git a/plugins/techdocs-addons/src/components/index.ts b/plugins/techdocs-addons/src/components/index.ts deleted file mode 100644 index 8d5b43143e..0000000000 --- a/plugins/techdocs-addons/src/components/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export * from './TechDocsReaderPage'; diff --git a/plugins/techdocs-addons/src/context.test.tsx b/plugins/techdocs-addons/src/context.test.tsx deleted file mode 100644 index 921c2efd7d..0000000000 --- a/plugins/techdocs-addons/src/context.test.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2022 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 { TechDocsMetadata } from './types'; -import { - useEntityMetadata, - useTechDocsMetadata, - useTechDocsReaderPage, - TechDocsEntityProvider, - TechDocsMetadataProvider, - TechDocsReaderPageProvider, -} from './context'; -import { renderHook, act } from '@testing-library/react-hooks'; - -import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; - -const mockEntity: Entity = { - apiVersion: 'v1', - kind: 'Component', - metadata: { name: 'test-component', namespace: 'default' }, -}; - -const mockTechDocsMetadata: TechDocsMetadata = { - site_name: 'test-componnet', - site_description: 'this is a test component', -}; - -const mockShadowRoot = () => { - const div = document.createElement('div'); - const shadowRoot = div.attachShadow({ mode: 'open' }); - shadowRoot.innerHTML = '

Shadow DOM Mock

'; - return shadowRoot; -}; - -const wrapper = ({ - entityName = { - namespace: mockEntity.metadata.namespace!!, - kind: mockEntity.kind, - name: mockEntity.metadata.name, - }, - children, -}: { - entityName: CompoundEntityRef; - children: React.ReactNode; -}) => ( - - - - {children} - - - -); - -describe('context', () => { - describe('useEntityMetadata', () => { - it('should return loading state', async () => { - const { result } = renderHook(() => useEntityMetadata()); - - await expect(result.current.loading).toEqual(true); - }); - - it('should return expected entity values', async () => { - const { result } = renderHook(() => useEntityMetadata(), { wrapper }); - - expect(result.current.value).toBeDefined(); - expect(result.current.error).toBeUndefined(); - expect(result.current.value).toMatchObject(mockEntity); - }); - }); - - describe('useTechDocsMetadata', () => { - it('should return loading state', async () => { - const { result } = renderHook(() => useTechDocsMetadata()); - - await expect(result.current.loading).toEqual(true); - }); - - it('should return expected techdocs metadata values', async () => { - const { result } = renderHook(() => useTechDocsMetadata(), { wrapper }); - - expect(result.current.value).toBeDefined(); - expect(result.current.error).toBeUndefined(); - expect(result.current.value).toMatchObject(mockTechDocsMetadata); - }); - }); - - describe('useTechDocsReaderPage', () => { - it('should set title', () => { - const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - - expect(result.current.title).toBe(''); - - act(() => result.current.setTitle('test site title')); - expect(result.current.title).toBe('test site title'); - }); - - it('should set subtitle', () => { - const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - - expect(result.current.subtitle).toBe(''); - - act(() => result.current.setSubtitle('test site subtitle')); - expect(result.current.subtitle).toBe('test site subtitle'); - }); - - it('should set shadow root', async () => { - const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - - // mock shadowroot - const shadowRoot = mockShadowRoot(); - - act(() => result.current.setShadowRoot(shadowRoot)); - - expect(result.current.shadowRoot?.innerHTML).toBe( - '

Shadow DOM Mock

', - ); - }); - }); -}); diff --git a/plugins/techdocs-addons/src/context.tsx b/plugins/techdocs-addons/src/context.tsx deleted file mode 100644 index 54a73e2589..0000000000 --- a/plugins/techdocs-addons/src/context.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2022 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 { CompoundEntityRef } from '@backstage/catalog-model'; -import React, { - createContext, - Dispatch, - PropsWithChildren, - SetStateAction, - useContext, - useState, -} from 'react'; -import { AsyncState } from 'react-use/lib/useAsync'; -import { - TechDocsAddonAsyncMetadata, - TechDocsEntityMetadata, - TechDocsMetadata, -} from './types'; - -type PropsWithAsyncMetadata = PropsWithChildren<{ - asyncValue: AsyncState; -}>; -type PropsWithEntityName = PropsWithChildren<{ entityName: CompoundEntityRef }>; - -const initialContextValue = { - loading: true, - error: undefined, - value: undefined, -}; - -const TechDocsMetadataContext = - createContext>( - initialContextValue, - ); - -export const TechDocsMetadataProvider = ({ - asyncValue, - children, -}: PropsWithAsyncMetadata) => { - return ( - - {children} - - ); -}; - -/** - * Hook for use within TechDocs addons to retrieve TechDocs Metadata for the - * current TechDocs site. - * @public - */ -export const useTechDocsMetadata = () => { - return useContext(TechDocsMetadataContext); -}; - -const TechDocsEntityContext = - createContext>( - initialContextValue, - ); - -export const TechDocsEntityProvider = ({ - asyncValue, - children, -}: PropsWithAsyncMetadata) => { - return ( - - {children} - - ); -}; - -/** - * Hook for use within TechDocs addons to retrieve Entity Metadata for the - * current TechDocs site. - * @public - */ -export const useEntityMetadata = () => { - return useContext(TechDocsEntityContext); -}; - -export type TechDocsReaderPageValue = { - entityName: CompoundEntityRef; - shadowRoot?: ShadowRoot; - setShadowRoot: Dispatch>; - title: string; - setTitle: Dispatch>; - subtitle: string; - setSubtitle: Dispatch>; -}; - -export const defaultTechDocsReaderPageValue: TechDocsReaderPageValue = { - title: '', - setTitle: () => {}, - subtitle: '', - setSubtitle: () => {}, - setShadowRoot: () => {}, - entityName: { kind: '', name: '', namespace: '' }, -}; - -export const TechDocsReaderPageContext = createContext( - defaultTechDocsReaderPageValue, -); - -export const useTechDocsReaderPage = () => { - return useContext(TechDocsReaderPageContext); -}; - -export const TechDocsReaderPageProvider = ({ - entityName, - children, -}: PropsWithEntityName) => { - const [title, setTitle] = useState(defaultTechDocsReaderPageValue.title); - const [subtitle, setSubtitle] = useState( - defaultTechDocsReaderPageValue.subtitle, - ); - const [shadowRoot, setShadowRoot] = useState( - defaultTechDocsReaderPageValue.shadowRoot, - ); - - const value = { - entityName, - shadowRoot, - setShadowRoot, - title, - setTitle, - subtitle, - setSubtitle, - }; - - return ( - - {children} - - ); -}; diff --git a/plugins/techdocs-addons/src/hooks.test.ts b/plugins/techdocs-addons/src/hooks.test.ts deleted file mode 100644 index c85d3a3d11..0000000000 --- a/plugins/techdocs-addons/src/hooks.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022 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 { useShadowRoot, useShadowRootElements } from './hooks'; -import { renderHook } from '@testing-library/react-hooks'; - -const mockShadowRoot = () => { - const div = document.createElement('div'); - const shadowRoot = div.attachShadow({ mode: 'open' }); - shadowRoot.innerHTML = '

Shadow DOM Mock

'; - return shadowRoot; -}; - -const shadowRoot = mockShadowRoot(); - -jest.mock('./context', () => { - return { - useTechDocsReaderPage: () => ({ shadowRoot }), - }; -}); - -describe('hooks', () => { - describe('useShadowRoot', () => { - it('should return shadow root', async () => { - const { result } = renderHook(() => useShadowRoot()); - - expect(result.current?.innerHTML).toBe(shadowRoot.innerHTML); - }); - }); - - describe('useShadowRootElements', () => { - it('should return shadow root elements based on selector', () => { - const { result } = renderHook(() => useShadowRootElements(['h1'])); - - expect(result.current).toHaveLength(1); - }); - }); -}); diff --git a/plugins/techdocs-addons/src/hooks.ts b/plugins/techdocs-addons/src/hooks.ts deleted file mode 100644 index 7bc6152006..0000000000 --- a/plugins/techdocs-addons/src/hooks.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022 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 { useTechDocsReaderPage } from './context'; - -/** - * Hook for use within TechDocs addons that provides access to the underlying - * shadow root of the current page, allowing the DOM within to be mutated. - * @public - */ -export const useShadowRoot = () => { - const { shadowRoot } = useTechDocsReaderPage(); - return shadowRoot; -}; - -/** - * Convenience hook for use within TechDocs addons that provides access to - * elements that match a given selector within the shadow root. - * - * todo(backstage/techdocs-core): Consider extending `selectors` from string[] - * to some kind of typed object array, so users have more control over the - * shape of the result. e.g. a flag to indicate querySelector vs. - * querySelectorAll. - * - * @public - */ -export const useShadowRootElements = < - TReturnedElement extends HTMLElement = HTMLElement, ->( - selectors: string[], -): TReturnedElement[] => { - const shadowRoot = useShadowRoot(); - if (!shadowRoot) return []; - return selectors - .map(selector => shadowRoot?.querySelectorAll(selector)) - .filter(nodeList => nodeList.length) - .map(nodeList => Array.from(nodeList)) - .flat(); -}; diff --git a/plugins/techdocs-addons/src/index.ts b/plugins/techdocs-addons/src/index.ts deleted file mode 100644 index 5e7b3211a9..0000000000 --- a/plugins/techdocs-addons/src/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2022 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. - */ - -/** - * Package encapsulating the TechDocs Addon framework. - * - * @packageDocumentation - */ - -export { - createTechDocsAddon, - TechDocsAddons, - TECHDOCS_ADDONS_WRAPPER_KEY, -} from './addons'; -export * from './components'; -export { useEntityMetadata, useTechDocsMetadata } from './context'; -export { useShadowRoot, useShadowRootElements } from './hooks'; -export { TechDocsAddonLocations } from './types'; -export type { - TechDocsAddonAsyncMetadata, - TechDocsAddonOptions, - TechDocsMetadata, - TechDocsEntityMetadata, -} from './types'; diff --git a/plugins/techdocs-addons/src/test-utils/index.ts b/plugins/techdocs-addons/src/test-utils/index.ts deleted file mode 100644 index 3bcf5f5ab8..0000000000 --- a/plugins/techdocs-addons/src/test-utils/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export * from './test-utils'; diff --git a/plugins/techdocs-addons/src/test-utils/mocks.ts b/plugins/techdocs-addons/src/test-utils/mocks.ts deleted file mode 100644 index fd4665237c..0000000000 --- a/plugins/techdocs-addons/src/test-utils/mocks.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 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. - */ - -export const useTechDocsReaderDom = jest.fn(); -export const useParams = jest.fn(); -jest.mock('@backstage/plugin-techdocs', () => ({ - ...(jest.requireActual('@backstage/plugin-techdocs') as {}), - useTechDocsReaderDom, - withTechDocsReaderProvider: jest.fn(x => x), - TechDocsStateIndicator: jest.fn(() => null), -})); -// todo(backstage/techdocs-core): Use core test-utils' `routeEntries` option. -jest.mock('react-router', () => ({ - ...(jest.requireActual('react-router') as {}), - useParams, -})); diff --git a/plugins/techdocs-addons/src/test-utils/test-utils.tsx b/plugins/techdocs-addons/src/test-utils/test-utils.tsx deleted file mode 100644 index 4362bb8cf7..0000000000 --- a/plugins/techdocs-addons/src/test-utils/test-utils.tsx +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2022 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 order matters for jest manual mocks! import this first. -import { useTechDocsReaderDom, useParams } from './mocks'; - -import React, { ReactElement, Fragment } from 'react'; - -// Shadow DOM support for the simple and complete DOM testing utilities -// https://github.com/testing-library/dom-testing-library/issues/742#issuecomment-674987855 -import { screen } from 'testing-library__dom'; -import { renderToStaticMarkup } from 'react-dom/server'; -import { Route, Routes } from 'react-router-dom'; -import { act, render } from '@testing-library/react'; -import { AsyncState } from 'react-use/lib/useAsyncFn'; - -import { - wrapInTestApp, - TestApiProvider, - TestApiProviderProps, -} from '@backstage/test-utils'; - -import { TechDocsEntityMetadata, TechDocsMetadata } from '../types'; -import { TechDocsReaderPage, TechDocsAddons } from '..'; - -type RecursivePartial = { - [P in keyof T]?: RecursivePartial; -}; - -type Apis = TestApiProviderProps['apis']; - -export type TechDocsAddonsBuilder = { - dom: ReactElement; - entity: RecursivePartial; - metadata: RecursivePartial; - componentId: string; - apis: Apis; - path: string; -}; - -const defaultOptions: TechDocsAddonsBuilder = { - dom: <>, - entity: {}, - metadata: {}, - componentId: 'docs', - apis: [], - path: '', -}; - -const defaultMetadata = { - site_name: 'Tech Docs', - site_description: 'Tech Docs', -}; - -const defaultEntity = { - kind: 'Component', - metadata: { namespace: 'default', name: 'docs' }, -}; - -const defaultDom = ( - - - -
-
-
-
-
- - -); - -export class TechDocsAddonBuilder { - private options: TechDocsAddonsBuilder = defaultOptions; - private addons: ReactElement[]; - - static buildAddonsInTechDocs(addons: ReactElement[]) { - return new TechDocsAddonBuilder(addons); - } - - constructor(addons: ReactElement[]) { - this.addons = addons; - } - - withApis(apis: Apis) { - const refs = apis.map(([ref]) => ref); - this.options.apis = this.options.apis - .filter(([ref]) => !refs.includes(ref)) - .concat(apis); - return this; - } - - withDom(dom: ReactElement) { - this.options.dom = dom; - return this; - } - - withMetadata(metadata: RecursivePartial) { - this.options.metadata = metadata; - return this; - } - - withEntity(entity: RecursivePartial) { - this.options.entity = entity; - return this; - } - - atPath(path: string) { - this.options.path = path; - return this; - } - - build() { - const apis = [...this.options.apis]; - const entityName = { - namespace: - this.options.entity?.metadata?.namespace || - defaultEntity.metadata.namespace, - kind: this.options.entity?.kind || defaultEntity.kind, - name: this.options.entity?.metadata?.name || defaultEntity.metadata.name, - }; - - const techDocsMetadata: AsyncState = { - loading: false, - error: undefined, - value: (this.options.metadata || { - ...defaultMetadata, - }) as TechDocsMetadata, - }; - - const entityMetadata: AsyncState = { - loading: false, - error: undefined, - value: (this.options.entity || { - ...defaultEntity, - }) as TechDocsEntityMetadata, - }; - - const dom = document.createElement('html'); - dom.innerHTML = renderToStaticMarkup(this.options.dom || defaultDom); - useTechDocsReaderDom.mockReturnValue(dom); - // todo(backstage/techdocs-core): Use core test-utils' `routeEntries` option to mock - // the current path. We use jest mocks instead for now because of a bug in - // react-router that prevents '*' params from being mocked. - useParams.mockReturnValue({ - ...entityName, - '*': this.options.path, - }); - - return wrapInTestApp( - - - - } - > - - {this.addons.map((addon, index) => ( - {addon} - ))} - - - - , - ); - } - - render(): typeof screen & { shadowRoot: ShadowRoot | null } { - render(this.build()); - - const shadowHost = screen.getByTestId('techdocs-native-shadowroot'); - - return { - ...screen, - shadowRoot: shadowHost?.shadowRoot, - }; - } - - // Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async - // act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit - // cleaner, since act doesn't return the result of the evaluated function. - // https://github.com/testing-library/react-testing-library/issues/281 - // https://github.com/facebook/react/pull/14853 - async renderWithEffects(): Promise< - ReturnType - > { - await act(async () => { - this.render(); - }); - - const shadowHost = screen.getByTestId('techdocs-native-shadowroot'); - - return { - ...screen, - shadowRoot: shadowHost?.shadowRoot, - }; - } -} - -export default TechDocsAddonBuilder.buildAddonsInTechDocs; diff --git a/plugins/techdocs-addons/src/types.ts b/plugins/techdocs-addons/src/types.ts deleted file mode 100644 index d8ab7e9520..0000000000 --- a/plugins/techdocs-addons/src/types.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2022 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 { Entity } from '@backstage/catalog-model'; -import { ComponentType } from 'react'; -import { AsyncState } from 'react-use/lib/useAsyncFn'; - -/** - * Locations for which TechDocs addons may be declared and rendered. - * @public - */ -export enum TechDocsAddonLocations { - /** - * These addons fill up the header from the right, on the same line as the - * title. - */ - HEADER = 'header', - - /** - * These addons appear below the header and above all content; tooling addons - * can be inserted for convenience. - */ - SUBHEADER = 'subheader', - - /** - * These addons appear left of the content and above the navigation. - */ - PRIMARY_SIDEBAR = 'primary sidebar', - - /** - * These addons appear right of the content and above the table of contents. - */ - SECONDARY_SIDEBAR = 'secondary sidebar', - - /** - * A virtual location which allows mutation of all content within the shadow - * root by transforming DOM nodes. These addons should return null on render. - */ - CONTENT = 'content', - - /** - * A virtual location allowing an instance of the addon to be rendered for - * every HTML node with the same tag name as the addon name in the markdown - * content. If no reference is made, no instance will be rendered. Works like - * regular React components, just being accessible from markdown. - * - * todo(backstage/techdocs-core): Keep and implement or remove before - * releasing this package! - */ - COMPONENT = 'component', -} - -/** - * Options for creating a TechDocs addon. - * @public - */ -export type TechDocsAddonOptions = { - name: string; - location: TechDocsAddonLocations; - component: ComponentType; -}; - -/** - * Common response envelope for addon-related hooks. - * @public - */ -export type TechDocsAddonAsyncMetadata = AsyncState; - -/** - * Metadata for TechDocs page - * - * @public - */ -export type TechDocsMetadata = { - site_name: string; - site_description: string; -}; - -/** - * Metadata for TechDocs Entity - * - * @public - */ -export type TechDocsEntityMetadata = Entity & { - locationMetadata?: { type: string; target: string }; -};