diff --git a/.changeset/techdocs-hold-me-closer.md b/.changeset/techdocs-hold-me-closer.md
index 2295603388..04bbf5088f 100644
--- a/.changeset/techdocs-hold-me-closer.md
+++ b/.changeset/techdocs-hold-me-closer.md
@@ -1,5 +1,7 @@
---
-'@backstage/plugin-techdocs-addons': minor
+'@backstage/techdocs-addons': minor
---
-Introducing an addon framework for TechDocs.
+Introducing `@backstage/techdocs-addons`, a web library you can use to create TechDocs addons.
+
+Note: this package is not necessarily stable yet. After iteration on this package, its stability will be signaled by a major-version bump.
diff --git a/.changeset/techdocs-swift-apricots-learn.md b/.changeset/techdocs-swift-apricots-learn.md
deleted file mode 100644
index 70d21b3535..0000000000
--- a/.changeset/techdocs-swift-apricots-learn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-techdocs-addons': patch
----
-
-Separation between contexts and hooks
diff --git a/.changeset/techdocs-until-you-puke.md b/.changeset/techdocs-until-you-puke.md
index af70fe315b..74578b1067 100644
--- a/.changeset/techdocs-until-you-puke.md
+++ b/.changeset/techdocs-until-you-puke.md
@@ -2,15 +2,14 @@
'@backstage/plugin-techdocs': minor
---
-TechDocs now supports a new method of customization: addons!
+TechDocs supports a new, experimental method of customization: addons!
To customize the standalone TechDocs reader page experience, update your `/packages/app/src/App.tsx` in the following way:
```diff
import { TechDocsIndexPage, TechDocsReaderPage } from '@backstage/plugin-techdocs';
-+ import { TechDocsAddons } from '@backstage/plugin-techdocs-addons';
++ import { TechDocsAddons } from '@backstage/techdocs-addons';
+ import { SomeAddon } from '@backstage/plugin-some-plugin';
-- import { techDocsPage } from './components/techdocs/TechDocsPage';
// ...
@@ -19,7 +18,6 @@ import { TechDocsIndexPage, TechDocsReaderPage } from '@backstage/plugin-techdoc
path="/docs/:namespace/:kind/:name/*"
element={}
>
-- {techDocsPage}
+
+
+
@@ -32,7 +30,7 @@ To customize the TechDocs reader experience on the Catalog entity page, update y
```diff
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
-+ import { TechDocsAddons } from '@backstage/plugin-techdocs-addons';
++ import { TechDocsAddons } from '@backstage/techdocs-addons';
+ import { SomeAddon } from '@backstage/plugin-some-plugin';
// ...
diff --git a/cypress/fixtures/mkdocs.yml b/cypress/fixtures/mkdocs.yml
index 2362fab898..071d147509 100644
--- a/cypress/fixtures/mkdocs.yml
+++ b/cypress/fixtures/mkdocs.yml
@@ -1,5 +1,8 @@
site_name: e2e Fixture Documentation
site_description: Documentation used for end-to-end tests of TechDocs in Backstage.
+repo_url: https://github.com/backstage/backstage
+edit_uri: edit/master/cypress/fixtures/docs
+
nav:
- Home: index.md
- Sub-page 1: sub-page-one.md
diff --git a/mkdocs.yml b/mkdocs.yml
index 204a4768c3..5c73516ba6 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,5 +1,7 @@
site_name: 'Backstage'
site_description: 'Main documentation for Backstage features and platform APIs'
+repo_url: https://github.com/backstage/backstage
+edit_uri: edit/master/docs
plugins:
- techdocs-core
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 51012b042a..6a2fb7e0f6 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -68,6 +68,7 @@ import {
TechDocsIndexPage,
TechDocsReaderPage,
techdocsPlugin,
+ GiveFeedbackAddon,
} from '@backstage/plugin-techdocs';
import {
UserSettingsPage,
@@ -93,13 +94,6 @@ import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
import { PermissionedRoute } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
-import {
- ExampleContent,
- ExampleHeader,
- ExamplePrimarySidebar,
- ExampleSecondarySidebar,
- ExampleSubHeader,
-} from './components/techdocs/ExampleAddons';
const app = createApp({
apis,
@@ -188,11 +182,7 @@ const routes = (
>
{techDocsPage}
-
-
-
-
-
+
-
-
-
-
-
+
@@ -482,11 +474,7 @@ const websiteEntityPage = (
-
-
-
-
-
+
@@ -529,11 +517,7 @@ const defaultEntityPage = (
-
-
-
-
-
+
diff --git a/packages/app/src/components/techdocs/ExampleAddons.tsx b/packages/app/src/components/techdocs/ExampleAddons.tsx
deleted file mode 100644
index 7b5fdba80c..0000000000
--- a/packages/app/src/components/techdocs/ExampleAddons.tsx
+++ /dev/null
@@ -1,108 +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, { useEffect } from 'react';
-
-import { Card, CardContent } from '@material-ui/core';
-
-import {
- techdocsPlugin,
- useShadowRootElements,
-} from '@backstage/plugin-techdocs';
-import {
- createTechDocsAddon,
- TechDocsAddonLocations,
-} from '@backstage/techdocs-addons';
-import { HeaderLabel } from '@backstage/core-components';
-
-/**
- * Note: this is not typically how or where one might define such things. It
- * would more typically be exported/provided by a plugin!
- *
- * In fact, this whole file and usage should be deleted before we merge things
- * in. This is just a convenient way to test the addon framework in a nice
- * end-to-end way before releasing anything.
- */
-
-export const ExampleHeader = techdocsPlugin.provide(
- createTechDocsAddon({
- name: 'ExampleHeader',
- location: TechDocsAddonLocations.HEADER,
- component: () => {
- return ;
- },
- }),
-);
-
-export const ExampleSubHeader = techdocsPlugin.provide(
- createTechDocsAddon({
- name: 'ExampleSubHeader',
- location: TechDocsAddonLocations.SUBHEADER,
- component: () => {
- return (
-
- Subheader.
-
- );
- },
- }),
-);
-
-export const ExamplePrimarySidebar = techdocsPlugin.provide(
- createTechDocsAddon({
- name: 'ExamplePrimarySidebar',
- location: TechDocsAddonLocations.PRIMARY_SIDEBAR,
- component: () => {
- return (
-
- Primary Sidebar.
-
- );
- },
- }),
-);
-
-export const ExampleSecondarySidebar = techdocsPlugin.provide(
- createTechDocsAddon({
- name: 'ExampleSecondarySidebar',
- location: TechDocsAddonLocations.SECONDARY_SIDEBAR,
- component: () => {
- return (
-
- Secondary Sidebar.
-
- );
- },
- }),
-);
-
-const ExampleContentComponent = () => {
- const h1 = useShadowRootElements(['h1'])[0];
- useEffect(() => {
- if (h1 && !h1.innerText.startsWith('Modified: ')) {
- h1.innerText = `Modified: ${h1.innerText}`;
- }
- }, [h1]);
- return null;
-};
-
-export const ExampleContent = techdocsPlugin.provide(
- createTechDocsAddon({
- name: 'ExampleContent',
- location: TechDocsAddonLocations.CONTENT,
- component: ExampleContentComponent,
- }),
-);
diff --git a/packages/app/src/components/techdocs/TechDocsPage.tsx b/packages/app/src/components/techdocs/TechDocsPage.tsx
index 89d0c74ad5..48a9812160 100644
--- a/packages/app/src/components/techdocs/TechDocsPage.tsx
+++ b/packages/app/src/components/techdocs/TechDocsPage.tsx
@@ -17,6 +17,7 @@
import {
TechDocsReaderPage,
TechDocsReaderPageHeader,
+ TechDocsReaderPageSubheader,
TechDocsReaderPageContent,
} from '@backstage/plugin-techdocs';
import React from 'react';
@@ -25,6 +26,7 @@ const DefaultTechDocsPage = () => {
return (
+
);
diff --git a/packages/techdocs-addons/api-report.md b/packages/techdocs-addons/api-report.md
index 4d5eef5edb..573361e5a7 100644
--- a/packages/techdocs-addons/api-report.md
+++ b/packages/techdocs-addons/api-report.md
@@ -3,23 +3,19 @@
> 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 { Extension } from '@backstage/core-plugin-api';
import { default as React_2 } from 'react';
-// @public
+// @alpha
export function createTechDocsAddon(
options: TechDocsAddonOptions,
): Extension>;
-// @public
+// @alpha
export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1';
-// @public
-export type TechDocsAddonAsyncMetadata = AsyncState;
-
-// @public
+// @alpha
export enum TechDocsAddonLocations {
CONTENT = 'content',
HEADER = 'header',
@@ -28,17 +24,17 @@ export enum TechDocsAddonLocations {
SUBHEADER = 'subheader',
}
-// @public
+// @alpha
export type TechDocsAddonOptions = {
name: string;
location: TechDocsAddonLocations;
component: ComponentType;
};
-// @public
+// @alpha
export const TechDocsAddons: React_2.ComponentType;
-// @public
+// @alpha
export const useTechDocsAddons: () => {
renderComponentByName: (name: string) => React_2.ReactElement<
{
diff --git a/packages/techdocs-addons/package.json b/packages/techdocs-addons/package.json
index c8ed12ec8b..5635c9c6fe 100644
--- a/packages/techdocs-addons/package.json
+++ b/packages/techdocs-addons/package.json
@@ -42,8 +42,7 @@
"@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"
+ "react-router-dom": "6.0.0-beta.0"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0",
diff --git a/packages/techdocs-addons/src/addons.tsx b/packages/techdocs-addons/src/addons.tsx
index 60fe13bfeb..8304319a88 100644
--- a/packages/techdocs-addons/src/addons.tsx
+++ b/packages/techdocs-addons/src/addons.tsx
@@ -31,13 +31,13 @@ export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1';
/**
* Marks the registry component.
- * @public
+ * @alpha
*/
export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1';
/**
* TechDocs Addon registry.
- * @public
+ * @alpha
*/
export const TechDocsAddons: React.ComponentType = () => null;
@@ -49,7 +49,7 @@ const getDataKeyByName = (name: string) => {
/**
* Create a TechDocs addon.
- * @public
+ * @alpha
*/
export function createTechDocsAddon(
options: TechDocsAddonOptions,
@@ -93,7 +93,7 @@ const getAllTechDocsAddonsData = (collection: ElementCollection) => {
/**
* hook to use addons in components
- * @public
+ * @alpha
*/
export const useTechDocsAddons = () => {
const node = useOutlet();
diff --git a/packages/techdocs-addons/src/index.ts b/packages/techdocs-addons/src/index.ts
index 2ef7265db3..240f7ffb6a 100644
--- a/packages/techdocs-addons/src/index.ts
+++ b/packages/techdocs-addons/src/index.ts
@@ -27,4 +27,4 @@ export {
TECHDOCS_ADDONS_WRAPPER_KEY,
} from './addons';
export { TechDocsAddonLocations } from './types';
-export type { TechDocsAddonAsyncMetadata, TechDocsAddonOptions } from './types';
+export type { TechDocsAddonOptions } from './types';
diff --git a/packages/techdocs-addons/src/types.ts b/packages/techdocs-addons/src/types.ts
index aa0d128427..9775e9a10e 100644
--- a/packages/techdocs-addons/src/types.ts
+++ b/packages/techdocs-addons/src/types.ts
@@ -15,11 +15,10 @@
*/
import { ComponentType } from 'react';
-import { AsyncState } from 'react-use/lib/useAsyncFn';
/**
* Locations for which TechDocs addons may be declared and rendered.
- * @public
+ * @alpha
*/
export enum TechDocsAddonLocations {
/**
@@ -79,16 +78,10 @@ export enum TechDocsAddonLocations {
/**
* Options for creating a TechDocs addon.
- * @public
+ * @alpha
*/
export type TechDocsAddonOptions = {
name: string;
location: TechDocsAddonLocations;
component: ComponentType;
};
-
-/**
- * Common response envelope for addon-related hooks.
- * @public
- */
-export type TechDocsAddonAsyncMetadata = AsyncState;
diff --git a/plugins/techdocs-backend/examples/documented-component/mkdocs.yml b/plugins/techdocs-backend/examples/documented-component/mkdocs.yml
index 2087979d22..1a159a4d12 100644
--- a/plugins/techdocs-backend/examples/documented-component/mkdocs.yml
+++ b/plugins/techdocs-backend/examples/documented-component/mkdocs.yml
@@ -1,4 +1,6 @@
site_name: 'Example Documentation'
+repo_url: https://github.com/backstage/backstage
+edit_uri: edit/master/plugins/techdocs-backend/examples/documented-component/docs
nav:
- Home: index.md
diff --git a/plugins/techdocs/api-report.md b/plugins/techdocs/api-report.md
index 0aeacde75c..2e9da8a931 100644
--- a/plugins/techdocs/api-report.md
+++ b/plugins/techdocs/api-report.md
@@ -8,6 +8,7 @@
import { ApiRef } from '@backstage/core-plugin-api';
import { AsyncState } from 'react-use/lib/useAsync';
import { BackstagePlugin } from '@backstage/core-plugin-api';
+import { CommonProps } from '@material-ui/core/OverridableComponent';
import { ComponentType } from 'react';
import { CompoundEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
@@ -22,8 +23,10 @@ import { default as React_2 } from 'react';
import { ReactNode } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { SetStateAction } from 'react';
+import { StyledComponentProps } from '@material-ui/core';
import { TableColumn } from '@backstage/core-components';
import { TableProps } from '@backstage/core-components';
+import { ToolbarTypeMap } from '@material-ui/core';
import { UserListFilterKind } from '@backstage/plugin-catalog-react';
// @public
@@ -395,6 +398,545 @@ export type TechDocsReaderPageRenderFunction = ({
onReady?: () => void;
}) => JSX.Element;
+// @public
+export const TechDocsReaderPageSubheader: React_2.ComponentType<
+ Pick<
+ {
+ disableGutters?: boolean | undefined;
+ variant?: 'dense' | 'regular' | undefined;
+ } & CommonProps> &
+ Pick<
+ Pick<
+ React_2.DetailedHTMLProps<
+ React_2.HTMLAttributes,
+ HTMLDivElement
+ >,
+ 'key' | keyof React_2.HTMLAttributes
+ > & {
+ ref?:
+ | ((instance: HTMLDivElement | null) => void)
+ | React_2.RefObject
+ | null
+ | undefined;
+ },
+ | 'key'
+ | 'id'
+ | 'color'
+ | 'translate'
+ | 'hidden'
+ | 'dir'
+ | 'slot'
+ | 'title'
+ | 'accessKey'
+ | 'draggable'
+ | 'lang'
+ | 'prefix'
+ | 'children'
+ | 'contentEditable'
+ | 'inputMode'
+ | 'tabIndex'
+ | 'ref'
+ | 'defaultChecked'
+ | 'defaultValue'
+ | 'suppressContentEditableWarning'
+ | 'suppressHydrationWarning'
+ | 'contextMenu'
+ | 'placeholder'
+ | 'spellCheck'
+ | 'radioGroup'
+ | 'role'
+ | 'about'
+ | 'datatype'
+ | 'inlist'
+ | 'property'
+ | 'resource'
+ | 'typeof'
+ | 'vocab'
+ | 'autoCapitalize'
+ | 'autoCorrect'
+ | 'autoSave'
+ | 'itemProp'
+ | 'itemScope'
+ | 'itemType'
+ | 'itemID'
+ | 'itemRef'
+ | 'results'
+ | 'security'
+ | 'unselectable'
+ | 'is'
+ | 'aria-activedescendant'
+ | 'aria-atomic'
+ | 'aria-autocomplete'
+ | 'aria-busy'
+ | 'aria-checked'
+ | 'aria-colcount'
+ | 'aria-colindex'
+ | 'aria-colspan'
+ | 'aria-controls'
+ | 'aria-current'
+ | 'aria-describedby'
+ | 'aria-details'
+ | 'aria-disabled'
+ | 'aria-dropeffect'
+ | 'aria-errormessage'
+ | 'aria-expanded'
+ | 'aria-flowto'
+ | 'aria-grabbed'
+ | 'aria-haspopup'
+ | 'aria-hidden'
+ | 'aria-invalid'
+ | 'aria-keyshortcuts'
+ | 'aria-label'
+ | 'aria-labelledby'
+ | 'aria-level'
+ | 'aria-live'
+ | 'aria-modal'
+ | 'aria-multiline'
+ | 'aria-multiselectable'
+ | 'aria-orientation'
+ | 'aria-owns'
+ | 'aria-placeholder'
+ | 'aria-posinset'
+ | 'aria-pressed'
+ | 'aria-readonly'
+ | 'aria-relevant'
+ | 'aria-required'
+ | 'aria-roledescription'
+ | 'aria-rowcount'
+ | 'aria-rowindex'
+ | 'aria-rowspan'
+ | 'aria-selected'
+ | 'aria-setsize'
+ | 'aria-sort'
+ | 'aria-valuemax'
+ | 'aria-valuemin'
+ | 'aria-valuenow'
+ | 'aria-valuetext'
+ | 'dangerouslySetInnerHTML'
+ | 'onCopy'
+ | 'onCopyCapture'
+ | 'onCut'
+ | 'onCutCapture'
+ | 'onPaste'
+ | 'onPasteCapture'
+ | 'onCompositionEnd'
+ | 'onCompositionEndCapture'
+ | 'onCompositionStart'
+ | 'onCompositionStartCapture'
+ | 'onCompositionUpdate'
+ | 'onCompositionUpdateCapture'
+ | 'onFocus'
+ | 'onFocusCapture'
+ | 'onBlur'
+ | 'onBlurCapture'
+ | 'onChange'
+ | 'onChangeCapture'
+ | 'onBeforeInput'
+ | 'onBeforeInputCapture'
+ | 'onInput'
+ | 'onInputCapture'
+ | 'onReset'
+ | 'onResetCapture'
+ | 'onSubmit'
+ | 'onSubmitCapture'
+ | 'onInvalid'
+ | 'onInvalidCapture'
+ | 'onLoad'
+ | 'onLoadCapture'
+ | 'onError'
+ | 'onErrorCapture'
+ | 'onKeyDown'
+ | 'onKeyDownCapture'
+ | 'onKeyPress'
+ | 'onKeyPressCapture'
+ | 'onKeyUp'
+ | 'onKeyUpCapture'
+ | 'onAbort'
+ | 'onAbortCapture'
+ | 'onCanPlay'
+ | 'onCanPlayCapture'
+ | 'onCanPlayThrough'
+ | 'onCanPlayThroughCapture'
+ | 'onDurationChange'
+ | 'onDurationChangeCapture'
+ | 'onEmptied'
+ | 'onEmptiedCapture'
+ | 'onEncrypted'
+ | 'onEncryptedCapture'
+ | 'onEnded'
+ | 'onEndedCapture'
+ | 'onLoadedData'
+ | 'onLoadedDataCapture'
+ | 'onLoadedMetadata'
+ | 'onLoadedMetadataCapture'
+ | 'onLoadStart'
+ | 'onLoadStartCapture'
+ | 'onPause'
+ | 'onPauseCapture'
+ | 'onPlay'
+ | 'onPlayCapture'
+ | 'onPlaying'
+ | 'onPlayingCapture'
+ | 'onProgress'
+ | 'onProgressCapture'
+ | 'onRateChange'
+ | 'onRateChangeCapture'
+ | 'onSeeked'
+ | 'onSeekedCapture'
+ | 'onSeeking'
+ | 'onSeekingCapture'
+ | 'onStalled'
+ | 'onStalledCapture'
+ | 'onSuspend'
+ | 'onSuspendCapture'
+ | 'onTimeUpdate'
+ | 'onTimeUpdateCapture'
+ | 'onVolumeChange'
+ | 'onVolumeChangeCapture'
+ | 'onWaiting'
+ | 'onWaitingCapture'
+ | 'onAuxClick'
+ | 'onAuxClickCapture'
+ | 'onClick'
+ | 'onClickCapture'
+ | 'onContextMenu'
+ | 'onContextMenuCapture'
+ | 'onDoubleClick'
+ | 'onDoubleClickCapture'
+ | 'onDrag'
+ | 'onDragCapture'
+ | 'onDragEnd'
+ | 'onDragEndCapture'
+ | 'onDragEnter'
+ | 'onDragEnterCapture'
+ | 'onDragExit'
+ | 'onDragExitCapture'
+ | 'onDragLeave'
+ | 'onDragLeaveCapture'
+ | 'onDragOver'
+ | 'onDragOverCapture'
+ | 'onDragStart'
+ | 'onDragStartCapture'
+ | 'onDrop'
+ | 'onDropCapture'
+ | 'onMouseDown'
+ | 'onMouseDownCapture'
+ | 'onMouseEnter'
+ | 'onMouseLeave'
+ | 'onMouseMove'
+ | 'onMouseMoveCapture'
+ | 'onMouseOut'
+ | 'onMouseOutCapture'
+ | 'onMouseOver'
+ | 'onMouseOverCapture'
+ | 'onMouseUp'
+ | 'onMouseUpCapture'
+ | 'onSelect'
+ | 'onSelectCapture'
+ | 'onTouchCancel'
+ | 'onTouchCancelCapture'
+ | 'onTouchEnd'
+ | 'onTouchEndCapture'
+ | 'onTouchMove'
+ | 'onTouchMoveCapture'
+ | 'onTouchStart'
+ | 'onTouchStartCapture'
+ | 'onPointerDown'
+ | 'onPointerDownCapture'
+ | 'onPointerMove'
+ | 'onPointerMoveCapture'
+ | 'onPointerUp'
+ | 'onPointerUpCapture'
+ | 'onPointerCancel'
+ | 'onPointerCancelCapture'
+ | 'onPointerEnter'
+ | 'onPointerEnterCapture'
+ | 'onPointerLeave'
+ | 'onPointerLeaveCapture'
+ | 'onPointerOver'
+ | 'onPointerOverCapture'
+ | 'onPointerOut'
+ | 'onPointerOutCapture'
+ | 'onGotPointerCapture'
+ | 'onGotPointerCaptureCapture'
+ | 'onLostPointerCapture'
+ | 'onLostPointerCaptureCapture'
+ | 'onScroll'
+ | 'onScrollCapture'
+ | 'onWheel'
+ | 'onWheelCapture'
+ | 'onAnimationStart'
+ | 'onAnimationStartCapture'
+ | 'onAnimationEnd'
+ | 'onAnimationEndCapture'
+ | 'onAnimationIteration'
+ | 'onAnimationIterationCapture'
+ | 'onTransitionEnd'
+ | 'onTransitionEndCapture'
+ >,
+ | 'key'
+ | 'id'
+ | 'color'
+ | 'translate'
+ | 'hidden'
+ | 'dir'
+ | 'slot'
+ | 'style'
+ | 'title'
+ | 'accessKey'
+ | 'draggable'
+ | 'lang'
+ | 'className'
+ | 'prefix'
+ | 'children'
+ | 'contentEditable'
+ | 'inputMode'
+ | 'tabIndex'
+ | 'ref'
+ | 'defaultChecked'
+ | 'defaultValue'
+ | 'suppressContentEditableWarning'
+ | 'suppressHydrationWarning'
+ | 'contextMenu'
+ | 'placeholder'
+ | 'spellCheck'
+ | 'radioGroup'
+ | 'role'
+ | 'about'
+ | 'datatype'
+ | 'inlist'
+ | 'property'
+ | 'resource'
+ | 'typeof'
+ | 'vocab'
+ | 'autoCapitalize'
+ | 'autoCorrect'
+ | 'autoSave'
+ | 'itemProp'
+ | 'itemScope'
+ | 'itemType'
+ | 'itemID'
+ | 'itemRef'
+ | 'results'
+ | 'security'
+ | 'unselectable'
+ | 'is'
+ | 'aria-activedescendant'
+ | 'aria-atomic'
+ | 'aria-autocomplete'
+ | 'aria-busy'
+ | 'aria-checked'
+ | 'aria-colcount'
+ | 'aria-colindex'
+ | 'aria-colspan'
+ | 'aria-controls'
+ | 'aria-current'
+ | 'aria-describedby'
+ | 'aria-details'
+ | 'aria-disabled'
+ | 'aria-dropeffect'
+ | 'aria-errormessage'
+ | 'aria-expanded'
+ | 'aria-flowto'
+ | 'aria-grabbed'
+ | 'aria-haspopup'
+ | 'aria-hidden'
+ | 'aria-invalid'
+ | 'aria-keyshortcuts'
+ | 'aria-label'
+ | 'aria-labelledby'
+ | 'aria-level'
+ | 'aria-live'
+ | 'aria-modal'
+ | 'aria-multiline'
+ | 'aria-multiselectable'
+ | 'aria-orientation'
+ | 'aria-owns'
+ | 'aria-placeholder'
+ | 'aria-posinset'
+ | 'aria-pressed'
+ | 'aria-readonly'
+ | 'aria-relevant'
+ | 'aria-required'
+ | 'aria-roledescription'
+ | 'aria-rowcount'
+ | 'aria-rowindex'
+ | 'aria-rowspan'
+ | 'aria-selected'
+ | 'aria-setsize'
+ | 'aria-sort'
+ | 'aria-valuemax'
+ | 'aria-valuemin'
+ | 'aria-valuenow'
+ | 'aria-valuetext'
+ | 'dangerouslySetInnerHTML'
+ | 'onCopy'
+ | 'onCopyCapture'
+ | 'onCut'
+ | 'onCutCapture'
+ | 'onPaste'
+ | 'onPasteCapture'
+ | 'onCompositionEnd'
+ | 'onCompositionEndCapture'
+ | 'onCompositionStart'
+ | 'onCompositionStartCapture'
+ | 'onCompositionUpdate'
+ | 'onCompositionUpdateCapture'
+ | 'onFocus'
+ | 'onFocusCapture'
+ | 'onBlur'
+ | 'onBlurCapture'
+ | 'onChange'
+ | 'onChangeCapture'
+ | 'onBeforeInput'
+ | 'onBeforeInputCapture'
+ | 'onInput'
+ | 'onInputCapture'
+ | 'onReset'
+ | 'onResetCapture'
+ | 'onSubmit'
+ | 'onSubmitCapture'
+ | 'onInvalid'
+ | 'onInvalidCapture'
+ | 'onLoad'
+ | 'onLoadCapture'
+ | 'onError'
+ | 'onErrorCapture'
+ | 'onKeyDown'
+ | 'onKeyDownCapture'
+ | 'onKeyPress'
+ | 'onKeyPressCapture'
+ | 'onKeyUp'
+ | 'onKeyUpCapture'
+ | 'onAbort'
+ | 'onAbortCapture'
+ | 'onCanPlay'
+ | 'onCanPlayCapture'
+ | 'onCanPlayThrough'
+ | 'onCanPlayThroughCapture'
+ | 'onDurationChange'
+ | 'onDurationChangeCapture'
+ | 'onEmptied'
+ | 'onEmptiedCapture'
+ | 'onEncrypted'
+ | 'onEncryptedCapture'
+ | 'onEnded'
+ | 'onEndedCapture'
+ | 'onLoadedData'
+ | 'onLoadedDataCapture'
+ | 'onLoadedMetadata'
+ | 'onLoadedMetadataCapture'
+ | 'onLoadStart'
+ | 'onLoadStartCapture'
+ | 'onPause'
+ | 'onPauseCapture'
+ | 'onPlay'
+ | 'onPlayCapture'
+ | 'onPlaying'
+ | 'onPlayingCapture'
+ | 'onProgress'
+ | 'onProgressCapture'
+ | 'onRateChange'
+ | 'onRateChangeCapture'
+ | 'onSeeked'
+ | 'onSeekedCapture'
+ | 'onSeeking'
+ | 'onSeekingCapture'
+ | 'onStalled'
+ | 'onStalledCapture'
+ | 'onSuspend'
+ | 'onSuspendCapture'
+ | 'onTimeUpdate'
+ | 'onTimeUpdateCapture'
+ | 'onVolumeChange'
+ | 'onVolumeChangeCapture'
+ | 'onWaiting'
+ | 'onWaitingCapture'
+ | 'onAuxClick'
+ | 'onAuxClickCapture'
+ | 'onClick'
+ | 'onClickCapture'
+ | 'onContextMenu'
+ | 'onContextMenuCapture'
+ | 'onDoubleClick'
+ | 'onDoubleClickCapture'
+ | 'onDrag'
+ | 'onDragCapture'
+ | 'onDragEnd'
+ | 'onDragEndCapture'
+ | 'onDragEnter'
+ | 'onDragEnterCapture'
+ | 'onDragExit'
+ | 'onDragExitCapture'
+ | 'onDragLeave'
+ | 'onDragLeaveCapture'
+ | 'onDragOver'
+ | 'onDragOverCapture'
+ | 'onDragStart'
+ | 'onDragStartCapture'
+ | 'onDrop'
+ | 'onDropCapture'
+ | 'onMouseDown'
+ | 'onMouseDownCapture'
+ | 'onMouseEnter'
+ | 'onMouseLeave'
+ | 'onMouseMove'
+ | 'onMouseMoveCapture'
+ | 'onMouseOut'
+ | 'onMouseOutCapture'
+ | 'onMouseOver'
+ | 'onMouseOverCapture'
+ | 'onMouseUp'
+ | 'onMouseUpCapture'
+ | 'onSelect'
+ | 'onSelectCapture'
+ | 'onTouchCancel'
+ | 'onTouchCancelCapture'
+ | 'onTouchEnd'
+ | 'onTouchEndCapture'
+ | 'onTouchMove'
+ | 'onTouchMoveCapture'
+ | 'onTouchStart'
+ | 'onTouchStartCapture'
+ | 'onPointerDown'
+ | 'onPointerDownCapture'
+ | 'onPointerMove'
+ | 'onPointerMoveCapture'
+ | 'onPointerUp'
+ | 'onPointerUpCapture'
+ | 'onPointerCancel'
+ | 'onPointerCancelCapture'
+ | 'onPointerEnter'
+ | 'onPointerEnterCapture'
+ | 'onPointerLeave'
+ | 'onPointerLeaveCapture'
+ | 'onPointerOver'
+ | 'onPointerOverCapture'
+ | 'onPointerOut'
+ | 'onPointerOutCapture'
+ | 'onGotPointerCapture'
+ | 'onGotPointerCaptureCapture'
+ | 'onLostPointerCapture'
+ | 'onLostPointerCaptureCapture'
+ | 'onScroll'
+ | 'onScrollCapture'
+ | 'onWheel'
+ | 'onWheelCapture'
+ | 'onAnimationStart'
+ | 'onAnimationStartCapture'
+ | 'onAnimationEnd'
+ | 'onAnimationEndCapture'
+ | 'onAnimationIteration'
+ | 'onAnimationIterationCapture'
+ | 'onTransitionEnd'
+ | 'onTransitionEndCapture'
+ | 'variant'
+ | 'innerRef'
+ | 'disableGutters'
+ > &
+ StyledComponentProps<'root'>
+>;
+
// @public
export type TechDocsReaderPageValue = {
metadata: AsyncState;
diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json
index 9813bdc66f..d383edc40b 100644
--- a/plugins/techdocs/package.json
+++ b/plugins/techdocs/package.json
@@ -47,6 +47,7 @@
"@backstage/plugin-catalog": "^1.1.0-next.2",
"@backstage/plugin-search": "^0.7.5-next.0",
"@backstage/techdocs-addons": "^0.0.0",
+ "@backstage/version-bridge": "^1.0.0",
"@backstage/theme": "^0.2.15",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.tsx
index a2c1897cbe..66fb97cfa7 100644
--- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.tsx
+++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.tsx
@@ -19,7 +19,6 @@ import React, {
memo,
Dispatch,
SetStateAction,
- createContext,
useContext,
useState,
} from 'react';
@@ -27,6 +26,10 @@ import useAsync, { AsyncState } from 'react-use/lib/useAsync';
import { useApi } from '@backstage/core-plugin-api';
import { CompoundEntityRef } from '@backstage/catalog-model';
+import {
+ createVersionedContext,
+ createVersionedValueMap,
+} from '@backstage/version-bridge';
import { techdocsApiRef } from '../../../api';
import { TechDocsEntityMetadata, TechDocsMetadata } from '../../../types';
@@ -78,15 +81,26 @@ export const defaultTechDocsReaderPageValue: TechDocsReaderPageValue = {
entityName: { kind: '', name: '', namespace: '' },
};
-export const TechDocsReaderPageContext = createContext(
- defaultTechDocsReaderPageValue,
-);
+export const TechDocsReaderPageContext = createVersionedContext<{
+ 1: TechDocsReaderPageValue;
+}>('techdocs-reader-page-context');
/**
* Hook used to get access to shared state between reader page components.
* @public
*/
export const useTechDocsReaderPage = () => {
- return useContext(TechDocsReaderPageContext);
+ const versionedContext = useContext(TechDocsReaderPageContext);
+
+ if (versionedContext === undefined) {
+ return defaultTechDocsReaderPageValue;
+ }
+
+ const context = versionedContext.atVersion(1);
+ if (context === undefined) {
+ throw new Error('No context found for version 1.');
+ }
+
+ return context;
};
/**
@@ -143,9 +157,10 @@ export const TechDocsReaderPageProvider = memo(
subtitle,
setSubtitle,
};
+ const versionedValue = createVersionedValueMap({ 1: value });
return (
-
+
{children instanceof Function ? children(value) : children}
);
diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx
index 45a89d0c84..5e89a09fea 100644
--- a/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx
+++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx
@@ -23,6 +23,11 @@ import {
useTechDocsAddons,
} from '@backstage/techdocs-addons';
+/**
+ * Renders the reader page subheader.
+ * Please use the Tech Docs add-ons to customize it
+ * @public
+ */
export const TechDocsReaderPageSubheader = withStyles(theme => ({
root: {
gridArea: 'pageSubheader',
diff --git a/plugins/techdocs/src/reader/components/index.ts b/plugins/techdocs/src/reader/components/index.ts
index 281a16cc08..d910135e91 100644
--- a/plugins/techdocs/src/reader/components/index.ts
+++ b/plugins/techdocs/src/reader/components/index.ts
@@ -32,5 +32,6 @@ export {
} from './TechDocsReaderPage';
export * from './TechDocsReaderPageHeader';
export * from './TechDocsReaderPageContent';
+export * from './TechDocsReaderPageSubheader';
export * from './TechDocsStateIndicator';
export type { ReaderState, ContentStateTypes } from './useReaderState';