@backstage/plugin-techdocs 0.0.0-nightly-202201323044 → 0.0.0-nightly-20220203021748

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 CHANGED
@@ -1,23 +1,178 @@
1
1
  # @backstage/plugin-techdocs
2
2
 
3
- ## 0.0.0-nightly-202201323044
3
+ ## 0.0.0-nightly-20220203021748
4
+
5
+ ### Patch Changes
6
+
7
+ - 742434a6ba: Fixed a bug where links to files within a TechDocs site that use the `download` attribute would result in a 404 in cases where the TechDocs backend and Backstage frontend application are on the same host.
8
+ - 359c31e31d: Added support for documentation using the raw `<source>` tag to point to relative resources like audio or video files.
9
+ - 18317a08db: Fixed a bug where copy-to-clipboard buttons were appended to unintended elements.
10
+ - Updated dependencies
11
+ - @backstage/core-components@0.0.0-nightly-20220203021748
12
+ - @backstage/plugin-catalog-react@0.0.0-nightly-20220203021748
13
+ - @backstage/integration-react@0.0.0-nightly-20220203021748
14
+ - @backstage/plugin-catalog@0.0.0-nightly-20220203021748
15
+ - @backstage/plugin-search@0.0.0-nightly-20220203021748
16
+
17
+ ## 0.13.2-next.1
18
+
19
+ ### Patch Changes
20
+
21
+ - 742434a6ba: Fixed a bug where links to files within a TechDocs site that use the `download` attribute would result in a 404 in cases where the TechDocs backend and Backstage frontend application are on the same host.
22
+ - Updated dependencies
23
+ - @backstage/core-components@0.8.7-next.1
24
+ - @backstage/plugin-catalog-react@0.6.13-next.1
25
+ - @backstage/plugin-catalog@0.7.11-next.1
26
+
27
+ ## 0.13.2-next.0
28
+
29
+ ### Patch Changes
30
+
31
+ - 359c31e31d: Added support for documentation using the raw `<source>` tag to point to relative resources like audio or video files.
32
+ - Updated dependencies
33
+ - @backstage/core-components@0.8.7-next.0
34
+ - @backstage/integration-react@0.1.20-next.0
35
+ - @backstage/plugin-catalog@0.7.11-next.0
36
+ - @backstage/plugin-catalog-react@0.6.13-next.0
37
+ - @backstage/plugin-search@0.6.1-next.0
38
+
39
+ ## 0.13.1
40
+
41
+ ### Patch Changes
42
+
43
+ - bdc53553eb: chore(deps): bump `react-text-truncate` from 0.16.0 to 0.17.0
44
+ - a64f99f734: Code snippets now include a "copy to clipboard" button.
45
+ - Updated dependencies
46
+ - @backstage/core-components@0.8.6
47
+ - @backstage/plugin-search@0.6.0
48
+ - @backstage/plugin-catalog@0.7.10
49
+
50
+ ## 0.13.0
51
+
52
+ ### Minor Changes
53
+
54
+ - aecfe4f403: Make `TechDocsClient` and `TechDocsStorageClient` use the `FetchApi`. You now
55
+ need to pass in an instance of that API when constructing the client, if you
56
+ create a custom instance in your app.
57
+
58
+ If you are replacing the factory:
59
+
60
+ ```diff
61
+ +import { fetchApiRef } from '@backstage/core-plugin-api';
62
+
63
+ createApiFactory({
64
+ api: techdocsStorageApiRef,
65
+ deps: {
66
+ configApi: configApiRef,
67
+ discoveryApi: discoveryApiRef,
68
+ identityApi: identityApiRef,
69
+ + fetchApi: fetchApiRef,
70
+ },
71
+ factory: ({
72
+ configApi,
73
+ discoveryApi,
74
+ identityApi,
75
+ + fetchApi,
76
+ }) =>
77
+ new TechDocsStorageClient({
78
+ configApi,
79
+ discoveryApi,
80
+ identityApi,
81
+ + fetchApi,
82
+ }),
83
+ }),
84
+ createApiFactory({
85
+ api: techdocsApiRef,
86
+ deps: {
87
+ configApi: configApiRef,
88
+ discoveryApi: discoveryApiRef,
89
+ - identityApi: identityApiRef,
90
+ + fetchApi: fetchApiRef,
91
+ },
92
+ factory: ({
93
+ configApi,
94
+ discoveryApi,
95
+ - identityApi,
96
+ + fetchApi,
97
+ }) =>
98
+ new TechDocsClient({
99
+ configApi,
100
+ discoveryApi,
101
+ - identityApi,
102
+ + fetchApi,
103
+ }),
104
+ }),
105
+ ```
106
+
107
+ If instantiating directly:
108
+
109
+ ```diff
110
+ +import { fetchApiRef } from '@backstage/core-plugin-api';
111
+
112
+ +const fetchApi = useApi(fetchApiRef);
113
+ const storageClient = new TechDocsStorageClient({
114
+ configApi,
115
+ discoveryApi,
116
+ identityApi,
117
+ + fetchApi,
118
+ });
119
+ const techdocsClient = new TechDocsClient({
120
+ configApi,
121
+ discoveryApi,
122
+ - identityApi,
123
+ + fetchApi,
124
+ }),
125
+ ```
126
+
127
+ ### Patch Changes
128
+
129
+ - 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
130
+ - 29710c91c2: use lighter color for block quotes and horizontal rulers
131
+ - Updated dependencies
132
+ - @backstage/core-components@0.8.5
133
+ - @backstage/integration@0.7.2
134
+ - @backstage/plugin-search@0.5.6
135
+ - @backstage/core-plugin-api@0.6.0
136
+ - @backstage/plugin-catalog@0.7.9
137
+ - @backstage/plugin-catalog-react@0.6.12
138
+ - @backstage/config@0.1.13
139
+ - @backstage/catalog-model@0.9.10
140
+ - @backstage/integration-react@0.1.19
141
+
142
+ ## 0.12.15-next.0
143
+
144
+ ### Patch Changes
145
+
146
+ - 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
147
+ - 29710c91c2: use lighter color for block quotes and horizontal rulers
148
+ - Updated dependencies
149
+ - @backstage/core-components@0.8.5-next.0
150
+ - @backstage/core-plugin-api@0.6.0-next.0
151
+ - @backstage/plugin-catalog@0.7.9-next.0
152
+ - @backstage/config@0.1.13-next.0
153
+ - @backstage/plugin-catalog-react@0.6.12-next.0
154
+ - @backstage/plugin-search@0.5.6-next.0
155
+ - @backstage/catalog-model@0.9.10-next.0
156
+ - @backstage/integration-react@0.1.19-next.0
157
+ - @backstage/integration@0.7.2-next.0
158
+
159
+ ## 0.12.14
4
160
 
5
161
  ### Patch Changes
6
162
 
7
163
  - 5333451def: Cleaned up API exports
8
164
  - 1628ca3f49: Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes
9
165
  - Updated dependencies
10
- - @backstage/config@0.0.0-nightly-202201323044
11
- - @backstage/integration@0.0.0-nightly-202201323044
12
- - @backstage/core-components@0.0.0-nightly-202201323044
13
- - @backstage/core-plugin-api@0.0.0-nightly-202201323044
14
- - @backstage/plugin-catalog-react@0.0.0-nightly-202201323044
15
- - @backstage/errors@0.0.0-nightly-202201323044
16
- - @backstage/catalog-model@0.0.0-nightly-202201323044
17
- - @backstage/integration-react@0.0.0-nightly-202201323044
18
- - @backstage/theme@0.0.0-nightly-202201323044
19
- - @backstage/plugin-catalog@0.0.0-nightly-202201323044
20
- - @backstage/plugin-search@0.0.0-nightly-202201323044
166
+ - @backstage/config@0.1.12
167
+ - @backstage/integration@0.7.1
168
+ - @backstage/core-components@0.8.4
169
+ - @backstage/core-plugin-api@0.5.0
170
+ - @backstage/plugin-catalog-react@0.6.11
171
+ - @backstage/errors@0.2.0
172
+ - @backstage/catalog-model@0.9.9
173
+ - @backstage/integration-react@0.1.18
174
+ - @backstage/plugin-catalog@0.7.8
175
+ - @backstage/plugin-search@0.5.5
21
176
 
22
177
  ## 0.12.13
23
178
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
- import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
3
+ import { DiscoveryApi, FetchApi, IdentityApi } from '@backstage/core-plugin-api';
4
4
  import * as _backstage_catalog_model from '@backstage/catalog-model';
5
5
  import { Entity, LocationSpec, EntityName } from '@backstage/catalog-model';
6
6
  import { Config } from '@backstage/config';
@@ -19,10 +19,33 @@ declare type TechDocsEntityMetadata = Entity & {
19
19
  locationMetadata?: LocationSpec;
20
20
  };
21
21
 
22
+ /**
23
+ * Utility API reference for the {@link TechDocsStorageApi}.
24
+ *
25
+ * @public
26
+ */
22
27
  declare const techdocsStorageApiRef: _backstage_core_plugin_api.ApiRef<TechDocsStorageApi>;
28
+ /**
29
+ * Utility API reference for the {@link TechDocsApi}.
30
+ *
31
+ * @public
32
+ */
23
33
  declare const techdocsApiRef: _backstage_core_plugin_api.ApiRef<TechDocsApi>;
34
+ /**
35
+ * The outcome of a docs sync operation.
36
+ *
37
+ * @public
38
+ */
24
39
  declare type SyncResult = 'cached' | 'updated';
40
+ /**
41
+ * API which talks to TechDocs storage to fetch files to render.
42
+ *
43
+ * @public
44
+ */
25
45
  interface TechDocsStorageApi {
46
+ /**
47
+ * Set to techdocs.requestUrl as the URL for techdocs-backend API.
48
+ */
26
49
  getApiOrigin(): Promise<string>;
27
50
  getStorageUrl(): Promise<string>;
28
51
  getBuilder(): Promise<string>;
@@ -30,7 +53,15 @@ interface TechDocsStorageApi {
30
53
  syncEntityDocs(entityId: EntityName, logHandler?: (line: string) => void): Promise<SyncResult>;
31
54
  getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): Promise<string>;
32
55
  }
56
+ /**
57
+ * API to talk to techdocs-backend.
58
+ *
59
+ * @public
60
+ */
33
61
  interface TechDocsApi {
62
+ /**
63
+ * Set to techdocs.requestUrl as the URL for techdocs-backend API.
64
+ */
34
65
  getApiOrigin(): Promise<string>;
35
66
  getTechDocsMetadata(entityId: EntityName): Promise<TechDocsMetadata>;
36
67
  getEntityMetadata(entityId: EntityName): Promise<TechDocsEntityMetadata>;
@@ -38,15 +69,17 @@ interface TechDocsApi {
38
69
 
39
70
  /**
40
71
  * API to talk to `techdocs-backend`.
72
+ *
73
+ * @public
41
74
  */
42
75
  declare class TechDocsClient implements TechDocsApi {
43
76
  configApi: Config;
44
77
  discoveryApi: DiscoveryApi;
45
- identityApi: IdentityApi;
46
- constructor({ configApi, discoveryApi, identityApi, }: {
78
+ private fetchApi;
79
+ constructor(options: {
47
80
  configApi: Config;
48
81
  discoveryApi: DiscoveryApi;
49
- identityApi: IdentityApi;
82
+ fetchApi: FetchApi;
50
83
  });
51
84
  getApiOrigin(): Promise<string>;
52
85
  /**
@@ -71,15 +104,19 @@ declare class TechDocsClient implements TechDocsApi {
71
104
  }
72
105
  /**
73
106
  * API which talks to TechDocs storage to fetch files to render.
107
+ *
108
+ * @public
74
109
  */
75
110
  declare class TechDocsStorageClient implements TechDocsStorageApi {
76
111
  configApi: Config;
77
112
  discoveryApi: DiscoveryApi;
78
113
  identityApi: IdentityApi;
79
- constructor({ configApi, discoveryApi, identityApi, }: {
114
+ private fetchApi;
115
+ constructor(options: {
80
116
  configApi: Config;
81
117
  discoveryApi: DiscoveryApi;
82
118
  identityApi: IdentityApi;
119
+ fetchApi: FetchApi;
83
120
  });
84
121
  getApiOrigin(): Promise<string>;
85
122
  getStorageUrl(): Promise<string>;
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createApiRef, createRouteRef, useRouteRef, useApi, configApiRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, createRoutableExtension, createComponentExtension } from '@backstage/core-plugin-api';
1
+ import { createApiRef, createRouteRef, useRouteRef, useApi, configApiRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, fetchApiRef, createRoutableExtension, createComponentExtension } from '@backstage/core-plugin-api';
2
2
  import { ResponseError, NotFoundError } from '@backstage/errors';
3
3
  import { EventSourcePolyfill } from 'event-source-polyfill';
4
4
  import React, { useEffect, useState, useReducer, useRef, useMemo, createContext, useContext, useCallback } from 'react';
@@ -37,14 +37,10 @@ const techdocsApiRef = createApiRef({
37
37
  });
38
38
 
39
39
  class TechDocsClient {
40
- constructor({
41
- configApi,
42
- discoveryApi,
43
- identityApi
44
- }) {
45
- this.configApi = configApi;
46
- this.discoveryApi = discoveryApi;
47
- this.identityApi = identityApi;
40
+ constructor(options) {
41
+ this.configApi = options.configApi;
42
+ this.discoveryApi = options.discoveryApi;
43
+ this.fetchApi = options.fetchApi;
48
44
  }
49
45
  async getApiOrigin() {
50
46
  var _a;
@@ -54,10 +50,7 @@ class TechDocsClient {
54
50
  const { kind, namespace, name } = entityId;
55
51
  const apiOrigin = await this.getApiOrigin();
56
52
  const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`;
57
- const token = await this.identityApi.getIdToken();
58
- const request = await fetch(`${requestUrl}`, {
59
- headers: token ? { Authorization: `Bearer ${token}` } : {}
60
- });
53
+ const request = await this.fetchApi.fetch(`${requestUrl}`);
61
54
  if (!request.ok) {
62
55
  throw await ResponseError.fromResponse(request);
63
56
  }
@@ -67,10 +60,7 @@ class TechDocsClient {
67
60
  const { kind, namespace, name } = entityId;
68
61
  const apiOrigin = await this.getApiOrigin();
69
62
  const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`;
70
- const token = await this.identityApi.getIdToken();
71
- const request = await fetch(`${requestUrl}`, {
72
- headers: token ? { Authorization: `Bearer ${token}` } : {}
73
- });
63
+ const request = await this.fetchApi.fetch(`${requestUrl}`);
74
64
  if (!request.ok) {
75
65
  throw await ResponseError.fromResponse(request);
76
66
  }
@@ -78,14 +68,11 @@ class TechDocsClient {
78
68
  }
79
69
  }
80
70
  class TechDocsStorageClient {
81
- constructor({
82
- configApi,
83
- discoveryApi,
84
- identityApi
85
- }) {
86
- this.configApi = configApi;
87
- this.discoveryApi = discoveryApi;
88
- this.identityApi = identityApi;
71
+ constructor(options) {
72
+ this.configApi = options.configApi;
73
+ this.discoveryApi = options.discoveryApi;
74
+ this.identityApi = options.identityApi;
75
+ this.fetchApi = options.fetchApi;
89
76
  }
90
77
  async getApiOrigin() {
91
78
  var _a;
@@ -102,10 +89,7 @@ class TechDocsStorageClient {
102
89
  const { kind, namespace, name } = entityId;
103
90
  const storageUrl = await this.getStorageUrl();
104
91
  const url = `${storageUrl}/${namespace}/${kind}/${name}/${path}`;
105
- const token = await this.identityApi.getIdToken();
106
- const request = await fetch(`${url.endsWith("/") ? url : `${url}/`}index.html`, {
107
- headers: token ? { Authorization: `Bearer ${token}` } : {}
108
- });
92
+ const request = await this.fetchApi.fetch(`${url.endsWith("/") ? url : `${url}/`}index.html`);
109
93
  let errorMessage = "";
110
94
  switch (request.status) {
111
95
  case 404:
@@ -125,7 +109,7 @@ class TechDocsStorageClient {
125
109
  const { kind, namespace, name } = entityId;
126
110
  const apiOrigin = await this.getApiOrigin();
127
111
  const url = `${apiOrigin}/sync/${namespace}/${kind}/${name}`;
128
- const token = await this.identityApi.getIdToken();
112
+ const { token } = await this.identityApi.getCredentials();
129
113
  return new Promise((resolve, reject) => {
130
114
  const source = new EventSourcePolyfill(url, {
131
115
  withCredentials: true,
@@ -495,12 +479,14 @@ const techdocsPlugin = createPlugin({
495
479
  deps: {
496
480
  configApi: configApiRef,
497
481
  discoveryApi: discoveryApiRef,
498
- identityApi: identityApiRef
482
+ identityApi: identityApiRef,
483
+ fetchApi: fetchApiRef
499
484
  },
500
- factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsStorageClient({
485
+ factory: ({ configApi, discoveryApi, identityApi, fetchApi }) => new TechDocsStorageClient({
501
486
  configApi,
502
487
  discoveryApi,
503
- identityApi
488
+ identityApi,
489
+ fetchApi
504
490
  })
505
491
  }),
506
492
  createApiFactory({
@@ -508,12 +494,12 @@ const techdocsPlugin = createPlugin({
508
494
  deps: {
509
495
  configApi: configApiRef,
510
496
  discoveryApi: discoveryApiRef,
511
- identityApi: identityApiRef
497
+ fetchApi: fetchApiRef
512
498
  },
513
- factory: ({ configApi, discoveryApi, identityApi }) => new TechDocsClient({
499
+ factory: ({ configApi, discoveryApi, fetchApi }) => new TechDocsClient({
514
500
  configApi,
515
501
  discoveryApi,
516
- identityApi
502
+ fetchApi
517
503
  })
518
504
  })
519
505
  ],
@@ -598,6 +584,7 @@ const addBaseUrl = ({
598
584
  await Promise.all([
599
585
  updateDom(dom.querySelectorAll("img"), "src"),
600
586
  updateDom(dom.querySelectorAll("script"), "src"),
587
+ updateDom(dom.querySelectorAll("source"), "src"),
601
588
  updateDom(dom.querySelectorAll("link"), "href"),
602
589
  updateDom(dom.querySelectorAll("a[download]"), "href")
603
590
  ]);
@@ -686,7 +673,7 @@ const addLinkClickListener = ({
686
673
  const href = target.getAttribute("href");
687
674
  if (!href)
688
675
  return;
689
- if (href.startsWith(baseUrl)) {
676
+ if (href.startsWith(baseUrl) && !elem.hasAttribute("download")) {
690
677
  e.preventDefault();
691
678
  onClick(e, href);
692
679
  }
@@ -696,6 +683,22 @@ const addLinkClickListener = ({
696
683
  };
697
684
  };
698
685
 
686
+ const copyToClipboard = () => {
687
+ return (dom) => {
688
+ Array.from(dom.querySelectorAll("pre > code")).forEach((codeElem) => {
689
+ var _a;
690
+ const button = document.createElement("button");
691
+ const toBeCopied = codeElem.textContent || "";
692
+ button.className = "md-clipboard md-icon";
693
+ button.title = "Copy to clipboard";
694
+ button.innerHTML = '<svg viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg>';
695
+ button.addEventListener("click", () => navigator.clipboard.writeText(toBeCopied));
696
+ (_a = codeElem == null ? void 0 : codeElem.parentElement) == null ? void 0 : _a.prepend(button);
697
+ });
698
+ return dom;
699
+ };
700
+ };
701
+
699
702
  const removeMkdocsHeader = () => {
700
703
  return (dom) => {
701
704
  var _a;
@@ -1330,6 +1333,8 @@ const useTechDocsReaderDom = (entityRef) => {
1330
1333
 
1331
1334
  --md-code-fg-color: ${theme.palette.text.primary};
1332
1335
  --md-code-bg-color: ${theme.palette.background.paper};
1336
+ --md-accent-fg-color: ${theme.palette.primary.main};
1337
+ --md-default-fg-color--lightest: ${theme.palette.textVerySubtle};
1333
1338
  }
1334
1339
  .md-main__inner { margin-top: 0; }
1335
1340
  .md-sidebar { position: fixed; bottom: 100px; width: 20rem; }
@@ -1342,6 +1347,13 @@ const useTechDocsReaderDom = (entityRef) => {
1342
1347
  .md-typeset h1, .md-typeset h2, .md-typeset h3 { font-weight: bold; }
1343
1348
  .md-nav { font-size: 1rem; }
1344
1349
  .md-grid { max-width: 90vw; margin: 0 }
1350
+ .md-typeset blockquote {
1351
+ color: ${theme.palette.textSubtle};
1352
+ border-left: 0.2rem solid ${theme.palette.textVerySubtle};
1353
+ }
1354
+ .md-typeset hr {
1355
+ border-bottom: 0.05rem dotted ${theme.palette.textVerySubtle};
1356
+ }
1345
1357
  .md-typeset table:not([class]) {
1346
1358
  font-size: 1rem;
1347
1359
  border: 1px solid ${theme.palette.text.primary};
@@ -1452,11 +1464,14 @@ const useTechDocsReaderDom = (entityRef) => {
1452
1464
  theme.palette.primary.main,
1453
1465
  theme.palette.success.main,
1454
1466
  theme.palette.text.primary,
1467
+ theme.palette.textSubtle,
1468
+ theme.palette.textVerySubtle,
1455
1469
  theme.typography.fontFamily,
1456
1470
  isPinned
1457
1471
  ]);
1458
1472
  const postRender = useCallback(async (transformedElement) => transform(transformedElement, [
1459
1473
  scrollIntoAnchor(),
1474
+ copyToClipboard(),
1460
1475
  addLinkClickListener({
1461
1476
  baseUrl: window.location.origin,
1462
1477
  onClick: (event, url) => {