@backstage/plugin-techdocs 0.12.15-next.0 → 0.13.2-next.1

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,5 +1,130 @@
1
1
  # @backstage/plugin-techdocs
2
2
 
3
+ ## 0.13.2-next.1
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
+ - Updated dependencies
9
+ - @backstage/core-components@0.8.7-next.1
10
+ - @backstage/plugin-catalog-react@0.6.13-next.1
11
+ - @backstage/plugin-catalog@0.7.11-next.1
12
+
13
+ ## 0.13.2-next.0
14
+
15
+ ### Patch Changes
16
+
17
+ - 359c31e31d: Added support for documentation using the raw `<source>` tag to point to relative resources like audio or video files.
18
+ - Updated dependencies
19
+ - @backstage/core-components@0.8.7-next.0
20
+ - @backstage/integration-react@0.1.20-next.0
21
+ - @backstage/plugin-catalog@0.7.11-next.0
22
+ - @backstage/plugin-catalog-react@0.6.13-next.0
23
+ - @backstage/plugin-search@0.6.1-next.0
24
+
25
+ ## 0.13.1
26
+
27
+ ### Patch Changes
28
+
29
+ - bdc53553eb: chore(deps): bump `react-text-truncate` from 0.16.0 to 0.17.0
30
+ - a64f99f734: Code snippets now include a "copy to clipboard" button.
31
+ - Updated dependencies
32
+ - @backstage/core-components@0.8.6
33
+ - @backstage/plugin-search@0.6.0
34
+ - @backstage/plugin-catalog@0.7.10
35
+
36
+ ## 0.13.0
37
+
38
+ ### Minor Changes
39
+
40
+ - aecfe4f403: Make `TechDocsClient` and `TechDocsStorageClient` use the `FetchApi`. You now
41
+ need to pass in an instance of that API when constructing the client, if you
42
+ create a custom instance in your app.
43
+
44
+ If you are replacing the factory:
45
+
46
+ ```diff
47
+ +import { fetchApiRef } from '@backstage/core-plugin-api';
48
+
49
+ createApiFactory({
50
+ api: techdocsStorageApiRef,
51
+ deps: {
52
+ configApi: configApiRef,
53
+ discoveryApi: discoveryApiRef,
54
+ identityApi: identityApiRef,
55
+ + fetchApi: fetchApiRef,
56
+ },
57
+ factory: ({
58
+ configApi,
59
+ discoveryApi,
60
+ identityApi,
61
+ + fetchApi,
62
+ }) =>
63
+ new TechDocsStorageClient({
64
+ configApi,
65
+ discoveryApi,
66
+ identityApi,
67
+ + fetchApi,
68
+ }),
69
+ }),
70
+ createApiFactory({
71
+ api: techdocsApiRef,
72
+ deps: {
73
+ configApi: configApiRef,
74
+ discoveryApi: discoveryApiRef,
75
+ - identityApi: identityApiRef,
76
+ + fetchApi: fetchApiRef,
77
+ },
78
+ factory: ({
79
+ configApi,
80
+ discoveryApi,
81
+ - identityApi,
82
+ + fetchApi,
83
+ }) =>
84
+ new TechDocsClient({
85
+ configApi,
86
+ discoveryApi,
87
+ - identityApi,
88
+ + fetchApi,
89
+ }),
90
+ }),
91
+ ```
92
+
93
+ If instantiating directly:
94
+
95
+ ```diff
96
+ +import { fetchApiRef } from '@backstage/core-plugin-api';
97
+
98
+ +const fetchApi = useApi(fetchApiRef);
99
+ const storageClient = new TechDocsStorageClient({
100
+ configApi,
101
+ discoveryApi,
102
+ identityApi,
103
+ + fetchApi,
104
+ });
105
+ const techdocsClient = new TechDocsClient({
106
+ configApi,
107
+ discoveryApi,
108
+ - identityApi,
109
+ + fetchApi,
110
+ }),
111
+ ```
112
+
113
+ ### Patch Changes
114
+
115
+ - 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
116
+ - 29710c91c2: use lighter color for block quotes and horizontal rulers
117
+ - Updated dependencies
118
+ - @backstage/core-components@0.8.5
119
+ - @backstage/integration@0.7.2
120
+ - @backstage/plugin-search@0.5.6
121
+ - @backstage/core-plugin-api@0.6.0
122
+ - @backstage/plugin-catalog@0.7.9
123
+ - @backstage/plugin-catalog-react@0.6.12
124
+ - @backstage/config@0.1.13
125
+ - @backstage/catalog-model@0.9.10
126
+ - @backstage/integration-react@0.1.19
127
+
3
128
  ## 0.12.15-next.0
4
129
 
5
130
  ### Patch Changes
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.getCredentials();
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.getCredentials();
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.getCredentials();
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:
@@ -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("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; }
@@ -1466,6 +1471,7 @@ const useTechDocsReaderDom = (entityRef) => {
1466
1471
  ]);
1467
1472
  const postRender = useCallback(async (transformedElement) => transform(transformedElement, [
1468
1473
  scrollIntoAnchor(),
1474
+ copyToClipboard(),
1469
1475
  addLinkClickListener({
1470
1476
  baseUrl: window.location.origin,
1471
1477
  onClick: (event, url) => {