@backstage/plugin-techdocs 1.12.1-next.1 → 1.12.2-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +158 -0
- package/dist/home/components/DefaultTechDocsHome.esm.js +14 -2
- package/dist/home/components/DefaultTechDocsHome.esm.js.map +1 -1
- package/dist/home/components/Grids/InfoCardGrid.esm.js +75 -0
- package/dist/home/components/Grids/InfoCardGrid.esm.js.map +1 -0
- package/dist/home/components/TechDocsCustomHome.esm.js +24 -11
- package/dist/home/components/TechDocsCustomHome.esm.js.map +1 -1
- package/dist/home/components/TechDocsIndexPage.esm.js.map +1 -1
- package/dist/home/components/TechDocsPageWrapper.esm.js +3 -3
- package/dist/home/components/TechDocsPageWrapper.esm.js.map +1 -1
- package/dist/index.d.ts +68 -2
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/reader/components/TechDocsReaderPageContent/dom.esm.js +4 -3
- package/dist/reader/components/TechDocsReaderPageContent/dom.esm.js.map +1 -1
- package/package.json +22 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,163 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs
|
|
2
2
|
|
|
3
|
+
## 1.12.2-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f4be934: Changed the base URL in addLinkClickListener from window.location.origin to app.baseUrl for improved path handling. This fixes an issue where Backstage, when running on a subpath, was unable to handle non-Backstage URLs of the same origin correctly.
|
|
8
|
+
- 1f40e6b: Add optional props to `TechDocCustomHome` to allow for more flexibility:
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { TechDocsCustomHome } from '@backstage/plugin-techdocs';
|
|
12
|
+
//...
|
|
13
|
+
|
|
14
|
+
const options = { emptyRowsWhenPaging: false };
|
|
15
|
+
const linkDestination = (entity: Entity): string | undefined => {
|
|
16
|
+
return entity.metadata.annotations?.['external-docs'];
|
|
17
|
+
};
|
|
18
|
+
const techDocsTabsConfig = [
|
|
19
|
+
{
|
|
20
|
+
label: 'Recommended Documentation',
|
|
21
|
+
panels: [
|
|
22
|
+
{
|
|
23
|
+
title: 'Golden Path',
|
|
24
|
+
description: 'Documentation about standards to follow',
|
|
25
|
+
panelType: 'DocsCardGrid',
|
|
26
|
+
panelProps: { CustomHeader: () => <ContentHeader title='Golden Path'/> },
|
|
27
|
+
filterPredicate: entity =>
|
|
28
|
+
entity?.metadata?.tags?.includes('golden-path') ?? false,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Recommended',
|
|
32
|
+
description: 'Useful documentation',
|
|
33
|
+
panelType: 'InfoCardGrid',
|
|
34
|
+
panelProps: {
|
|
35
|
+
CustomHeader: () => <ContentHeader title='Recommended' />
|
|
36
|
+
linkDestination: linkDestination,
|
|
37
|
+
},
|
|
38
|
+
filterPredicate: entity =>
|
|
39
|
+
entity?.metadata?.tags?.includes('recommended') ?? false,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'Browse All',
|
|
45
|
+
panels: [
|
|
46
|
+
{
|
|
47
|
+
description: 'Browse all docs',
|
|
48
|
+
filterPredicate: filterEntity,
|
|
49
|
+
panelType: 'TechDocsIndexPage',
|
|
50
|
+
title: 'All',
|
|
51
|
+
panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options },
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const AppRoutes = () => {
|
|
58
|
+
<FlatRoutes>
|
|
59
|
+
<Route
|
|
60
|
+
path="/docs"
|
|
61
|
+
element={
|
|
62
|
+
<TechDocsCustomHome
|
|
63
|
+
tabsConfig={techDocsTabsConfig}
|
|
64
|
+
filter={{
|
|
65
|
+
kind: ['Location', 'Resource', 'Component'],
|
|
66
|
+
'metadata.annotations.featured-docs': CATALOG_FILTER_EXISTS,
|
|
67
|
+
}}
|
|
68
|
+
CustomPageWrapper={({ children }: React.PropsWithChildren<{}>) => (<PageWithHeader title="Docs" themeId="documentation">{children}</PageWithHeader>)}
|
|
69
|
+
/>
|
|
70
|
+
}
|
|
71
|
+
/>
|
|
72
|
+
</FlatRoutes>;
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Add new Grid option called `InfoCardGrid` which is a more customizable card option for the Docs grid.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<InfoCardGrid
|
|
80
|
+
entities={entities}
|
|
81
|
+
linkContent="Learn more"
|
|
82
|
+
linkDestination={entity => entity.metadata['external-docs']}
|
|
83
|
+
/>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Expose existing `CustomDocsPanel` so that it can be used independently if desired.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
const panels: PanelConfig[] = [
|
|
90
|
+
{
|
|
91
|
+
description: '',
|
|
92
|
+
filterPredicate: entity => {},
|
|
93
|
+
panelType: 'InfoCardGrid',
|
|
94
|
+
title: 'Standards',
|
|
95
|
+
panelProps: {
|
|
96
|
+
CustomHeader: () => <ContentHeader title='Recommended' />
|
|
97
|
+
linkDestination: linkDestination,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
description: '',
|
|
102
|
+
filterPredicate: entity => {},
|
|
103
|
+
panelType: 'DocsCardGrid',
|
|
104
|
+
title: 'Contribute',
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
{
|
|
108
|
+
panels.map((config, index) => (
|
|
109
|
+
<CustomDocsPanel
|
|
110
|
+
key={index}
|
|
111
|
+
config={config}
|
|
112
|
+
entities={!!entities ? entities : []}
|
|
113
|
+
index={index}
|
|
114
|
+
/>
|
|
115
|
+
));
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- Updated dependencies
|
|
120
|
+
- @backstage/plugin-search-react@1.8.6-next.0
|
|
121
|
+
- @backstage/frontend-plugin-api@0.9.5-next.0
|
|
122
|
+
- @backstage/catalog-client@1.9.1
|
|
123
|
+
- @backstage/catalog-model@1.7.3
|
|
124
|
+
- @backstage/config@1.3.2
|
|
125
|
+
- @backstage/core-compat-api@0.3.6-next.0
|
|
126
|
+
- @backstage/core-components@0.16.3
|
|
127
|
+
- @backstage/core-plugin-api@1.10.3
|
|
128
|
+
- @backstage/errors@1.2.7
|
|
129
|
+
- @backstage/integration@1.16.1
|
|
130
|
+
- @backstage/integration-react@1.2.3
|
|
131
|
+
- @backstage/theme@0.6.3
|
|
132
|
+
- @backstage/plugin-auth-react@0.1.11
|
|
133
|
+
- @backstage/plugin-catalog-react@1.15.2-next.0
|
|
134
|
+
- @backstage/plugin-search-common@1.2.17
|
|
135
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
136
|
+
- @backstage/plugin-techdocs-react@1.2.13
|
|
137
|
+
|
|
138
|
+
## 1.12.1
|
|
139
|
+
|
|
140
|
+
### Patch Changes
|
|
141
|
+
|
|
142
|
+
- 3710b35: Allow passing down `withSearch` prop to `EntityTechdocsContent` component since it was `true` by default, now user can use the `EntityTechdocsContent` component _without_ showing the search field on top of the content.
|
|
143
|
+
- Updated dependencies
|
|
144
|
+
- @backstage/plugin-catalog-react@1.15.1
|
|
145
|
+
- @backstage/frontend-plugin-api@0.9.4
|
|
146
|
+
- @backstage/core-plugin-api@1.10.3
|
|
147
|
+
- @backstage/core-components@0.16.3
|
|
148
|
+
- @backstage/integration@1.16.1
|
|
149
|
+
- @backstage/catalog-model@1.7.3
|
|
150
|
+
- @backstage/config@1.3.2
|
|
151
|
+
- @backstage/core-compat-api@0.3.5
|
|
152
|
+
- @backstage/errors@1.2.7
|
|
153
|
+
- @backstage/integration-react@1.2.3
|
|
154
|
+
- @backstage/theme@0.6.3
|
|
155
|
+
- @backstage/plugin-auth-react@0.1.11
|
|
156
|
+
- @backstage/plugin-search-common@1.2.17
|
|
157
|
+
- @backstage/plugin-search-react@1.8.5
|
|
158
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
159
|
+
- @backstage/plugin-techdocs-react@1.2.13
|
|
160
|
+
|
|
3
161
|
## 1.12.1-next.1
|
|
4
162
|
|
|
5
163
|
### Patch Changes
|
|
@@ -12,9 +12,21 @@ const DefaultTechDocsHome = (props) => {
|
|
|
12
12
|
columns,
|
|
13
13
|
actions,
|
|
14
14
|
ownerPickerMode,
|
|
15
|
-
pagination
|
|
15
|
+
pagination,
|
|
16
|
+
options,
|
|
17
|
+
PageWrapper,
|
|
18
|
+
CustomHeader
|
|
16
19
|
} = props;
|
|
17
|
-
|
|
20
|
+
const Wrapper = PageWrapper ? PageWrapper : TechDocsPageWrapper;
|
|
21
|
+
const Header = CustomHeader || (() => /* @__PURE__ */ React.createElement(ContentHeader, { title: "" }, /* @__PURE__ */ React.createElement(SupportButton, null, "Discover documentation in your ecosystem.")));
|
|
22
|
+
return /* @__PURE__ */ React.createElement(Wrapper, null, /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Header, null), /* @__PURE__ */ React.createElement(EntityListProvider, { pagination }, /* @__PURE__ */ React.createElement(CatalogFilterLayout, null, /* @__PURE__ */ React.createElement(CatalogFilterLayout.Filters, null, /* @__PURE__ */ React.createElement(TechDocsPicker, null), /* @__PURE__ */ React.createElement(UserListPicker, { initialFilter }), /* @__PURE__ */ React.createElement(EntityOwnerPicker, { mode: ownerPickerMode }), /* @__PURE__ */ React.createElement(EntityTagPicker, null)), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, /* @__PURE__ */ React.createElement(
|
|
23
|
+
EntityListDocsTable,
|
|
24
|
+
{
|
|
25
|
+
actions,
|
|
26
|
+
columns,
|
|
27
|
+
options
|
|
28
|
+
}
|
|
29
|
+
))))));
|
|
18
30
|
};
|
|
19
31
|
|
|
20
32
|
export { DefaultTechDocsHome };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultTechDocsHome.esm.js","sources":["../../../src/home/components/DefaultTechDocsHome.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Content,\n ContentHeader,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n CatalogFilterLayout,\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\nimport { TechDocsPicker } from './TechDocsPicker';\nimport { EntityListDocsTable } from './Tables';\nimport { TechDocsIndexPageProps } from './TechDocsIndexPage';\n\n/**\n * Props for {@link DefaultTechDocsHome}\n *\n * @public\n * @deprecated Please use `TechDocsIndexPageProps` instead.\n */\nexport type DefaultTechDocsHomeProps = TechDocsIndexPageProps;\n\n/**\n * Component which renders a default documentation landing page.\n *\n * @public\n */\nexport const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {\n const {\n initialFilter = 'owned',\n columns,\n actions,\n ownerPickerMode,\n pagination,\n } = props;\n
|
|
1
|
+
{"version":3,"file":"DefaultTechDocsHome.esm.js","sources":["../../../src/home/components/DefaultTechDocsHome.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n Content,\n ContentHeader,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n CatalogFilterLayout,\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\nimport { TechDocsPicker } from './TechDocsPicker';\nimport { EntityListDocsTable } from './Tables';\nimport { TechDocsIndexPageProps } from './TechDocsIndexPage';\n\n/**\n * Props for {@link DefaultTechDocsHome}\n *\n * @public\n * @deprecated Please use `TechDocsIndexPageProps` instead.\n */\nexport type DefaultTechDocsHomeProps = TechDocsIndexPageProps;\n\n/**\n * Component which renders a default documentation landing page.\n *\n * @public\n */\nexport const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {\n const {\n initialFilter = 'owned',\n columns,\n actions,\n ownerPickerMode,\n pagination,\n options,\n PageWrapper,\n CustomHeader,\n } = props;\n const Wrapper: React.FC<{\n children: React.ReactNode;\n }> = PageWrapper ? PageWrapper : TechDocsPageWrapper;\n const Header: React.FC =\n CustomHeader ||\n (() => (\n <ContentHeader title=\"\">\n <SupportButton>Discover documentation in your ecosystem.</SupportButton>\n </ContentHeader>\n ));\n return (\n <Wrapper>\n <Content>\n <Header />\n <EntityListProvider pagination={pagination}>\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <TechDocsPicker />\n <UserListPicker initialFilter={initialFilter} />\n <EntityOwnerPicker mode={ownerPickerMode} />\n <EntityTagPicker />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n <EntityListDocsTable\n actions={actions}\n columns={columns}\n options={options}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </EntityListProvider>\n </Content>\n </Wrapper>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AA+Ca,MAAA,mBAAA,GAAsB,CAAC,KAAkC,KAAA;AACpE,EAAM,MAAA;AAAA,IACJ,aAAgB,GAAA,OAAA;AAAA,IAChB,OAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AACJ,EAAM,MAAA,OAAA,GAED,cAAc,WAAc,GAAA,mBAAA;AACjC,EAAM,MAAA,MAAA,GACJ,YACC,KAAA,sBACE,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA,EAAc,OAAM,EACnB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,IAAA,EAAA,2CAAyC,CAC1D,CAAA,CAAA;AAEJ,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,IAAA,sCACE,MAAO,EAAA,IAAA,CAAA,kBACP,KAAA,CAAA,aAAA,CAAA,kBAAA,EAAA,EAAmB,8BACjB,KAAA,CAAA,aAAA,CAAA,mBAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,mBAAA,CAAoB,SAApB,IACC,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAe,EAAA,IAAA,CAAA,sCACf,cAAe,EAAA,EAAA,aAAA,EAA8B,CAC9C,kBAAA,KAAA,CAAA,aAAA,CAAC,qBAAkB,IAAM,EAAA,eAAA,EAAiB,CAC1C,kBAAA,KAAA,CAAA,aAAA,CAAC,qBAAgB,CACnB,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,mBAAA,CAAoB,SAApB,IACC,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACC,OAAA;AAAA,MACA,OAAA;AAAA,MACA;AAAA;AAAA,GAEJ,CACF,CACF,CACF,CACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
3
|
+
import { stringifyEntityRef } from '@backstage/catalog-model';
|
|
4
|
+
import { useRouteRef, useApi, configApiRef } from '@backstage/core-plugin-api';
|
|
5
|
+
import { Progress, ItemCardGrid, InfoCard, Link } from '@backstage/core-components';
|
|
6
|
+
import { entityPresentationApiRef } from '@backstage/plugin-catalog-react';
|
|
7
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
8
|
+
import { rootDocsRouteRef } from '../../../routes.esm.js';
|
|
9
|
+
import { toLowerMaybe } from '../../../helpers.esm.js';
|
|
10
|
+
|
|
11
|
+
const useStyles = makeStyles(
|
|
12
|
+
(theme) => ({
|
|
13
|
+
linkSpacer: {
|
|
14
|
+
paddingTop: theme.spacing(0.2)
|
|
15
|
+
},
|
|
16
|
+
readMoreLink: {
|
|
17
|
+
paddingTop: theme.spacing(0.2)
|
|
18
|
+
}
|
|
19
|
+
}),
|
|
20
|
+
{ name: "BackstageInfoCardGrid" }
|
|
21
|
+
);
|
|
22
|
+
const InfoCardGrid = (props) => {
|
|
23
|
+
const { entities, linkContent, linkDestination } = props;
|
|
24
|
+
const classes = useStyles();
|
|
25
|
+
const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
|
|
26
|
+
const config = useApi(configApiRef);
|
|
27
|
+
const linkRoute = (entity) => {
|
|
28
|
+
if (linkDestination) {
|
|
29
|
+
const destination = linkDestination(entity);
|
|
30
|
+
if (destination) {
|
|
31
|
+
return destination;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return getRouteToReaderPageFor({
|
|
35
|
+
namespace: toLowerMaybe(entity.metadata.namespace ?? "default", config),
|
|
36
|
+
kind: toLowerMaybe(entity.kind, config),
|
|
37
|
+
name: toLowerMaybe(entity.metadata.name, config)
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const entityPresentationApi = useApi(entityPresentationApiRef);
|
|
41
|
+
const { value: entityRefToPresentation, loading } = useAsync(async () => {
|
|
42
|
+
return new Map(
|
|
43
|
+
await Promise.all(
|
|
44
|
+
entities?.map(async (entity) => {
|
|
45
|
+
const presentation = await entityPresentationApi.forEntity(entity).promise;
|
|
46
|
+
return [stringifyEntityRef(entity), presentation];
|
|
47
|
+
}) || []
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
if (loading) return /* @__PURE__ */ React.createElement(Progress, null);
|
|
52
|
+
if (!entities || !entities?.length) return null;
|
|
53
|
+
return /* @__PURE__ */ React.createElement(ItemCardGrid, { "data-testid": "info-card-container" }, entities.map((entity) => /* @__PURE__ */ React.createElement(
|
|
54
|
+
InfoCard,
|
|
55
|
+
{
|
|
56
|
+
key: entity.metadata.name,
|
|
57
|
+
"data-testid": entity?.metadata?.title,
|
|
58
|
+
title: entityRefToPresentation?.get(stringifyEntityRef(entity))?.primaryTitle
|
|
59
|
+
},
|
|
60
|
+
/* @__PURE__ */ React.createElement("div", null, entity?.metadata?.description),
|
|
61
|
+
/* @__PURE__ */ React.createElement("div", { className: classes.linkSpacer }),
|
|
62
|
+
/* @__PURE__ */ React.createElement(
|
|
63
|
+
Link,
|
|
64
|
+
{
|
|
65
|
+
to: linkRoute(entity),
|
|
66
|
+
className: classes.readMoreLink,
|
|
67
|
+
"data-testid": "read-docs-link"
|
|
68
|
+
},
|
|
69
|
+
linkContent || "Read Docs"
|
|
70
|
+
)
|
|
71
|
+
)));
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export { InfoCardGrid };
|
|
75
|
+
//# sourceMappingURL=InfoCardGrid.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfoCardGrid.esm.js","sources":["../../../../src/home/components/Grids/InfoCardGrid.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi, useRouteRef, configApiRef } from '@backstage/core-plugin-api';\nimport {\n ItemCardGrid,\n InfoCard,\n Link,\n Progress,\n} from '@backstage/core-components';\nimport {\n EntityRefPresentationSnapshot,\n entityPresentationApiRef,\n} from '@backstage/plugin-catalog-react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { rootDocsRouteRef } from '../../../routes';\nimport { toLowerMaybe } from '../../../helpers';\n\n/** @public */\nexport type InfoCardGridClassKey = 'linkSpacer' | 'readMoreLink';\n\nconst useStyles = makeStyles(\n theme => ({\n linkSpacer: {\n paddingTop: theme.spacing(0.2),\n },\n readMoreLink: {\n paddingTop: theme.spacing(0.2),\n },\n }),\n { name: 'BackstageInfoCardGrid' },\n);\n\n/**\n * Props for {@link InfoCardGrid}\n *\n * @public\n */\nexport type InfoCardGridProps = {\n entities: Entity[] | undefined;\n linkContent?: string | JSX.Element;\n linkDestination?: (entity: Entity) => string | undefined;\n};\n\n/**\n * Component which accepts a list of entities and renders a info card for each entity\n *\n * @public\n */\nexport const InfoCardGrid = (props: InfoCardGridProps) => {\n const { entities, linkContent, linkDestination } = props;\n const classes = useStyles();\n const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);\n const config = useApi(configApiRef);\n const linkRoute = (entity: Entity) => {\n if (linkDestination) {\n const destination = linkDestination(entity);\n if (destination) {\n return destination;\n }\n }\n return getRouteToReaderPageFor({\n namespace: toLowerMaybe(entity.metadata.namespace ?? 'default', config),\n kind: toLowerMaybe(entity.kind, config),\n name: toLowerMaybe(entity.metadata.name, config),\n });\n };\n const entityPresentationApi = useApi(entityPresentationApiRef);\n const { value: entityRefToPresentation, loading } = useAsync(async () => {\n return new Map<string, EntityRefPresentationSnapshot>(\n await Promise.all(\n entities?.map(async entity => {\n const presentation = await entityPresentationApi.forEntity(entity)\n .promise;\n return [stringifyEntityRef(entity), presentation] as [\n string,\n EntityRefPresentationSnapshot,\n ];\n }) || [],\n ),\n );\n });\n if (loading) return <Progress />;\n if (!entities || !entities?.length) return null;\n return (\n <ItemCardGrid data-testid=\"info-card-container\">\n {entities.map(entity => (\n <InfoCard\n key={entity.metadata.name}\n data-testid={entity?.metadata?.title}\n title={\n entityRefToPresentation?.get(stringifyEntityRef(entity))\n ?.primaryTitle\n }\n >\n <div>{entity?.metadata?.description}</div>\n <div className={classes.linkSpacer} />\n <Link\n to={linkRoute(entity)}\n className={classes.readMoreLink}\n data-testid=\"read-docs-link\"\n >\n {linkContent || 'Read Docs'}\n </Link>\n </InfoCard>\n ))}\n </ItemCardGrid>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import useAsync from 'react-use/esm/useAsync';
|
|
3
3
|
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
-
import {
|
|
4
|
+
import { useEntityOwnership, EntityListProvider, catalogApiRef, CATALOG_FILTER_EXISTS } from '@backstage/plugin-catalog-react';
|
|
5
5
|
import './Tables/EntityListDocsTable.esm.js';
|
|
6
6
|
import { DocsTable } from './Tables/DocsTable.esm.js';
|
|
7
7
|
import { DocsCardGrid } from './Grids/DocsCardGrid.esm.js';
|
|
8
|
-
import { Content, Progress, WarningPanel, CodeSnippet, HeaderTabs
|
|
8
|
+
import { ContentHeader, SupportButton, Content, Progress, WarningPanel, CodeSnippet, HeaderTabs } from '@backstage/core-components';
|
|
9
9
|
import '@material-ui/core/Typography';
|
|
10
|
+
import { InfoCardGrid } from './Grids/InfoCardGrid.esm.js';
|
|
10
11
|
import { TechDocsPageWrapper } from './TechDocsPageWrapper.esm.js';
|
|
12
|
+
import { TechDocsIndexPage } from './TechDocsIndexPage.esm.js';
|
|
11
13
|
import { useApi } from '@backstage/core-plugin-api';
|
|
12
14
|
import { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';
|
|
13
15
|
|
|
14
16
|
const panels = {
|
|
15
17
|
DocsTable,
|
|
16
|
-
DocsCardGrid
|
|
18
|
+
DocsCardGrid,
|
|
19
|
+
TechDocsIndexPage,
|
|
20
|
+
InfoCardGrid
|
|
17
21
|
};
|
|
18
|
-
const
|
|
22
|
+
const CustomDocsPanel = ({
|
|
19
23
|
config,
|
|
20
24
|
entities,
|
|
21
25
|
index
|
|
@@ -38,10 +42,18 @@ const CustomPanel = ({
|
|
|
38
42
|
}
|
|
39
43
|
return typeof config.filterPredicate === "function" && config.filterPredicate(entity);
|
|
40
44
|
});
|
|
41
|
-
|
|
45
|
+
const Header = config.panelProps?.CustomHeader || (() => /* @__PURE__ */ React.createElement(ContentHeader, { title: config.title, description: config.description }, index === 0 ? /* @__PURE__ */ React.createElement(SupportButton, null, "Discover documentation in your ecosystem.") : null));
|
|
46
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Header, null), /* @__PURE__ */ React.createElement("div", { className: classes.panelContainer }, /* @__PURE__ */ React.createElement(EntityListProvider, null, /* @__PURE__ */ React.createElement(
|
|
47
|
+
Panel,
|
|
48
|
+
{
|
|
49
|
+
"data-testid": "techdocs-custom-panel",
|
|
50
|
+
entities: shownEntities,
|
|
51
|
+
...config.panelProps
|
|
52
|
+
}
|
|
53
|
+
))));
|
|
42
54
|
};
|
|
43
55
|
const TechDocsCustomHome = (props) => {
|
|
44
|
-
const { tabsConfig } = props;
|
|
56
|
+
const { tabsConfig, filter, CustomPageWrapper } = props;
|
|
45
57
|
const [selectedTab, setSelectedTab] = useState(0);
|
|
46
58
|
const catalogApi = useApi(catalogApiRef);
|
|
47
59
|
const {
|
|
@@ -51,6 +63,7 @@ const TechDocsCustomHome = (props) => {
|
|
|
51
63
|
} = useAsync(async () => {
|
|
52
64
|
const response = await catalogApi.getEntities({
|
|
53
65
|
filter: {
|
|
66
|
+
...filter,
|
|
54
67
|
[`metadata.annotations.${TECHDOCS_ANNOTATION}`]: CATALOG_FILTER_EXISTS
|
|
55
68
|
},
|
|
56
69
|
fields: [
|
|
@@ -68,10 +81,10 @@ const TechDocsCustomHome = (props) => {
|
|
|
68
81
|
});
|
|
69
82
|
const currentTabConfig = tabsConfig[selectedTab];
|
|
70
83
|
if (loading) {
|
|
71
|
-
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper,
|
|
84
|
+
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper, { CustomPageWrapper }, /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Progress, null)));
|
|
72
85
|
}
|
|
73
86
|
if (error) {
|
|
74
|
-
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper,
|
|
87
|
+
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper, { CustomPageWrapper }, /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(
|
|
75
88
|
WarningPanel,
|
|
76
89
|
{
|
|
77
90
|
severity: "error",
|
|
@@ -80,7 +93,7 @@ const TechDocsCustomHome = (props) => {
|
|
|
80
93
|
/* @__PURE__ */ React.createElement(CodeSnippet, { language: "text", text: error.toString() })
|
|
81
94
|
)));
|
|
82
95
|
}
|
|
83
|
-
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper,
|
|
96
|
+
return /* @__PURE__ */ React.createElement(TechDocsPageWrapper, { CustomPageWrapper }, /* @__PURE__ */ React.createElement(
|
|
84
97
|
HeaderTabs,
|
|
85
98
|
{
|
|
86
99
|
selectedIndex: selectedTab,
|
|
@@ -91,7 +104,7 @@ const TechDocsCustomHome = (props) => {
|
|
|
91
104
|
}))
|
|
92
105
|
}
|
|
93
106
|
), /* @__PURE__ */ React.createElement(Content, { "data-testid": "techdocs-content" }, currentTabConfig.panels.map((config, index) => /* @__PURE__ */ React.createElement(
|
|
94
|
-
|
|
107
|
+
CustomDocsPanel,
|
|
95
108
|
{
|
|
96
109
|
key: index,
|
|
97
110
|
config,
|
|
@@ -101,5 +114,5 @@ const TechDocsCustomHome = (props) => {
|
|
|
101
114
|
))));
|
|
102
115
|
};
|
|
103
116
|
|
|
104
|
-
export { TechDocsCustomHome };
|
|
117
|
+
export { CustomDocsPanel, TechDocsCustomHome };
|
|
105
118
|
//# sourceMappingURL=TechDocsCustomHome.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechDocsCustomHome.esm.js","sources":["../../../src/home/components/TechDocsCustomHome.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { CSSProperties } from '@material-ui/styles/withStyles';\nimport {\n CATALOG_FILTER_EXISTS,\n catalogApiRef,\n CatalogApi,\n useEntityOwnership,\n EntityListProvider,\n} from '@backstage/plugin-catalog-react';\nimport { Entity } from '@backstage/catalog-model';\nimport { DocsTable } from './Tables';\nimport { DocsCardGrid } from './Grids';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\n\nimport {\n CodeSnippet,\n Content,\n HeaderTabs,\n Progress,\n WarningPanel,\n SupportButton,\n ContentHeader,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\n\nconst panels = {\n DocsTable: DocsTable,\n DocsCardGrid: DocsCardGrid,\n};\n\n/**\n * Available panel types\n *\n * @public\n */\nexport type PanelType = 'DocsCardGrid' | 'DocsTable';\n\n/**\n * Type representing a TechDocsCustomHome panel.\n *\n * @public\n */\nexport interface PanelConfig {\n title: string;\n description: string;\n panelType: PanelType;\n panelCSS?: CSSProperties;\n filterPredicate: ((entity: Entity) => boolean) | string;\n}\n\n/**\n * Type representing a TechDocsCustomHome tab.\n *\n * @public\n */\nexport interface TabConfig {\n label: string;\n panels: PanelConfig[];\n}\n\n/**\n * Type representing a list of TechDocsCustomHome tabs.\n *\n * @public\n */\nexport type TabsConfig = TabConfig[];\n\nconst CustomPanel = ({\n config,\n entities,\n index,\n}: {\n config: PanelConfig;\n entities: Entity[];\n index: number;\n}) => {\n const useStyles = makeStyles({\n panelContainer: {\n marginBottom: '2rem',\n ...(config.panelCSS ? config.panelCSS : {}),\n },\n });\n const classes = useStyles();\n const { loading: loadingOwnership, isOwnedEntity } = useEntityOwnership();\n\n const Panel = panels[config.panelType];\n\n const shownEntities = entities.filter(entity => {\n if (config.filterPredicate === 'ownedByUser') {\n if (loadingOwnership) {\n return false;\n }\n return isOwnedEntity(entity);\n }\n\n return (\n typeof config.filterPredicate === 'function' &&\n config.filterPredicate(entity)\n );\n });\n\n return (\n <>\n <ContentHeader title={config.title} description={config.description}>\n {index === 0 ? (\n <SupportButton>\n Discover documentation in your ecosystem.\n </SupportButton>\n ) : null}\n </ContentHeader>\n <div className={classes.panelContainer}>\n <EntityListProvider>\n <Panel data-testid=\"techdocs-custom-panel\" entities={shownEntities} />\n </EntityListProvider>\n </div>\n </>\n );\n};\n\n/**\n * Props for {@link TechDocsCustomHome}\n *\n * @public\n */\nexport type TechDocsCustomHomeProps = {\n tabsConfig: TabsConfig;\n};\n\nexport const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {\n const { tabsConfig } = props;\n const [selectedTab, setSelectedTab] = useState<number>(0);\n const catalogApi: CatalogApi = useApi(catalogApiRef);\n\n const {\n value: entities,\n loading,\n error,\n } = useAsync(async () => {\n const response = await catalogApi.getEntities({\n filter: {\n [`metadata.annotations.${TECHDOCS_ANNOTATION}`]: CATALOG_FILTER_EXISTS,\n },\n fields: [\n 'apiVersion',\n 'kind',\n 'metadata',\n 'relations',\n 'spec.owner',\n 'spec.type',\n ],\n });\n return response.items.filter((entity: Entity) => {\n return !!entity.metadata.annotations?.[TECHDOCS_ANNOTATION];\n });\n });\n\n const currentTabConfig = tabsConfig[selectedTab];\n\n if (loading) {\n return (\n <TechDocsPageWrapper>\n <Content>\n <Progress />\n </Content>\n </TechDocsPageWrapper>\n );\n }\n\n if (error) {\n return (\n <TechDocsPageWrapper>\n <Content>\n <WarningPanel\n severity=\"error\"\n title=\"Could not load available documentation.\"\n >\n <CodeSnippet language=\"text\" text={error.toString()} />\n </WarningPanel>\n </Content>\n </TechDocsPageWrapper>\n );\n }\n\n return (\n <TechDocsPageWrapper>\n <HeaderTabs\n selectedIndex={selectedTab}\n onChange={index => setSelectedTab(index)}\n tabs={tabsConfig.map(({ label }, index) => ({\n id: index.toString(),\n label,\n }))}\n />\n <Content data-testid=\"techdocs-content\">\n {currentTabConfig.panels.map((config, index) => (\n <CustomPanel\n key={index}\n config={config}\n entities={!!entities ? entities : []}\n index={index}\n />\n ))}\n </Content>\n </TechDocsPageWrapper>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TechDocsCustomHome.esm.js","sources":["../../../src/home/components/TechDocsCustomHome.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { CSSProperties } from '@material-ui/styles/withStyles';\nimport {\n CATALOG_FILTER_EXISTS,\n catalogApiRef,\n CatalogApi,\n useEntityOwnership,\n EntityListProvider,\n} from '@backstage/plugin-catalog-react';\nimport { Entity } from '@backstage/catalog-model';\nimport { DocsTable, DocsTableRow } from './Tables';\nimport { DocsCardGrid, InfoCardGrid } from './Grids';\nimport { TechDocsPageWrapper } from './TechDocsPageWrapper';\nimport { TechDocsIndexPage } from './TechDocsIndexPage';\n\nimport {\n CodeSnippet,\n Content,\n HeaderTabs,\n Progress,\n WarningPanel,\n SupportButton,\n ContentHeader,\n TableOptions,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\n\nconst panels = {\n DocsTable: DocsTable,\n DocsCardGrid: DocsCardGrid,\n TechDocsIndexPage: TechDocsIndexPage,\n InfoCardGrid: InfoCardGrid,\n};\n\n/**\n * Available panel types\n *\n * @public\n */\nexport type PanelType =\n | 'DocsCardGrid'\n | 'DocsTable'\n | 'TechDocsIndexPage'\n | 'InfoCardGrid';\n\n/**\n * Type representing Panel props\n *\n * @public\n */\nexport interface PanelProps {\n options?: TableOptions<DocsTableRow>;\n linkContent?: string | JSX.Element;\n linkDestination?: (entity: Entity) => string | undefined;\n PageWrapper?: React.FC;\n CustomHeader?: React.FC;\n}\n\n/**\n * Type representing a TechDocsCustomHome panel.\n *\n * @public\n */\nexport interface PanelConfig {\n title: string;\n description: string;\n panelType: PanelType;\n panelCSS?: CSSProperties;\n filterPredicate: ((entity: Entity) => boolean) | string;\n panelProps?: PanelProps;\n}\n\n/**\n * Type representing a TechDocsCustomHome tab.\n *\n * @public\n */\nexport interface TabConfig {\n label: string;\n panels: PanelConfig[];\n}\n\n/**\n * Type representing a list of TechDocsCustomHome tabs.\n *\n * @public\n */\nexport type TabsConfig = TabConfig[];\n\n/**\n * Component which can be used to render entities in a custom way.\n *\n * @public\n */\nexport const CustomDocsPanel = ({\n config,\n entities,\n index,\n}: {\n config: PanelConfig;\n entities: Entity[];\n index: number;\n}) => {\n const useStyles = makeStyles({\n panelContainer: {\n marginBottom: '2rem',\n ...(config.panelCSS ? config.panelCSS : {}),\n },\n });\n const classes = useStyles();\n const { loading: loadingOwnership, isOwnedEntity } = useEntityOwnership();\n\n const Panel = panels[config.panelType];\n\n const shownEntities = entities.filter(entity => {\n if (config.filterPredicate === 'ownedByUser') {\n if (loadingOwnership) {\n return false;\n }\n return isOwnedEntity(entity);\n }\n\n return (\n typeof config.filterPredicate === 'function' &&\n config.filterPredicate(entity)\n );\n });\n\n const Header: React.FC =\n config.panelProps?.CustomHeader ||\n (() => (\n <ContentHeader title={config.title} description={config.description}>\n {index === 0 ? (\n <SupportButton>\n Discover documentation in your ecosystem.\n </SupportButton>\n ) : null}\n </ContentHeader>\n ));\n\n return (\n <>\n <Header />\n <div className={classes.panelContainer}>\n <EntityListProvider>\n <Panel\n data-testid=\"techdocs-custom-panel\"\n entities={shownEntities}\n {...config.panelProps}\n />\n </EntityListProvider>\n </div>\n </>\n );\n};\n\n/**\n * Props for {@link TechDocsCustomHome}\n *\n * @public\n */\nexport type TechDocsCustomHomeProps = {\n tabsConfig: TabsConfig;\n filter?: EntityFilterQuery;\n CustomPageWrapper?: React.FC;\n};\n\nexport const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {\n const { tabsConfig, filter, CustomPageWrapper } = props;\n const [selectedTab, setSelectedTab] = useState<number>(0);\n const catalogApi: CatalogApi = useApi(catalogApiRef);\n\n const {\n value: entities,\n loading,\n error,\n } = useAsync(async () => {\n const response = await catalogApi.getEntities({\n filter: {\n ...filter,\n [`metadata.annotations.${TECHDOCS_ANNOTATION}`]: CATALOG_FILTER_EXISTS,\n },\n fields: [\n 'apiVersion',\n 'kind',\n 'metadata',\n 'relations',\n 'spec.owner',\n 'spec.type',\n ],\n });\n return response.items.filter((entity: Entity) => {\n return !!entity.metadata.annotations?.[TECHDOCS_ANNOTATION];\n });\n });\n\n const currentTabConfig = tabsConfig[selectedTab];\n\n if (loading) {\n return (\n <TechDocsPageWrapper CustomPageWrapper={CustomPageWrapper}>\n <Content>\n <Progress />\n </Content>\n </TechDocsPageWrapper>\n );\n }\n\n if (error) {\n return (\n <TechDocsPageWrapper CustomPageWrapper={CustomPageWrapper}>\n <Content>\n <WarningPanel\n severity=\"error\"\n title=\"Could not load available documentation.\"\n >\n <CodeSnippet language=\"text\" text={error.toString()} />\n </WarningPanel>\n </Content>\n </TechDocsPageWrapper>\n );\n }\n\n return (\n <TechDocsPageWrapper CustomPageWrapper={CustomPageWrapper}>\n <HeaderTabs\n selectedIndex={selectedTab}\n onChange={index => setSelectedTab(index)}\n tabs={tabsConfig.map(({ label }, index) => ({\n id: index.toString(),\n label,\n }))}\n />\n <Content data-testid=\"techdocs-content\">\n {currentTabConfig.panels.map((config, index) => (\n <CustomDocsPanel\n key={index}\n config={config}\n entities={!!entities ? entities : []}\n index={index}\n />\n ))}\n </Content>\n </TechDocsPageWrapper>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechDocsIndexPage.esm.js","sources":["../../../src/home/components/TechDocsIndexPage.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useOutlet } from 'react-router-dom';\nimport {
|
|
1
|
+
{"version":3,"file":"TechDocsIndexPage.esm.js","sources":["../../../src/home/components/TechDocsIndexPage.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { useOutlet } from 'react-router-dom';\nimport {\n TableColumn,\n TableProps,\n TableOptions,\n} from '@backstage/core-components';\nimport {\n EntityListPagination,\n EntityOwnerPickerProps,\n UserListFilterKind,\n} from '@backstage/plugin-catalog-react';\nimport { DefaultTechDocsHome } from './DefaultTechDocsHome';\nimport { DocsTableRow } from './Tables';\n\n/**\n * Props for {@link TechDocsIndexPage}\n *\n * @public\n */\nexport type TechDocsIndexPageProps = {\n initialFilter?: UserListFilterKind;\n columns?: TableColumn<DocsTableRow>[];\n actions?: TableProps<DocsTableRow>['actions'];\n ownerPickerMode?: EntityOwnerPickerProps['mode'];\n pagination?: EntityListPagination;\n options?: TableOptions<DocsTableRow>;\n PageWrapper?: React.FC;\n CustomHeader?: React.FC;\n};\n\nexport const TechDocsIndexPage = (props: TechDocsIndexPageProps) => {\n const outlet = useOutlet();\n\n return outlet || <DefaultTechDocsHome {...props} />;\n};\n"],"names":[],"mappings":";;;;AA+Ca,MAAA,iBAAA,GAAoB,CAAC,KAAkC,KAAA;AAClE,EAAA,MAAM,SAAS,SAAU,EAAA;AAEzB,EAAA,OAAO,MAAU,oBAAA,KAAA,CAAA,aAAA,CAAC,mBAAqB,EAAA,EAAA,GAAG,KAAO,EAAA,CAAA;AACnD;;;;"}
|
|
@@ -3,10 +3,10 @@ import { PageWithHeader } from '@backstage/core-components';
|
|
|
3
3
|
import { useApi, configApiRef } from '@backstage/core-plugin-api';
|
|
4
4
|
|
|
5
5
|
const TechDocsPageWrapper = (props) => {
|
|
6
|
-
const { children } = props;
|
|
6
|
+
const { children, CustomPageWrapper } = props;
|
|
7
7
|
const configApi = useApi(configApiRef);
|
|
8
8
|
const generatedSubtitle = `Documentation available in ${configApi.getOptionalString("organization.name") ?? "Backstage"}`;
|
|
9
|
-
return /* @__PURE__ */ React.createElement(
|
|
9
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, CustomPageWrapper ? /* @__PURE__ */ React.createElement(CustomPageWrapper, null, children) : /* @__PURE__ */ React.createElement(
|
|
10
10
|
PageWithHeader,
|
|
11
11
|
{
|
|
12
12
|
title: "Documentation",
|
|
@@ -14,7 +14,7 @@ const TechDocsPageWrapper = (props) => {
|
|
|
14
14
|
themeId: "documentation"
|
|
15
15
|
},
|
|
16
16
|
children
|
|
17
|
-
);
|
|
17
|
+
));
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export { TechDocsPageWrapper };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechDocsPageWrapper.esm.js","sources":["../../../src/home/components/TechDocsPageWrapper.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { PageWithHeader } from '@backstage/core-components';\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Props for {@link TechDocsPageWrapper}\n *\n * @public\n */\nexport type TechDocsPageWrapperProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Component wrapping a TechDocs page with Page and Header components\n *\n * @public\n */\nexport const TechDocsPageWrapper = (props: TechDocsPageWrapperProps) => {\n const { children } = props;\n const configApi = useApi(configApiRef);\n const generatedSubtitle = `Documentation available in ${\n configApi.getOptionalString('organization.name') ?? 'Backstage'\n }`;\n\n return (\n <PageWithHeader\n
|
|
1
|
+
{"version":3,"file":"TechDocsPageWrapper.esm.js","sources":["../../../src/home/components/TechDocsPageWrapper.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\n\nimport { PageWithHeader } from '@backstage/core-components';\nimport { useApi, configApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Props for {@link TechDocsPageWrapper}\n *\n * @public\n */\nexport type TechDocsPageWrapperProps = {\n children?: React.ReactNode;\n CustomPageWrapper?: React.FC<{ children?: React.ReactNode }>;\n};\n\n/**\n * Component wrapping a TechDocs page with Page and Header components\n *\n * @public\n */\nexport const TechDocsPageWrapper = (props: TechDocsPageWrapperProps) => {\n const { children, CustomPageWrapper } = props;\n const configApi = useApi(configApiRef);\n const generatedSubtitle = `Documentation available in ${\n configApi.getOptionalString('organization.name') ?? 'Backstage'\n }`;\n\n return (\n <>\n {CustomPageWrapper ? (\n <CustomPageWrapper>{children}</CustomPageWrapper>\n ) : (\n <PageWithHeader\n title=\"Documentation\"\n subtitle={generatedSubtitle}\n themeId=\"documentation\"\n >\n {children}\n </PageWithHeader>\n )}\n </>\n );\n};\n"],"names":[],"mappings":";;;;AAoCa,MAAA,mBAAA,GAAsB,CAAC,KAAoC,KAAA;AACtE,EAAM,MAAA,EAAE,QAAU,EAAA,iBAAA,EAAsB,GAAA,KAAA;AACxC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AACrC,EAAA,MAAM,oBAAoB,CACxB,2BAAA,EAAA,SAAA,CAAU,iBAAkB,CAAA,mBAAmB,KAAK,WACtD,CAAA,CAAA;AAEA,EAAA,uBAEK,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAA,iBAAA,mBACE,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,IAAA,EAAmB,QAAS,CAE7B,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,KAAM,EAAA,eAAA;AAAA,MACN,QAAU,EAAA,iBAAA;AAAA,MACV,OAAQ,EAAA;AAAA,KAAA;AAAA,IAEP;AAAA,GAGP,CAAA;AAEJ;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,8 +11,11 @@ import { ToolbarProps } from '@material-ui/core/Toolbar';
|
|
|
11
11
|
import { TableColumn, TableProps, TableOptions } from '@backstage/core-components';
|
|
12
12
|
import { UserListFilterKind, EntityOwnerPickerProps, EntityListPagination } from '@backstage/plugin-catalog-react';
|
|
13
13
|
import { CSSProperties } from '@material-ui/styles/withStyles';
|
|
14
|
+
import { EntityFilterQuery } from '@backstage/catalog-client';
|
|
14
15
|
import { SearchResultListItemExtensionProps } from '@backstage/plugin-search-react';
|
|
15
16
|
import { ResultHighlight } from '@backstage/plugin-search-common';
|
|
17
|
+
import { Overrides } from '@material-ui/core/styles/overrides';
|
|
18
|
+
import { StyleRules } from '@material-ui/core/styles/withStyles';
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Helper function that gives the children of {@link TechDocsReaderPage} access to techdocs and entity metadata
|
|
@@ -353,6 +356,25 @@ type DocsCardGridProps = {
|
|
|
353
356
|
*/
|
|
354
357
|
declare const DocsCardGrid: (props: DocsCardGridProps) => React__default.JSX.Element | null;
|
|
355
358
|
|
|
359
|
+
/** @public */
|
|
360
|
+
type InfoCardGridClassKey = 'linkSpacer' | 'readMoreLink';
|
|
361
|
+
/**
|
|
362
|
+
* Props for {@link InfoCardGrid}
|
|
363
|
+
*
|
|
364
|
+
* @public
|
|
365
|
+
*/
|
|
366
|
+
type InfoCardGridProps = {
|
|
367
|
+
entities: Entity[] | undefined;
|
|
368
|
+
linkContent?: string | JSX.Element;
|
|
369
|
+
linkDestination?: (entity: Entity) => string | undefined;
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* Component which accepts a list of entities and renders a info card for each entity
|
|
373
|
+
*
|
|
374
|
+
* @public
|
|
375
|
+
*/
|
|
376
|
+
declare const InfoCardGrid: (props: InfoCardGridProps) => React__default.JSX.Element | null;
|
|
377
|
+
|
|
356
378
|
/**
|
|
357
379
|
* Generic representing the metadata structure for a docs table row.
|
|
358
380
|
*
|
|
@@ -467,6 +489,9 @@ type TechDocsIndexPageProps = {
|
|
|
467
489
|
actions?: TableProps<DocsTableRow>['actions'];
|
|
468
490
|
ownerPickerMode?: EntityOwnerPickerProps['mode'];
|
|
469
491
|
pagination?: EntityListPagination;
|
|
492
|
+
options?: TableOptions<DocsTableRow>;
|
|
493
|
+
PageWrapper?: React__default.FC;
|
|
494
|
+
CustomHeader?: React__default.FC;
|
|
470
495
|
};
|
|
471
496
|
|
|
472
497
|
/**
|
|
@@ -488,7 +513,19 @@ declare const DefaultTechDocsHome: (props: TechDocsIndexPageProps) => React__def
|
|
|
488
513
|
*
|
|
489
514
|
* @public
|
|
490
515
|
*/
|
|
491
|
-
type PanelType = 'DocsCardGrid' | 'DocsTable';
|
|
516
|
+
type PanelType = 'DocsCardGrid' | 'DocsTable' | 'TechDocsIndexPage' | 'InfoCardGrid';
|
|
517
|
+
/**
|
|
518
|
+
* Type representing Panel props
|
|
519
|
+
*
|
|
520
|
+
* @public
|
|
521
|
+
*/
|
|
522
|
+
interface PanelProps {
|
|
523
|
+
options?: TableOptions<DocsTableRow>;
|
|
524
|
+
linkContent?: string | JSX.Element;
|
|
525
|
+
linkDestination?: (entity: Entity) => string | undefined;
|
|
526
|
+
PageWrapper?: React__default.FC;
|
|
527
|
+
CustomHeader?: React__default.FC;
|
|
528
|
+
}
|
|
492
529
|
/**
|
|
493
530
|
* Type representing a TechDocsCustomHome panel.
|
|
494
531
|
*
|
|
@@ -500,6 +537,7 @@ interface PanelConfig {
|
|
|
500
537
|
panelType: PanelType;
|
|
501
538
|
panelCSS?: CSSProperties;
|
|
502
539
|
filterPredicate: ((entity: Entity) => boolean) | string;
|
|
540
|
+
panelProps?: PanelProps;
|
|
503
541
|
}
|
|
504
542
|
/**
|
|
505
543
|
* Type representing a TechDocsCustomHome tab.
|
|
@@ -516,6 +554,16 @@ interface TabConfig {
|
|
|
516
554
|
* @public
|
|
517
555
|
*/
|
|
518
556
|
type TabsConfig = TabConfig[];
|
|
557
|
+
/**
|
|
558
|
+
* Component which can be used to render entities in a custom way.
|
|
559
|
+
*
|
|
560
|
+
* @public
|
|
561
|
+
*/
|
|
562
|
+
declare const CustomDocsPanel: ({ config, entities, index, }: {
|
|
563
|
+
config: PanelConfig;
|
|
564
|
+
entities: Entity[];
|
|
565
|
+
index: number;
|
|
566
|
+
}) => React__default.JSX.Element;
|
|
519
567
|
/**
|
|
520
568
|
* Props for {@link TechDocsCustomHome}
|
|
521
569
|
*
|
|
@@ -523,6 +571,8 @@ type TabsConfig = TabConfig[];
|
|
|
523
571
|
*/
|
|
524
572
|
type TechDocsCustomHomeProps = {
|
|
525
573
|
tabsConfig: TabsConfig;
|
|
574
|
+
filter?: EntityFilterQuery;
|
|
575
|
+
CustomPageWrapper?: React__default.FC;
|
|
526
576
|
};
|
|
527
577
|
|
|
528
578
|
/**
|
|
@@ -532,6 +582,9 @@ type TechDocsCustomHomeProps = {
|
|
|
532
582
|
*/
|
|
533
583
|
type TechDocsPageWrapperProps = {
|
|
534
584
|
children?: React__default.ReactNode;
|
|
585
|
+
CustomPageWrapper?: React__default.FC<{
|
|
586
|
+
children?: React__default.ReactNode;
|
|
587
|
+
}>;
|
|
535
588
|
};
|
|
536
589
|
/**
|
|
537
590
|
* Component wrapping a TechDocs page with Page and Header components
|
|
@@ -637,6 +690,19 @@ declare const LegacyEmbeddedDocsRouter: ({ children, withSearch, }: React__defau
|
|
|
637
690
|
withSearch?: boolean | undefined;
|
|
638
691
|
}>) => React__default.JSX.Element;
|
|
639
692
|
|
|
693
|
+
/** @public */
|
|
694
|
+
type CatalogReactComponentsNameToClassKey = {
|
|
695
|
+
BackstageInfoCardGrid: InfoCardGridClassKey;
|
|
696
|
+
};
|
|
697
|
+
/** @public */
|
|
698
|
+
type BackstageOverrides = Overrides & {
|
|
699
|
+
[Name in keyof CatalogReactComponentsNameToClassKey]?: Partial<StyleRules<CatalogReactComponentsNameToClassKey[Name]>>;
|
|
700
|
+
};
|
|
701
|
+
declare module '@backstage/theme' {
|
|
702
|
+
interface OverrideComponentNameToClassKeys extends CatalogReactComponentsNameToClassKey {
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
640
706
|
/**
|
|
641
707
|
* The Backstage plugin that renders technical documentation for your components
|
|
642
708
|
*
|
|
@@ -656,4 +722,4 @@ type DeprecatedTechDocsMetadata = TechDocsMetadata;
|
|
|
656
722
|
*/
|
|
657
723
|
type DeprecatedTechDocsEntityMetadata = TechDocsEntityMetadata;
|
|
658
724
|
|
|
659
|
-
export { type ContentStateTypes, DefaultTechDocsHome, type DefaultTechDocsHomeProps, DocsCardGrid, type DocsCardGridProps, type DocsGroupConfig, DocsTable, type DocsTableProps, type DocsTableRow, LegacyEmbeddedDocsRouter as EmbeddedDocsRouter, EntityListDocsGrid, type EntityListDocsGridPageProps, EntityListDocsTable, type EntityListDocsTableProps, EntityTechdocsContent, type PanelConfig, type PanelType, Reader, type ReaderState, Router, type SyncResult, type TabConfig, type TabsConfig, type TechDocsApi, TechDocsClient, TechDocsCustomHome, type TechDocsCustomHomeProps, type DeprecatedTechDocsEntityMetadata as TechDocsEntityMetadata, TechDocsIndexPage, type TechDocsIndexPageProps, type DeprecatedTechDocsMetadata as TechDocsMetadata, TechDocsPageWrapper, type TechDocsPageWrapperProps, TechDocsPicker, TechDocsReaderLayout, type TechDocsReaderLayoutProps, TechDocsReaderPage, TechDocsReaderPageContent, type TechDocsReaderPageContentProps, TechDocsReaderPageHeader, type TechDocsReaderPageHeaderProps, type TechDocsReaderPageProps, type TechDocsReaderPageRenderFunction, TechDocsReaderPageSubheader, TechDocsReaderProvider, type TechDocsReaderProviderProps, type TechDocsReaderProviderRenderFunction, TechDocsSearch, type TechDocsSearchProps, TechDocsSearchResultListItem, type TechDocsSearchResultListItemProps, type TechDocsStorageApi, TechDocsStorageClient, TechdocsPage, isTechDocsAvailable, techdocsPlugin as plugin, techdocsApiRef, techdocsPlugin, techdocsStorageApiRef };
|
|
725
|
+
export { type BackstageOverrides, type CatalogReactComponentsNameToClassKey, type ContentStateTypes, CustomDocsPanel, DefaultTechDocsHome, type DefaultTechDocsHomeProps, DocsCardGrid, type DocsCardGridProps, type DocsGroupConfig, DocsTable, type DocsTableProps, type DocsTableRow, LegacyEmbeddedDocsRouter as EmbeddedDocsRouter, EntityListDocsGrid, type EntityListDocsGridPageProps, EntityListDocsTable, type EntityListDocsTableProps, EntityTechdocsContent, InfoCardGrid, type InfoCardGridClassKey, type InfoCardGridProps, type PanelConfig, type PanelProps, type PanelType, Reader, type ReaderState, Router, type SyncResult, type TabConfig, type TabsConfig, type TechDocsApi, TechDocsClient, TechDocsCustomHome, type TechDocsCustomHomeProps, type DeprecatedTechDocsEntityMetadata as TechDocsEntityMetadata, TechDocsIndexPage, type TechDocsIndexPageProps, type DeprecatedTechDocsMetadata as TechDocsMetadata, TechDocsPageWrapper, type TechDocsPageWrapperProps, TechDocsPicker, TechDocsReaderLayout, type TechDocsReaderLayoutProps, TechDocsReaderPage, TechDocsReaderPageContent, type TechDocsReaderPageContentProps, TechDocsReaderPageHeader, type TechDocsReaderPageHeaderProps, type TechDocsReaderPageProps, type TechDocsReaderPageRenderFunction, TechDocsReaderPageSubheader, TechDocsReaderProvider, type TechDocsReaderProviderProps, type TechDocsReaderProviderRenderFunction, TechDocsSearch, type TechDocsSearchProps, TechDocsSearchResultListItem, type TechDocsSearchResultListItemProps, type TechDocsStorageApi, TechDocsStorageClient, TechdocsPage, isTechDocsAvailable, techdocsPlugin as plugin, techdocsApiRef, techdocsPlugin, techdocsStorageApiRef };
|
package/dist/index.esm.js
CHANGED
|
@@ -8,9 +8,11 @@ export { TechDocsReaderPageSubheader } from './reader/components/TechDocsReaderP
|
|
|
8
8
|
export { TechDocsSearch } from './search/components/TechDocsSearch.esm.js';
|
|
9
9
|
export { EntityListDocsGrid } from './home/components/Grids/EntityListDocsGrid.esm.js';
|
|
10
10
|
export { DocsCardGrid } from './home/components/Grids/DocsCardGrid.esm.js';
|
|
11
|
+
export { InfoCardGrid } from './home/components/Grids/InfoCardGrid.esm.js';
|
|
11
12
|
export { EntityListDocsTable } from './home/components/Tables/EntityListDocsTable.esm.js';
|
|
12
13
|
export { DocsTable } from './home/components/Tables/DocsTable.esm.js';
|
|
13
14
|
export { DefaultTechDocsHome } from './home/components/DefaultTechDocsHome.esm.js';
|
|
15
|
+
export { CustomDocsPanel } from './home/components/TechDocsCustomHome.esm.js';
|
|
14
16
|
export { TechDocsPageWrapper } from './home/components/TechDocsPageWrapper.esm.js';
|
|
15
17
|
export { TechDocsPicker } from './home/components/TechDocsPicker.esm.js';
|
|
16
18
|
export { EntityTechdocsContent, TechDocsCustomHome, TechDocsIndexPage, TechDocsReaderPage, TechDocsSearchResultListItem, TechdocsPage, techdocsPlugin as plugin, techdocsPlugin } from './plugin.esm.js';
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect } from 'react';
|
|
2
2
|
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
|
3
3
|
import { useTheme } from '@material-ui/core/styles';
|
|
4
|
-
import { useAnalytics, useApi } from '@backstage/core-plugin-api';
|
|
4
|
+
import { useAnalytics, useApi, configApiRef } from '@backstage/core-plugin-api';
|
|
5
5
|
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
|
6
6
|
import { techdocsStorageApiRef, useShadowDomStylesLoading } from '@backstage/plugin-techdocs-react';
|
|
7
7
|
import { useTechDocsReader } from '../TechDocsReaderProvider.esm.js';
|
|
@@ -32,6 +32,7 @@ const useTechDocsReaderDom = (entityRef) => {
|
|
|
32
32
|
const analytics = useAnalytics();
|
|
33
33
|
const techdocsStorageApi = useApi(techdocsStorageApiRef);
|
|
34
34
|
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
|
35
|
+
const configApi = useApi(configApiRef);
|
|
35
36
|
const { state, path, content: rawPage } = useTechDocsReader();
|
|
36
37
|
const { "*": currPath = "" } = useParams();
|
|
37
38
|
const [dom, setDom] = useState(null);
|
|
@@ -126,7 +127,7 @@ const useTechDocsReaderDom = (entityRef) => {
|
|
|
126
127
|
scrollIntoNavigation(),
|
|
127
128
|
copyToClipboard(theme),
|
|
128
129
|
addLinkClickListener({
|
|
129
|
-
baseUrl: window.location.origin,
|
|
130
|
+
baseUrl: configApi.getOptionalString("app.baseUrl") || window.location.origin,
|
|
130
131
|
onClick: (event, url) => {
|
|
131
132
|
const modifierActive = event.ctrlKey || event.metaKey;
|
|
132
133
|
const parsedUrl = new URL(url);
|
|
@@ -179,7 +180,7 @@ const useTechDocsReaderDom = (entityRef) => {
|
|
|
179
180
|
}
|
|
180
181
|
})
|
|
181
182
|
]),
|
|
182
|
-
[theme, navigate, analytics, entityRef.name]
|
|
183
|
+
[theme, navigate, analytics, entityRef.name, configApi]
|
|
183
184
|
);
|
|
184
185
|
useEffect(() => {
|
|
185
186
|
if (!rawPage) return () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.esm.js","sources":["../../../../src/reader/components/TechDocsReaderPageContent/dom.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { useTheme } from '@material-ui/core/styles';\n\nimport { CompoundEntityRef } from '@backstage/catalog-model';\nimport { useAnalytics, useApi } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nimport {\n techdocsStorageApiRef,\n useShadowDomStylesLoading,\n} from '@backstage/plugin-techdocs-react';\n\nimport { useTechDocsReader } from '../TechDocsReaderProvider';\n\nimport {\n addBaseUrl,\n addGitFeedbackLink,\n addLinkClickListener,\n addSidebarToggle,\n onCssReady,\n removeMkdocsHeader,\n rewriteDocLinks,\n simplifyMkdocsFooter,\n scrollIntoNavigation,\n transform as transformer,\n copyToClipboard,\n useSanitizerTransformer,\n useStylesTransformer,\n handleMetaRedirects,\n} from '../../transformers';\nimport { useNavigateUrl } from './useNavigateUrl';\nimport { useParams } from 'react-router-dom';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';\n\n/**\n * Hook that encapsulates the behavior of getting raw HTML and applying\n * transforms to it in order to make it function at a basic level in the\n * Backstage UI.\n */\nexport const useTechDocsReaderDom = (\n entityRef: CompoundEntityRef,\n): Element | null => {\n const navigate = useNavigateUrl();\n const theme = useTheme();\n const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY);\n const sanitizerTransformer = useSanitizerTransformer();\n const stylesTransformer = useStylesTransformer();\n const analytics = useAnalytics();\n\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n\n const { state, path, content: rawPage } = useTechDocsReader();\n const { '*': currPath = '' } = useParams();\n\n const [dom, setDom] = useState<HTMLElement | null>(null);\n const isStyleLoading = useShadowDomStylesLoading(dom);\n\n const updateSidebarPositionAndHeight = useCallback(() => {\n if (!dom) return;\n\n const sidebars = dom.querySelectorAll<HTMLElement>('.md-sidebar');\n\n sidebars.forEach(element => {\n // set sidebar position to render in correct position\n if (isMobileMedia) {\n element.style.top = '0px';\n } else {\n const page = document?.querySelector('.techdocs-reader-page');\n const pageTop = page?.getBoundingClientRect().top ?? 0;\n let domTop = dom.getBoundingClientRect().top ?? 0;\n\n const tabs = dom.querySelector('.md-container > .md-tabs');\n const tabsHeight = tabs?.getBoundingClientRect().height ?? 0;\n\n // the sidebars should not scroll beyond the total height of the header and tabs\n if (domTop < pageTop) {\n domTop = pageTop;\n }\n\n const scrollbarTopPx = Math.max(domTop, 0) + tabsHeight;\n\n element.style.top = `${scrollbarTopPx}px`;\n\n // set scrollbar height to ensure all links can be seen when content is small\n const footer = dom.querySelector('.md-container > .md-footer');\n // if no footer, fallback to using the bottom of the window\n const scrollbarEndPx =\n footer?.getBoundingClientRect().top ?? window.innerHeight;\n\n element.style.height = `${scrollbarEndPx - scrollbarTopPx}px`;\n }\n\n // show the sidebar only after updating its position\n element.style.setProperty('opacity', '1');\n });\n }, [dom, isMobileMedia]);\n\n useEffect(() => {\n window.addEventListener('resize', updateSidebarPositionAndHeight);\n window.addEventListener('scroll', updateSidebarPositionAndHeight, true);\n return () => {\n window.removeEventListener('resize', updateSidebarPositionAndHeight);\n window.removeEventListener(\n 'scroll',\n updateSidebarPositionAndHeight,\n true,\n );\n };\n }, [dom, updateSidebarPositionAndHeight]);\n\n // dynamically set width of footer to accommodate for pinning of the sidebar\n const updateFooterWidth = useCallback(() => {\n if (!dom) return;\n const footer = dom.querySelector<HTMLElement>('.md-footer');\n if (footer) {\n footer.style.width = `${dom.getBoundingClientRect().width}px`;\n }\n }, [dom]);\n\n useEffect(() => {\n window.addEventListener('resize', updateFooterWidth);\n return () => {\n window.removeEventListener('resize', updateFooterWidth);\n };\n }, [dom, updateFooterWidth]);\n\n // an update to \"state\" might lead to an updated UI so we include it as a trigger\n useEffect(() => {\n if (!isStyleLoading) {\n updateFooterWidth();\n updateSidebarPositionAndHeight();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n state,\n isStyleLoading,\n updateFooterWidth,\n updateSidebarPositionAndHeight,\n ]);\n\n // a function that performs transformations that are executed prior to adding it to the DOM\n const preRender = useCallback(\n (rawContent: string, contentPath: string) =>\n transformer(rawContent, [\n sanitizerTransformer,\n addBaseUrl({\n techdocsStorageApi,\n entityId: entityRef,\n path: contentPath,\n }),\n rewriteDocLinks(),\n addSidebarToggle(),\n removeMkdocsHeader(),\n simplifyMkdocsFooter(),\n addGitFeedbackLink(scmIntegrationsApi),\n stylesTransformer,\n ]),\n [\n // only add dependencies that are in state or memorized variables to avoid unnecessary calls between re-renders\n entityRef,\n scmIntegrationsApi,\n techdocsStorageApi,\n sanitizerTransformer,\n stylesTransformer,\n ],\n );\n\n // a function that performs transformations that are executed after adding it to the DOM\n const postRender = useCallback(\n async (transformedElement: Element) =>\n transformer(transformedElement, [\n handleMetaRedirects(navigate, entityRef.name),\n scrollIntoNavigation(),\n copyToClipboard(theme),\n addLinkClickListener({\n baseUrl: window.location.origin,\n onClick: (event: MouseEvent, url: string) => {\n // detect if CTRL or META keys are pressed so that links can be opened in a new tab with `window.open`\n const modifierActive = event.ctrlKey || event.metaKey;\n const parsedUrl = new URL(url);\n\n // capture link clicks within documentation\n const linkText =\n (event.target as HTMLAnchorElement | undefined)?.innerText || url;\n const to = url.replace(window.location.origin, '');\n analytics.captureEvent('click', linkText, { attributes: { to } });\n\n // hash exists when anchor is clicked on secondary sidebar\n if (parsedUrl.hash) {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n // If it's in a different page, we navigate to it\n if (window.location.pathname !== parsedUrl.pathname) {\n navigate(url);\n } else {\n // If it's in the same page we avoid using navigate that causes\n // the page to rerender.\n window.history.pushState(\n null,\n document.title,\n parsedUrl.hash,\n );\n }\n // Scroll to hash if it's on the current page\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.scrollIntoView();\n }\n } else {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n navigate(url);\n }\n }\n },\n }),\n // disable MkDocs drawer toggling ('for' attribute => checkbox mechanism)\n onCssReady({\n onLoading: () => {},\n onLoaded: () => {\n transformedElement\n .querySelector('.md-nav__title')\n ?.removeAttribute('for');\n },\n }),\n // hide sidebars until their positions are updated\n onCssReady({\n onLoading: () => {\n const sidebars = Array.from(\n transformedElement.querySelectorAll<HTMLElement>('.md-sidebar'),\n );\n sidebars.forEach(element => {\n element.style.setProperty('opacity', '0');\n });\n },\n onLoaded: () => {},\n }),\n ]),\n [theme, navigate, analytics, entityRef.name],\n );\n\n useEffect(() => {\n if (!rawPage) return () => {};\n\n // if false, there is already a newer execution of this effect\n let shouldReplaceContent = true;\n\n // Pre-render\n preRender(rawPage, path).then(async preTransformedDomElement => {\n if (!preTransformedDomElement?.innerHTML) {\n return; // An unexpected error occurred\n }\n\n // don't manipulate the shadow dom if this isn't the latest effect execution\n if (!shouldReplaceContent) {\n return;\n }\n\n // Skip this update if the location's path has changed but the state\n // contains a page that isn't loaded yet.\n if (currPath !== path) {\n return;\n }\n\n // Scroll to top after render\n window.scroll({ top: 0 });\n\n // Post-render\n const postTransformedDomElement = await postRender(\n preTransformedDomElement,\n );\n\n setDom(postTransformedDomElement as HTMLElement);\n });\n\n // cancel this execution\n return () => {\n shouldReplaceContent = false;\n };\n }, [rawPage, currPath, path, preRender, postRender]);\n\n return dom;\n};\n"],"names":["transformer"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dom.esm.js","sources":["../../../../src/reader/components/TechDocsReaderPageContent/dom.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { useTheme } from '@material-ui/core/styles';\n\nimport { CompoundEntityRef } from '@backstage/catalog-model';\nimport { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nimport {\n techdocsStorageApiRef,\n useShadowDomStylesLoading,\n} from '@backstage/plugin-techdocs-react';\n\nimport { useTechDocsReader } from '../TechDocsReaderProvider';\n\nimport {\n addBaseUrl,\n addGitFeedbackLink,\n addLinkClickListener,\n addSidebarToggle,\n onCssReady,\n removeMkdocsHeader,\n rewriteDocLinks,\n simplifyMkdocsFooter,\n scrollIntoNavigation,\n transform as transformer,\n copyToClipboard,\n useSanitizerTransformer,\n useStylesTransformer,\n handleMetaRedirects,\n} from '../../transformers';\nimport { useNavigateUrl } from './useNavigateUrl';\nimport { useParams } from 'react-router-dom';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 76.1875em)';\n\n/**\n * Hook that encapsulates the behavior of getting raw HTML and applying\n * transforms to it in order to make it function at a basic level in the\n * Backstage UI.\n */\nexport const useTechDocsReaderDom = (\n entityRef: CompoundEntityRef,\n): Element | null => {\n const navigate = useNavigateUrl();\n const theme = useTheme();\n const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY);\n const sanitizerTransformer = useSanitizerTransformer();\n const stylesTransformer = useStylesTransformer();\n const analytics = useAnalytics();\n\n const techdocsStorageApi = useApi(techdocsStorageApiRef);\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const configApi = useApi(configApiRef);\n\n const { state, path, content: rawPage } = useTechDocsReader();\n const { '*': currPath = '' } = useParams();\n\n const [dom, setDom] = useState<HTMLElement | null>(null);\n const isStyleLoading = useShadowDomStylesLoading(dom);\n\n const updateSidebarPositionAndHeight = useCallback(() => {\n if (!dom) return;\n\n const sidebars = dom.querySelectorAll<HTMLElement>('.md-sidebar');\n\n sidebars.forEach(element => {\n // set sidebar position to render in correct position\n if (isMobileMedia) {\n element.style.top = '0px';\n } else {\n const page = document?.querySelector('.techdocs-reader-page');\n const pageTop = page?.getBoundingClientRect().top ?? 0;\n let domTop = dom.getBoundingClientRect().top ?? 0;\n\n const tabs = dom.querySelector('.md-container > .md-tabs');\n const tabsHeight = tabs?.getBoundingClientRect().height ?? 0;\n\n // the sidebars should not scroll beyond the total height of the header and tabs\n if (domTop < pageTop) {\n domTop = pageTop;\n }\n\n const scrollbarTopPx = Math.max(domTop, 0) + tabsHeight;\n\n element.style.top = `${scrollbarTopPx}px`;\n\n // set scrollbar height to ensure all links can be seen when content is small\n const footer = dom.querySelector('.md-container > .md-footer');\n // if no footer, fallback to using the bottom of the window\n const scrollbarEndPx =\n footer?.getBoundingClientRect().top ?? window.innerHeight;\n\n element.style.height = `${scrollbarEndPx - scrollbarTopPx}px`;\n }\n\n // show the sidebar only after updating its position\n element.style.setProperty('opacity', '1');\n });\n }, [dom, isMobileMedia]);\n\n useEffect(() => {\n window.addEventListener('resize', updateSidebarPositionAndHeight);\n window.addEventListener('scroll', updateSidebarPositionAndHeight, true);\n return () => {\n window.removeEventListener('resize', updateSidebarPositionAndHeight);\n window.removeEventListener(\n 'scroll',\n updateSidebarPositionAndHeight,\n true,\n );\n };\n }, [dom, updateSidebarPositionAndHeight]);\n\n // dynamically set width of footer to accommodate for pinning of the sidebar\n const updateFooterWidth = useCallback(() => {\n if (!dom) return;\n const footer = dom.querySelector<HTMLElement>('.md-footer');\n if (footer) {\n footer.style.width = `${dom.getBoundingClientRect().width}px`;\n }\n }, [dom]);\n\n useEffect(() => {\n window.addEventListener('resize', updateFooterWidth);\n return () => {\n window.removeEventListener('resize', updateFooterWidth);\n };\n }, [dom, updateFooterWidth]);\n\n // an update to \"state\" might lead to an updated UI so we include it as a trigger\n useEffect(() => {\n if (!isStyleLoading) {\n updateFooterWidth();\n updateSidebarPositionAndHeight();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n state,\n isStyleLoading,\n updateFooterWidth,\n updateSidebarPositionAndHeight,\n ]);\n\n // a function that performs transformations that are executed prior to adding it to the DOM\n const preRender = useCallback(\n (rawContent: string, contentPath: string) =>\n transformer(rawContent, [\n sanitizerTransformer,\n addBaseUrl({\n techdocsStorageApi,\n entityId: entityRef,\n path: contentPath,\n }),\n rewriteDocLinks(),\n addSidebarToggle(),\n removeMkdocsHeader(),\n simplifyMkdocsFooter(),\n addGitFeedbackLink(scmIntegrationsApi),\n stylesTransformer,\n ]),\n [\n // only add dependencies that are in state or memorized variables to avoid unnecessary calls between re-renders\n entityRef,\n scmIntegrationsApi,\n techdocsStorageApi,\n sanitizerTransformer,\n stylesTransformer,\n ],\n );\n\n // a function that performs transformations that are executed after adding it to the DOM\n const postRender = useCallback(\n async (transformedElement: Element) =>\n transformer(transformedElement, [\n handleMetaRedirects(navigate, entityRef.name),\n scrollIntoNavigation(),\n copyToClipboard(theme),\n addLinkClickListener({\n baseUrl:\n configApi.getOptionalString('app.baseUrl') ||\n window.location.origin,\n onClick: (event: MouseEvent, url: string) => {\n // detect if CTRL or META keys are pressed so that links can be opened in a new tab with `window.open`\n const modifierActive = event.ctrlKey || event.metaKey;\n const parsedUrl = new URL(url);\n\n // capture link clicks within documentation\n const linkText =\n (event.target as HTMLAnchorElement | undefined)?.innerText || url;\n const to = url.replace(window.location.origin, '');\n analytics.captureEvent('click', linkText, { attributes: { to } });\n\n // hash exists when anchor is clicked on secondary sidebar\n if (parsedUrl.hash) {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n // If it's in a different page, we navigate to it\n if (window.location.pathname !== parsedUrl.pathname) {\n navigate(url);\n } else {\n // If it's in the same page we avoid using navigate that causes\n // the page to rerender.\n window.history.pushState(\n null,\n document.title,\n parsedUrl.hash,\n );\n }\n // Scroll to hash if it's on the current page\n transformedElement\n ?.querySelector(`[id=\"${parsedUrl.hash.slice(1)}\"]`)\n ?.scrollIntoView();\n }\n } else {\n if (modifierActive) {\n window.open(url, '_blank');\n } else {\n navigate(url);\n }\n }\n },\n }),\n // disable MkDocs drawer toggling ('for' attribute => checkbox mechanism)\n onCssReady({\n onLoading: () => {},\n onLoaded: () => {\n transformedElement\n .querySelector('.md-nav__title')\n ?.removeAttribute('for');\n },\n }),\n // hide sidebars until their positions are updated\n onCssReady({\n onLoading: () => {\n const sidebars = Array.from(\n transformedElement.querySelectorAll<HTMLElement>('.md-sidebar'),\n );\n sidebars.forEach(element => {\n element.style.setProperty('opacity', '0');\n });\n },\n onLoaded: () => {},\n }),\n ]),\n [theme, navigate, analytics, entityRef.name, configApi],\n );\n\n useEffect(() => {\n if (!rawPage) return () => {};\n\n // if false, there is already a newer execution of this effect\n let shouldReplaceContent = true;\n\n // Pre-render\n preRender(rawPage, path).then(async preTransformedDomElement => {\n if (!preTransformedDomElement?.innerHTML) {\n return; // An unexpected error occurred\n }\n\n // don't manipulate the shadow dom if this isn't the latest effect execution\n if (!shouldReplaceContent) {\n return;\n }\n\n // Skip this update if the location's path has changed but the state\n // contains a page that isn't loaded yet.\n if (currPath !== path) {\n return;\n }\n\n // Scroll to top after render\n window.scroll({ top: 0 });\n\n // Post-render\n const postTransformedDomElement = await postRender(\n preTransformedDomElement,\n );\n\n setDom(postTransformedDomElement as HTMLElement);\n });\n\n // cancel this execution\n return () => {\n shouldReplaceContent = false;\n };\n }, [rawPage, currPath, path, preRender, postRender]);\n\n return dom;\n};\n"],"names":["transformer"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-techdocs",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.2-next.0",
|
|
4
4
|
"description": "The Backstage plugin that renders technical documentation for your components",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "frontend-plugin",
|
|
@@ -68,21 +68,22 @@
|
|
|
68
68
|
"test": "backstage-cli package test"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@backstage/catalog-
|
|
72
|
-
"@backstage/
|
|
73
|
-
"@backstage/
|
|
74
|
-
"@backstage/core-
|
|
75
|
-
"@backstage/core-
|
|
76
|
-
"@backstage/
|
|
77
|
-
"@backstage/
|
|
78
|
-
"@backstage/
|
|
79
|
-
"@backstage/integration
|
|
80
|
-
"@backstage/
|
|
81
|
-
"@backstage/plugin-
|
|
82
|
-
"@backstage/plugin-
|
|
83
|
-
"@backstage/plugin-search-
|
|
71
|
+
"@backstage/catalog-client": "1.9.1",
|
|
72
|
+
"@backstage/catalog-model": "1.7.3",
|
|
73
|
+
"@backstage/config": "1.3.2",
|
|
74
|
+
"@backstage/core-compat-api": "0.3.6-next.0",
|
|
75
|
+
"@backstage/core-components": "0.16.3",
|
|
76
|
+
"@backstage/core-plugin-api": "1.10.3",
|
|
77
|
+
"@backstage/errors": "1.2.7",
|
|
78
|
+
"@backstage/frontend-plugin-api": "0.9.5-next.0",
|
|
79
|
+
"@backstage/integration": "1.16.1",
|
|
80
|
+
"@backstage/integration-react": "1.2.3",
|
|
81
|
+
"@backstage/plugin-auth-react": "0.1.11",
|
|
82
|
+
"@backstage/plugin-catalog-react": "1.15.2-next.0",
|
|
83
|
+
"@backstage/plugin-search-common": "1.2.17",
|
|
84
|
+
"@backstage/plugin-search-react": "1.8.6-next.0",
|
|
84
85
|
"@backstage/plugin-techdocs-common": "0.1.0",
|
|
85
|
-
"@backstage/plugin-techdocs-react": "1.2.13
|
|
86
|
+
"@backstage/plugin-techdocs-react": "1.2.13",
|
|
86
87
|
"@backstage/theme": "0.6.3",
|
|
87
88
|
"@material-ui/core": "^4.12.2",
|
|
88
89
|
"@material-ui/icons": "^4.9.1",
|
|
@@ -97,11 +98,12 @@
|
|
|
97
98
|
"react-use": "^17.2.4"
|
|
98
99
|
},
|
|
99
100
|
"devDependencies": {
|
|
100
|
-
"@backstage/cli": "0.
|
|
101
|
-
"@backstage/core-app-api": "1.15.4
|
|
102
|
-
"@backstage/dev-utils": "1.1.
|
|
103
|
-
"@backstage/plugin-
|
|
104
|
-
"@backstage/
|
|
101
|
+
"@backstage/cli": "0.30.0-next.0",
|
|
102
|
+
"@backstage/core-app-api": "1.15.4",
|
|
103
|
+
"@backstage/dev-utils": "1.1.7-next.0",
|
|
104
|
+
"@backstage/plugin-catalog": "1.26.2-next.0",
|
|
105
|
+
"@backstage/plugin-techdocs-module-addons-contrib": "1.1.20",
|
|
106
|
+
"@backstage/test-utils": "1.7.4",
|
|
105
107
|
"@testing-library/dom": "^10.0.0",
|
|
106
108
|
"@testing-library/jest-dom": "^6.0.0",
|
|
107
109
|
"@testing-library/react": "^16.0.0",
|