diff --git a/.changeset/techdocs-hold-me-closer.md b/.changeset/techdocs-hold-me-closer.md new file mode 100644 index 0000000000..2295603388 --- /dev/null +++ b/.changeset/techdocs-hold-me-closer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-addons': minor +--- + +Introducing an addon framework for TechDocs. diff --git a/plugins/techdocs-addons/api-report.md b/plugins/techdocs-addons/api-report.md index f3b3d5fe69..c5a61a34e3 100644 --- a/plugins/techdocs-addons/api-report.md +++ b/plugins/techdocs-addons/api-report.md @@ -3,9 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + import { ComponentType } from 'react'; +import { CompoundEntityRef } from '@backstage/catalog-model'; import { Extension } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; +import { TechDocsEntityMetadata } from '@backstage/plugin-techdocs'; +import { TechDocsMetadata } from '@backstage/plugin-techdocs'; // @public export function createTechDocsAddon( @@ -31,4 +36,28 @@ export type TechDocsAddonOptions = { // @public export const TechDocsAddons: React_2.ComponentType; + +// @public +export const TechDocsReaderPage: ( + props: TechDocsReaderPageProps, +) => JSX.Element; + +// @public (undocumented) +export type TechDocsReaderPageProps = { + entityName: CompoundEntityRef; +}; + +// @public +export const useEntityMetadata: () => TechDocsEntityMetadata | undefined; + +// @public +export const useMetadata: () => TechDocsMetadata | undefined; + +// @public +export const useShadowRoot: () => ShadowRoot | undefined; + +// @public +export const useShadowRootElements: ( + selectors: string[], +) => T[]; ``` diff --git a/plugins/techdocs-addons/package.json b/plugins/techdocs-addons/package.json index 79da76e32a..3eb29ea77a 100644 --- a/plugins/techdocs-addons/package.json +++ b/plugins/techdocs-addons/package.json @@ -22,8 +22,17 @@ "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", - "react-router-dom": "6.0.0-beta.0" + "@backstage/plugin-techdocs": "^0.15.1", + "@material-ui/core": "^4.12.2", + "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/styles": "^4.11.0", + "jss": "~10.8.2", + "react-helmet": "6.1.0", + "react-router-dom": "6.0.0-beta.0", + "react-use": "^17.2.4" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/techdocs-addons/src/context.tsx b/plugins/techdocs-addons/src/context.tsx new file mode 100644 index 0000000000..7908033874 --- /dev/null +++ b/plugins/techdocs-addons/src/context.tsx @@ -0,0 +1,193 @@ +/* + * 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 { useApi, useApp } from '@backstage/core-plugin-api'; +import { + techdocsApiRef, + TechDocsEntityMetadata, + TechDocsMetadata, +} from '@backstage/plugin-techdocs'; +import React, { + createContext, + Dispatch, + PropsWithChildren, + SetStateAction, + useContext, + useState, +} from 'react'; +import useAsync from 'react-use/lib/useAsync'; + +type PropsWithEntityName = PropsWithChildren<{ entityName: CompoundEntityRef }>; + +const TechDocsMetadataContext = createContext( + undefined, +); + +export const TechDocsMetadataProvider = ({ + entityName, + children, +}: PropsWithEntityName) => { + const { NotFoundErrorPage } = useApp().getComponents(); + const techdocsApi = useApi(techdocsApiRef); + + const { value, loading, error } = useAsync(async () => { + return await techdocsApi.getTechDocsMetadata(entityName); + }, []); + + if (!loading && error) { + return ; + } + + return ( + + {children} + + ); +}; + +/** + * Hook for use within TechDocs addons to retrieve TechDocs Metadata for the + * current TechDocs site. + * @public + */ +export const useMetadata = () => { + return useContext(TechDocsMetadataContext); +}; + +const TechDocsEntityContext = createContext( + undefined, +); + +export const TechDocsEntityProvider = ({ + entityName, + children, +}: PropsWithEntityName) => { + const { NotFoundErrorPage } = useApp().getComponents(); + const techdocsApi = useApi(techdocsApiRef); + + const { value, loading, error } = useAsync(async () => { + return await techdocsApi.getEntityMetadata(entityName); + }, []); + + if (!loading && error) { + return ; + } + + 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} + + ); +}; + +/** + * 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 = ( + selectors: string[], +): T[] => { + 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 index ba9f2a7266..43802de14f 100644 --- a/plugins/techdocs-addons/src/index.ts +++ b/plugins/techdocs-addons/src/index.ts @@ -21,4 +21,12 @@ */ export { createTechDocsAddon, TechDocsAddons } from './addons'; +export { + useEntityMetadata, + useMetadata, + useShadowRoot, + useShadowRootElements, +} from './context'; +export { TechDocsReaderPage } from './reader'; +export type { TechDocsReaderPageProps } from './reader'; export type { TechDocsAddonLocations, TechDocsAddonOptions } from './types'; diff --git a/plugins/techdocs-addons/src/reader.tsx b/plugins/techdocs-addons/src/reader.tsx new file mode 100644 index 0000000000..f7f2407d46 --- /dev/null +++ b/plugins/techdocs-addons/src/reader.tsx @@ -0,0 +1,217 @@ +/* + * 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 { Content, Header, Page, Progress } from '@backstage/core-components'; +import { configApiRef, useApi } from '@backstage/core-plugin-api'; +// todo(backstage/techdocs-core): Export these from @backstage/plugin-techdocs +import { + // @ts-ignore + useTechDocsReaderDom, + // @ts-ignore + withTechDocsReaderProvider, + // @ts-ignore + TechDocsStateIndicator as TechDocReaderPageIndicator, +} from '@backstage/plugin-techdocs'; +import { + withStyles, + Portal, + Box, + Toolbar, + ToolbarProps, +} from '@material-ui/core'; +import { Skeleton } from '@material-ui/lab'; +import { StylesProvider, jssPreset } from '@material-ui/styles'; +import React, { useEffect, useRef, useState } from 'react'; +import { create } from 'jss'; +import Helmet from 'react-helmet'; + +import { useTechDocsAddons } from './addons'; +import { + TechDocsMetadataProvider, + useMetadata, + TechDocsEntityProvider, + TechDocsReaderPageProvider, + useTechDocsReaderPage, +} from './context'; +import { TechDocsAddonLocations as locations } from './types'; + +const TechDocsReaderPageSubheader = withStyles(theme => ({ + root: { + gridArea: 'pageSubheader', + flexDirection: 'column', + minHeight: 'auto', + padding: theme.spacing(3, 3, 0), + }, +}))(({ ...rest }: ToolbarProps) => { + const addons = useTechDocsAddons(); + + if (!addons.renderComponentsWithLocation(locations.SUBHEADER)) return null; + + return ( + + {addons.renderComponentsWithLocation(locations.SUBHEADER) && ( + + {addons.renderComponentsWithLocation(locations.SUBHEADER)} + + )} + + ); +}); + +const skeleton = ; + +const TechDocsReaderPageHeader = () => { + const addons = useTechDocsAddons(); + const configApi = useApi(configApiRef); + + const metadata = useMetadata(); + + 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.renderComponentsWithLocation(locations.HEADER)} +
+ ); +}; + +const TechDocsReaderPageContent = () => { + const ref = useRef(null); + const [jss, setJss] = useState( + create({ + ...jssPreset(), + insertionPoint: undefined, + }), + ); + + const addons = useTechDocsAddons(); + const { entityName, setShadowRoot } = useTechDocsReaderPage(); + const dom = useTechDocsReaderDom(entityName); + + 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( + '[data-md-component="navigation"]', + ); + const secondarySidebarElement = ref.current?.shadowRoot?.querySelector( + '[data-md-component="toc"]', + ); + + const primarySidebarAddonSpace = document.createElement('div'); + primarySidebarElement?.prepend(primarySidebarAddonSpace); + + const secondarySidebarAddonSpace = document.createElement('div'); + secondarySidebarElement?.prepend(secondarySidebarAddonSpace); + + // 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.renderComponentsWithLocation(locations.PRIMARY_SIDEBAR)} + + + {addons.renderComponentsWithLocation(locations.CONTENT)} + + + {addons.renderComponentsWithLocation(locations.SECONDARY_SIDEBAR)} + + + + ); +}; + +/** + * @public + */ +export type TechDocsReaderPageProps = { entityName: CompoundEntityRef }; + +/** + * An addon-aware implementation of the TechDocsReaderPage. + * @public + */ +export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { + const { entityName } = props; + const Component = withTechDocsReaderProvider(() => { + return ( + + + + + + + + + + + + + ); + }, entityName); + return ; +}; diff --git a/plugins/techdocs-addons/src/types.ts b/plugins/techdocs-addons/src/types.ts index 584d2229b3..9cb095577f 100644 --- a/plugins/techdocs-addons/src/types.ts +++ b/plugins/techdocs-addons/src/types.ts @@ -54,6 +54,9 @@ export enum TechDocsAddonLocations { * 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', } diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 8516c09783..d0ef75e32c 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -72,6 +72,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^7.0.2", "@testing-library/user-event": "^14.0.0", + "@types/event-source-polyfill": "^1.0.0", "@types/dompurify": "^2.2.2", "@types/jest": "^26.0.7", "@types/node": "^16.11.26", diff --git a/yarn.lock b/yarn.lock index 37046a1f16..3cfe0b84fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1456,6 +1456,15 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@backstage/catalog-client@^0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@backstage/catalog-client/-/catalog-client-0.9.0.tgz#3e1024fab13fd8e2000d33833d2463ea9be5df9d" + integrity sha1-PhAk+rE/2OIADTODPSRj6pvl350= + dependencies: + "@backstage/catalog-model" "^0.13.0" + "@backstage/errors" "^0.2.2" + cross-fetch "^3.1.5" + "@backstage/catalog-client@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/catalog-client/-/catalog-client-1.0.0.tgz#05f9ee3b771ca17e4800f5116d63bd183fe0c4d6" @@ -1465,6 +1474,19 @@ "@backstage/errors" "^1.0.0" cross-fetch "^3.1.5" +"@backstage/catalog-model@^0.13.0": + version "0.13.0" + resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-0.13.0.tgz#abeb91522ac7ef7907907ad5bc889803131db209" + integrity sha1-q+uRUirH73kHkHrVvIiYAxMdsgk= + dependencies: + "@backstage/config" "^0.1.15" + "@backstage/errors" "^0.2.2" + "@backstage/types" "^0.1.3" + ajv "^7.0.3" + json-schema "^0.4.0" + lodash "^4.17.21" + uuid "^8.0.0" + "@backstage/catalog-model@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/catalog-model/-/catalog-model-1.0.0.tgz#0aa8694a3182aaf4232725842da751bf5f78bd68" @@ -1478,7 +1500,15 @@ lodash "^4.17.21" uuid "^8.0.0" -"@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.2": +"@backstage/config@^0.1.15": + version "0.1.15" + resolved "https://registry.npmjs.org/@backstage/config/-/config-0.1.15.tgz#4bad122ad861be5bd61a60639f92d2494fa245c5" + integrity sha512-eNJEYYSEu9MkrkBYiMpUBWEc3Bu64YgB9pZZGCMW7/9350tV2wbylEdoBJHslilJlJhiUyTXBckn8Ua7DOH7rw== + dependencies: + "@backstage/types" "^0.1.3" + lodash "^4.17.21" + +"@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.1", "@backstage/core-components@^0.9.2": version "0.9.2" resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.2.tgz#9a3d79a15039256bbc007e5daa08c983050e0238" integrity sha512-kh0FB0FmjC55W+xSEkKrAc7D6hvbYLY7N1UUd6M4VBghYXD61Y8RrJFKmBM3bAfPgYaryQNjYgA0BsoTo53PJA== @@ -1522,6 +1552,43 @@ zen-observable "^0.8.15" zod "^3.11.6" +"@backstage/core-plugin-api@^0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-0.8.0.tgz#e2096bff679183168a7f9b47ed27c50a01970e32" + integrity sha1-4glr/2eRgxaKf5tH7SfFCgGXDjI= + dependencies: + "@backstage/config" "^0.1.15" + "@backstage/types" "^0.1.3" + "@backstage/version-bridge" "^0.1.2" + history "^5.0.0" + prop-types "^15.7.2" + react-router-dom "6.0.0-beta.0" + zen-observable "^0.8.15" + +"@backstage/errors@^0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@backstage/errors/-/errors-0.2.2.tgz#2113e0bc859e645b8b59bfcb435f7535739b02f8" + integrity sha1-IRPgvIWeZFuLWb/LQ191NXObAvg= + dependencies: + "@backstage/types" "^0.1.3" + cross-fetch "^3.1.5" + serialize-error "^8.0.1" + +"@backstage/integration-react@^0.1.25": + version "0.1.25" + resolved "https://registry.npmjs.org/@backstage/integration-react/-/integration-react-0.1.25.tgz#ebbdd30d66e1d210b7cd33a682ad2be0d5ea5fc0" + integrity sha1-673TDWbh0hC3zTOmgq0r4NXqX8A= + dependencies: + "@backstage/config" "^0.1.15" + "@backstage/core-components" "^0.9.1" + "@backstage/core-plugin-api" "^0.8.0" + "@backstage/integration" "^0.8.0" + "@backstage/theme" "^0.2.15" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + react-use "^17.2.4" + "@backstage/integration-react@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/integration-react/-/integration-react-1.0.0.tgz#8075e65c6b5387631d27a9c242e7a4fff6f92417" @@ -1537,6 +1604,19 @@ "@material-ui/lab" "4.0.0-alpha.57" react-use "^17.2.4" +"@backstage/integration@^0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@backstage/integration/-/integration-0.8.0.tgz#d74131ad347272b4935973aa4bd098fad9548ce6" + integrity sha1-10ExrTRycrSTWXOqS9CY+tlUjOY= + dependencies: + "@backstage/config" "^0.1.15" + "@octokit/auth-app" "^3.4.0" + "@octokit/rest" "^18.5.3" + cross-fetch "^3.1.5" + git-url-parse "^11.6.0" + lodash "^4.17.21" + luxon "^2.0.2" + "@backstage/integration@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/integration/-/integration-1.0.0.tgz#e307cfddea014bfb0eb2281a5ae25ea0b742e9cf" @@ -1550,6 +1630,41 @@ lodash "^4.17.21" luxon "^2.0.2" +"@backstage/plugin-catalog-common@^0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-common/-/plugin-catalog-common-0.2.2.tgz#2f039ecd829d1d8e017609cb0bbf9af7c231ab63" + integrity sha1-LwOezYKdHY4BdgnLC7+a98Ixq2M= + dependencies: + "@backstage/plugin-permission-common" "^0.5.2" + "@backstage/search-common" "^0.3.1" + +"@backstage/plugin-catalog-react@^0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-0.9.0.tgz#ff8c09ec455655fadb2c2fafd578908138b858bc" + integrity sha1-/4wJ7EVWVfrbLC+v1XiQgTi4WLw= + dependencies: + "@backstage/catalog-client" "^0.9.0" + "@backstage/catalog-model" "^0.13.0" + "@backstage/core-components" "^0.9.1" + "@backstage/core-plugin-api" "^0.8.0" + "@backstage/errors" "^0.2.2" + "@backstage/integration" "^0.8.0" + "@backstage/plugin-permission-common" "^0.5.2" + "@backstage/plugin-permission-react" "^0.3.3" + "@backstage/types" "^0.1.3" + "@backstage/version-bridge" "^0.1.2" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + classnames "^2.2.6" + jwt-decode "^3.1.0" + lodash "^4.17.21" + qs "^6.9.4" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + yaml "^1.10.0" + zen-observable "^0.8.15" + "@backstage/plugin-catalog-react@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-1.0.0.tgz#4f42c070ffe5c9690e45a5288e18bacd8d4e0e66" @@ -1578,7 +1693,33 @@ yaml "^1.10.0" zen-observable "^0.8.15" -"@backstage/plugin-permission-common@^0.5.3": +"@backstage/plugin-catalog@^0.10.0": + version "0.10.0" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-0.10.0.tgz#7b7f1b54704380c51f7506bfba948a3e0ff0575d" + integrity sha1-e38bVHBDgMUfdQa/upSKPg/wV10= + dependencies: + "@backstage/catalog-client" "^0.9.0" + "@backstage/catalog-model" "^0.13.0" + "@backstage/core-components" "^0.9.1" + "@backstage/core-plugin-api" "^0.8.0" + "@backstage/errors" "^0.2.2" + "@backstage/integration-react" "^0.1.25" + "@backstage/plugin-catalog-common" "^0.2.2" + "@backstage/plugin-catalog-react" "^0.9.0" + "@backstage/plugin-search-common" "^0.3.1" + "@backstage/theme" "^0.2.15" + "@backstage/types" "^0.1.2" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + history "^5.0.0" + lodash "^4.17.21" + react-helmet "6.1.0" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + +"@backstage/plugin-permission-common@^0.5.2", "@backstage/plugin-permission-common@^0.5.3": version "0.5.3" resolved "https://registry.npmjs.org/@backstage/plugin-permission-common/-/plugin-permission-common-0.5.3.tgz#a1a4446e603584f2c82763745051f75f4a942eb1" integrity sha512-zppDsNZEK9ffgXbf/Zx0sw4ffuOVOEvBZlft1+Oph2rO4+uN7dmCLMRRcKsYeNQ6/F50e6BMyNWpPZQDR/JQsA== @@ -1589,7 +1730,7 @@ uuid "^8.0.0" zod "^3.11.6" -"@backstage/plugin-permission-react@^0.3.4": +"@backstage/plugin-permission-react@^0.3.3", "@backstage/plugin-permission-react@^0.3.4": version "0.3.4" resolved "https://registry.npmjs.org/@backstage/plugin-permission-react/-/plugin-permission-react-0.3.4.tgz#e769dc1489c35d9c924234c0764a584558891716" integrity sha512-S8s1cvCZFmxP4Dn5V9fOls31s4V1rgx3YUXqHSkgLatYHOXczf+GM/c5rdGLQyOb/+Hb+MQqaPAkojvSxNliow== @@ -1602,6 +1743,83 @@ react-use "^17.2.4" swr "^1.1.2" +"@backstage/plugin-search-common@0.3.2", "@backstage/plugin-search-common@^0.3.1", "@backstage/plugin-search-common@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@backstage/plugin-search-common/-/plugin-search-common-0.3.2.tgz#15984ba4c14f8a9119168e8c79344ef8101863dc" + integrity sha1-FZhLpMFPipEZFo6MeTRO+BAYY9w= + dependencies: + "@backstage/plugin-permission-common" "^0.5.3" + "@backstage/types" "^1.0.0" + +"@backstage/plugin-search@^0.7.3": + version "0.7.4" + resolved "https://registry.npmjs.org/@backstage/plugin-search/-/plugin-search-0.7.4.tgz#d6571da128342d122f80253a756ece0a702967f9" + integrity sha1-1lcdoSg0LRIvgCU6dW7OCnApZ/k= + dependencies: + "@backstage/catalog-model" "^1.0.0" + "@backstage/config" "^1.0.0" + "@backstage/core-components" "^0.9.2" + "@backstage/core-plugin-api" "^1.0.0" + "@backstage/errors" "^1.0.0" + "@backstage/plugin-catalog-react" "^1.0.0" + "@backstage/plugin-search-common" "^0.3.2" + "@backstage/theme" "^0.2.15" + "@backstage/types" "^1.0.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + qs "^6.9.4" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-text-truncate "^0.18.0" + react-use "^17.2.4" + +"@backstage/plugin-techdocs@^0.15.1": + version "0.15.1" + resolved "https://registry.npmjs.org/@backstage/plugin-techdocs/-/plugin-techdocs-0.15.1.tgz#f57b63526976da04f1d926b5b5b50e1a89b29184" + integrity sha1-9XtjUml22gTx2Sa1tbUOGomykYQ= + dependencies: + "@backstage/catalog-model" "^0.13.0" + "@backstage/config" "^0.1.15" + "@backstage/core-components" "^0.9.1" + "@backstage/core-plugin-api" "^0.8.0" + "@backstage/errors" "^0.2.2" + "@backstage/integration" "^0.8.0" + "@backstage/integration-react" "^0.1.25" + "@backstage/plugin-catalog" "^0.10.0" + "@backstage/plugin-catalog-react" "^0.9.0" + "@backstage/plugin-search" "^0.7.3" + "@backstage/theme" "^0.2.15" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + "@material-ui/styles" "^4.10.0" + dompurify "^2.2.9" + event-source-polyfill "^1.0.25" + git-url-parse "^11.6.0" + lodash "^4.17.21" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-text-truncate "^0.18.0" + react-use "^17.2.4" + +"@backstage/search-common@^0.3.1": + version "0.3.2" + resolved "https://registry.npmjs.org/@backstage/search-common/-/search-common-0.3.2.tgz#608a4eddf7eae71ed807ec1f723a80c6f7cdf3e4" + integrity sha1-YIpO3ffq5x7YB+wfcjqAxvfN8+Q= + dependencies: + "@backstage/plugin-search-common" "0.3.2" + +"@backstage/types@^0.1.2", "@backstage/types@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@backstage/types/-/types-0.1.3.tgz#6613d8cbdf97d42d31cd1e66a833df533e7ccf14" + integrity sha512-fJVi4oVrlO+G3PRv1fYSll9/X4pE11HLnkI//Geare9sP6wSfp/2zXpLYfKVsG0e24jOl7Swkc8lwLkQ90zMaQ== + +"@backstage/version-bridge@^0.1.2": + version "0.1.2" + resolved "https://registry.npmjs.org/@backstage/version-bridge/-/version-bridge-0.1.2.tgz#a24f42e0f383d497576f8c9d43851c6538345c03" + integrity sha1-ok9C4POD1JdXb4ydQ4UcZTg0XAM= + "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -6022,6 +6240,11 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/event-source-polyfill@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@types/event-source-polyfill/-/event-source-polyfill-1.0.0.tgz#f93f13433f750c8ea0e3cfa69c72e3c7393e0585" + integrity sha512-b8O8/rg7NIW0iJ8i9MNDBZqPljHA+b7AjC3QFqH3dSyW6vgrl3oBgyIv5dw2fibh5enHHDkkPZG5PHza7U4NRw== + "@types/expect@^1.20.4": version "1.20.4" resolved "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" @@ -7857,7 +8080,7 @@ array-ify@^1.0.0: resolved "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-includes@^3.1.3, array-includes@^3.1.4: +array-includes@^3.1.2, array-includes@^3.1.3, array-includes@^3.1.4: version "3.1.4" resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== @@ -12111,6 +12334,11 @@ event-source-polyfill@1.0.25: resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.25.tgz#d8bb7f99cb6f8119c2baf086d9f6ee0514b6d9c8" integrity sha512-hQxu6sN1Eq4JjoI7ITdQeGGUN193A2ra83qC0Ltm9I2UJVAten3OFVN6k5RX4YWeCS0BoC8xg/5czOCIHVosQg== +event-source-polyfill@^1.0.25: + version "1.0.26" + resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.26.tgz#86c04d088ef078279168eefa028f928fec5059a4" + integrity sha512-IwDLs9fUTcGAyacHBeS53T8wcEkDyDn0UP4tfQqJ4wQP8AyH0mszuQf2ULTylnpI0sMquzJ4usrNV7+uztwI9A== + event-stream@=3.3.4: version "3.3.4" resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -16221,7 +16449,25 @@ jss@10.6.0, jss@^10.5.1: is-in-browser "^1.1.3" tiny-warning "^1.0.2" -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: +jss@~10.8.2: + version "10.8.2" + resolved "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz#4b2a30b094b924629a64928236017a52c7c97505" + integrity sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ== + dependencies: + "@babel/runtime" "^7.3.1" + csstype "^3.0.2" + is-in-browser "^1.1.3" + tiny-warning "^1.0.2" + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.2.0" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" + integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== + dependencies: + array-includes "^3.1.2" + object.assign "^4.1.2" + +jsx-ast-utils@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==