From f09f6a166bd1acd9b2026af18ef827d51a3ca893 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Thu, 22 Apr 2021 12:41:53 +0200 Subject: [PATCH 1/6] Use interface and not implementation in ApiRef Closes #4404 Signed-off-by: Oliver Sand --- .changeset/swift-waves-sleep.md | 12 + plugins/techdocs/dev/api.ts | 8 +- plugins/techdocs/src/api.ts | 236 +---------------- .../src/{api.test.ts => client.test.ts} | 8 +- plugins/techdocs/src/client.ts | 244 ++++++++++++++++++ plugins/techdocs/src/index.ts | 17 +- plugins/techdocs/src/plugin.ts | 22 +- plugins/techdocs/src/types.ts | 4 + 8 files changed, 296 insertions(+), 255 deletions(-) create mode 100644 .changeset/swift-waves-sleep.md rename plugins/techdocs/src/{api.test.ts => client.test.ts} (87%) create mode 100644 plugins/techdocs/src/client.ts diff --git a/.changeset/swift-waves-sleep.md b/.changeset/swift-waves-sleep.md new file mode 100644 index 0000000000..831ecc0001 --- /dev/null +++ b/.changeset/swift-waves-sleep.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Make `techdocsStorageApiRef` and `techdocsApiRef` use interfaces instead of the +actual implementation classes. + +This renames the classes `TechDocsApi` to `TechDocsClient` and `TechDocsStorageApi` +to `TechDocsStorageClient` and renames the interfaces `TechDocs` to `TechDocsApi` +and `TechDocsStorage` to `TechDocsStorageApi` to comply the pattern elsewhere in +the project. This also fixes the types returned by some methods on those +interfaces. diff --git a/plugins/techdocs/dev/api.ts b/plugins/techdocs/dev/api.ts index 7acf3c7032..e764bf82bb 100644 --- a/plugins/techdocs/dev/api.ts +++ b/plugins/techdocs/dev/api.ts @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DiscoveryApi, IdentityApi } from '@backstage/core'; -import { Config } from '@backstage/config'; import { EntityName } from '@backstage/catalog-model'; -import { TechDocsStorage } from '../src/api'; +import { Config } from '@backstage/config'; +import { DiscoveryApi, IdentityApi } from '@backstage/core'; import { NotFoundError } from '@backstage/errors'; +import { TechDocsStorageApi } from '../src/api'; -export class TechDocsDevStorageApi implements TechDocsStorage { +export class TechDocsDevStorageApi implements TechDocsStorageApi { public configApi: Config; public discoveryApi: DiscoveryApi; public identityApi: IdentityApi; diff --git a/plugins/techdocs/src/api.ts b/plugins/techdocs/src/api.ts index 0be530cc08..204cc1b5a8 100644 --- a/plugins/techdocs/src/api.ts +++ b/plugins/techdocs/src/api.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import { createApiRef, DiscoveryApi, IdentityApi } from '@backstage/core'; -import { Config } from '@backstage/config'; import { EntityName } from '@backstage/catalog-model'; -import { TechDocsMetadata } from './types'; -import { NotFoundError } from '@backstage/errors'; +import { createApiRef } from '@backstage/core'; +import { TechDocsEntityMetadata, TechDocsMetadata } from './types'; export const techdocsStorageApiRef = createApiRef({ id: 'plugin.techdocs.storageservice', @@ -30,7 +28,10 @@ export const techdocsApiRef = createApiRef({ description: 'Used to make requests towards techdocs API', }); -export interface TechDocsStorage { +export interface TechDocsStorageApi { + getApiOrigin(): Promise; + getStorageUrl(): Promise; + getBuilder(): Promise; getEntityDocs(entityId: EntityName, path: string): Promise; syncEntityDocs(entityId: EntityName): Promise; getBaseUrl( @@ -40,227 +41,8 @@ export interface TechDocsStorage { ): Promise; } -export interface TechDocs { +export interface TechDocsApi { + getApiOrigin(): Promise; getTechDocsMetadata(entityId: EntityName): Promise; - getEntityMetadata(entityId: EntityName): Promise; -} - -/** - * API to talk to techdocs-backend. - * - * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API - */ -export class TechDocsApi implements TechDocs { - public configApi: Config; - public discoveryApi: DiscoveryApi; - public identityApi: IdentityApi; - - constructor({ - configApi, - discoveryApi, - identityApi, - }: { - configApi: Config; - discoveryApi: DiscoveryApi; - identityApi: IdentityApi; - }) { - this.configApi = configApi; - this.discoveryApi = discoveryApi; - this.identityApi = identityApi; - } - - async getApiOrigin() { - return ( - this.configApi.getOptionalString('techdocs.requestUrl') ?? - (await this.discoveryApi.getBaseUrl('techdocs')) - ); - } - - /** - * Retrieve TechDocs metadata. - * - * When docs are built, we generate a techdocs_metadata.json and store it along with the generated - * static files. It includes necessary data about the docs site. This method requests techdocs-backend - * which retrieves the TechDocs metadata. - * - * @param {EntityName} entityId Object containing entity data like name, namespace, etc. - */ - async getTechDocsMetadata(entityId: EntityName) { - const { kind, namespace, name } = entityId; - - const apiOrigin = await this.getApiOrigin(); - const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`; - const token = await this.identityApi.getIdToken(); - - const request = await fetch(`${requestUrl}`, { - headers: token ? { Authorization: `Bearer ${token}` } : {}, - }); - const res = await request.json(); - - return res; - } - - /** - * Retrieve metadata about an entity. - * - * This method requests techdocs-backend which uses the catalog APIs to respond with filtered - * information required here. - * - * @param {EntityName} entityId Object containing entity data like name, namespace, etc. - */ - async getEntityMetadata(entityId: EntityName) { - const { kind, namespace, name } = entityId; - - const apiOrigin = await this.getApiOrigin(); - const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`; - const token = await this.identityApi.getIdToken(); - - const request = await fetch(`${requestUrl}`, { - headers: token ? { Authorization: `Bearer ${token}` } : {}, - }); - const res = await request.json(); - - return res; - } -} - -/** - * API which talks to TechDocs storage to fetch files to render. - * - * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API - */ -export class TechDocsStorageApi implements TechDocsStorage { - public configApi: Config; - public discoveryApi: DiscoveryApi; - public identityApi: IdentityApi; - - constructor({ - configApi, - discoveryApi, - identityApi, - }: { - configApi: Config; - discoveryApi: DiscoveryApi; - identityApi: IdentityApi; - }) { - this.configApi = configApi; - this.discoveryApi = discoveryApi; - this.identityApi = identityApi; - } - - async getApiOrigin() { - return ( - this.configApi.getOptionalString('techdocs.requestUrl') ?? - (await this.discoveryApi.getBaseUrl('techdocs')) - ); - } - - async getStorageUrl() { - return ( - this.configApi.getOptionalString('techdocs.storageUrl') ?? - `${await this.discoveryApi.getBaseUrl('techdocs')}/static/docs` - ); - } - - async getBuilder() { - return this.configApi.getString('techdocs.builder'); - } - - /** - * Fetch HTML content as text for an individual docs page in an entity's docs site. - * - * @param {EntityName} entityId Object containing entity data like name, namespace, etc. - * @param {string} path The unique path to an individual docs page e.g. overview/what-is-new - * @returns {string} HTML content of the docs page as string - * @throws {Error} Throws error when the page is not found. - */ - async getEntityDocs(entityId: EntityName, path: string) { - const { kind, namespace, name } = entityId; - - const storageUrl = await this.getStorageUrl(); - const url = `${storageUrl}/${namespace}/${kind}/${name}/${path}`; - const token = await this.identityApi.getIdToken(); - - const request = await fetch( - `${url.endsWith('/') ? url : `${url}/`}index.html`, - { - headers: token ? { Authorization: `Bearer ${token}` } : {}, - }, - ); - - let errorMessage = ''; - switch (request.status) { - case 404: - errorMessage = 'Page not found. '; - // path is empty for the home page of an entity's docs site - if (!path) { - errorMessage += - 'This could be because there is no index.md file in the root of the docs directory of this repository.'; - } - throw new NotFoundError(errorMessage); - case 500: - errorMessage = - 'Could not generate documentation or an error in the TechDocs backend. '; - throw new Error(errorMessage); - default: - // Do nothing - break; - } - - return request.text(); - } - - /** - * Check if docs are on the latest version and trigger rebuild if not - * - * @param {EntityName} entityId Object containing entity data like name, namespace, etc. - * @returns {boolean} Whether documents are currently synchronized to newest version - * @throws {Error} Throws error on error from sync endpoint in Techdocs Backend - */ - async syncEntityDocs(entityId: EntityName) { - const { kind, namespace, name } = entityId; - - const apiOrigin = await this.getApiOrigin(); - const url = `${apiOrigin}/sync/${namespace}/${kind}/${name}`; - const token = await this.identityApi.getIdToken(); - let request; - let attempts: number = 0; - // retry if request times out, up to 5 times - // can happen due to docs taking too long to generate - while (!request || (request.status === 408 && attempts < 5)) { - attempts++; - request = await fetch(url, { - headers: token ? { Authorization: `Bearer ${token}` } : {}, - }); - } - - switch (request.status) { - case 404: - throw new NotFoundError((await request.json()).error); - case 200: - case 201: - case 304: - return true; - // for timeout and misc errors, handle without error to allow viewing older docs - // if older docs not available, - // Reader will show 404 error coming from getEntityDocs - case 408: - default: - return false; - } - } - - async getBaseUrl( - oldBaseUrl: string, - entityId: EntityName, - path: string, - ): Promise { - const { kind, namespace, name } = entityId; - - const apiOrigin = await this.getApiOrigin(); - return new URL( - oldBaseUrl, - `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`, - ).toString(); - } + getEntityMetadata(entityId: EntityName): Promise; } diff --git a/plugins/techdocs/src/api.test.ts b/plugins/techdocs/src/client.test.ts similarity index 87% rename from plugins/techdocs/src/api.test.ts rename to plugins/techdocs/src/client.test.ts index 2260cc7d39..e8fc8f042f 100644 --- a/plugins/techdocs/src/api.test.ts +++ b/plugins/techdocs/src/client.test.ts @@ -15,7 +15,7 @@ */ import { Config } from '@backstage/config'; import { UrlPatternDiscovery } from '@backstage/core'; -import { TechDocsStorageApi } from './api'; +import { TechDocsStorageClient } from './client'; const mockEntity = { kind: 'Component', @@ -23,7 +23,7 @@ const mockEntity = { name: 'test-component', }; -describe('TechDocsStorageApi', () => { +describe('TechDocsStorageClient', () => { const mockBaseUrl = 'http://backstage:9191/api/techdocs'; const configApi = { getOptionalString: () => 'http://backstage:9191/api/techdocs', @@ -32,7 +32,7 @@ describe('TechDocsStorageApi', () => { it('should return correct base url based on defined storage', async () => { // @ts-ignore Partial not assignable to Config. - const storageApi = new TechDocsStorageApi({ configApi, discoveryApi }); + const storageApi = new TechDocsStorageClient({ configApi, discoveryApi }); await expect( storageApi.getBaseUrl('test.js', mockEntity, ''), @@ -43,7 +43,7 @@ describe('TechDocsStorageApi', () => { it('should return base url with correct entity structure', async () => { // @ts-ignore Partial not assignable to Config. - const storageApi = new TechDocsStorageApi({ configApi, discoveryApi }); + const storageApi = new TechDocsStorageClient({ configApi, discoveryApi }); await expect( storageApi.getBaseUrl('test/', mockEntity, ''), diff --git a/plugins/techdocs/src/client.ts b/plugins/techdocs/src/client.ts new file mode 100644 index 0000000000..245cfb0154 --- /dev/null +++ b/plugins/techdocs/src/client.ts @@ -0,0 +1,244 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityName } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; +import { DiscoveryApi, IdentityApi } from '@backstage/core'; +import { NotFoundError } from '@backstage/errors'; +import { TechDocsApi, TechDocsStorageApi } from './api'; +import { TechDocsEntityMetadata, TechDocsMetadata } from './types'; + +/** + * API to talk to techdocs-backend. + * + * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API + */ +export class TechDocsClient implements TechDocsApi { + public configApi: Config; + public discoveryApi: DiscoveryApi; + public identityApi: IdentityApi; + + constructor({ + configApi, + discoveryApi, + identityApi, + }: { + configApi: Config; + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + }) { + this.configApi = configApi; + this.discoveryApi = discoveryApi; + this.identityApi = identityApi; + } + + async getApiOrigin(): Promise { + return ( + this.configApi.getOptionalString('techdocs.requestUrl') ?? + (await this.discoveryApi.getBaseUrl('techdocs')) + ); + } + + /** + * Retrieve TechDocs metadata. + * + * When docs are built, we generate a techdocs_metadata.json and store it along with the generated + * static files. It includes necessary data about the docs site. This method requests techdocs-backend + * which retrieves the TechDocs metadata. + * + * @param {EntityName} entityId Object containing entity data like name, namespace, etc. + */ + async getTechDocsMetadata(entityId: EntityName): Promise { + const { kind, namespace, name } = entityId; + + const apiOrigin = await this.getApiOrigin(); + const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`; + const token = await this.identityApi.getIdToken(); + + const request = await fetch(`${requestUrl}`, { + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); + const res = await request.json(); + + return res; + } + + /** + * Retrieve metadata about an entity. + * + * This method requests techdocs-backend which uses the catalog APIs to respond with filtered + * information required here. + * + * @param {EntityName} entityId Object containing entity data like name, namespace, etc. + */ + async getEntityMetadata( + entityId: EntityName, + ): Promise { + const { kind, namespace, name } = entityId; + + const apiOrigin = await this.getApiOrigin(); + const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`; + const token = await this.identityApi.getIdToken(); + + const request = await fetch(`${requestUrl}`, { + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); + const res = await request.json(); + + return res; + } +} + +/** + * API which talks to TechDocs storage to fetch files to render. + * + * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API + */ +export class TechDocsStorageClient implements TechDocsStorageApi { + public configApi: Config; + public discoveryApi: DiscoveryApi; + public identityApi: IdentityApi; + + constructor({ + configApi, + discoveryApi, + identityApi, + }: { + configApi: Config; + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + }) { + this.configApi = configApi; + this.discoveryApi = discoveryApi; + this.identityApi = identityApi; + } + + async getApiOrigin(): Promise { + return ( + this.configApi.getOptionalString('techdocs.requestUrl') ?? + (await this.discoveryApi.getBaseUrl('techdocs')) + ); + } + + async getStorageUrl(): Promise { + return ( + this.configApi.getOptionalString('techdocs.storageUrl') ?? + `${await this.discoveryApi.getBaseUrl('techdocs')}/static/docs` + ); + } + + async getBuilder(): Promise { + return this.configApi.getString('techdocs.builder'); + } + + /** + * Fetch HTML content as text for an individual docs page in an entity's docs site. + * + * @param {EntityName} entityId Object containing entity data like name, namespace, etc. + * @param {string} path The unique path to an individual docs page e.g. overview/what-is-new + * @returns {string} HTML content of the docs page as string + * @throws {Error} Throws error when the page is not found. + */ + async getEntityDocs(entityId: EntityName, path: string): Promise { + const { kind, namespace, name } = entityId; + + const storageUrl = await this.getStorageUrl(); + const url = `${storageUrl}/${namespace}/${kind}/${name}/${path}`; + const token = await this.identityApi.getIdToken(); + + const request = await fetch( + `${url.endsWith('/') ? url : `${url}/`}index.html`, + { + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }, + ); + + let errorMessage = ''; + switch (request.status) { + case 404: + errorMessage = 'Page not found. '; + // path is empty for the home page of an entity's docs site + if (!path) { + errorMessage += + 'This could be because there is no index.md file in the root of the docs directory of this repository.'; + } + throw new NotFoundError(errorMessage); + case 500: + errorMessage = + 'Could not generate documentation or an error in the TechDocs backend. '; + throw new Error(errorMessage); + default: + // Do nothing + break; + } + + return request.text(); + } + + /** + * Check if docs are on the latest version and trigger rebuild if not + * + * @param {EntityName} entityId Object containing entity data like name, namespace, etc. + * @returns {boolean} Whether documents are currently synchronized to newest version + * @throws {Error} Throws error on error from sync endpoint in Techdocs Backend + */ + async syncEntityDocs(entityId: EntityName): Promise { + const { kind, namespace, name } = entityId; + + const apiOrigin = await this.getApiOrigin(); + const url = `${apiOrigin}/sync/${namespace}/${kind}/${name}`; + const token = await this.identityApi.getIdToken(); + let request; + let attempts: number = 0; + // retry if request times out, up to 5 times + // can happen due to docs taking too long to generate + while (!request || (request.status === 408 && attempts < 5)) { + attempts++; + request = await fetch(url, { + headers: token ? { Authorization: `Bearer ${token}` } : {}, + }); + } + + switch (request.status) { + case 404: + throw new NotFoundError((await request.json()).error); + case 200: + case 201: + case 304: + return true; + // for timeout and misc errors, handle without error to allow viewing older docs + // if older docs not available, + // Reader will show 404 error coming from getEntityDocs + case 408: + default: + return false; + } + } + + async getBaseUrl( + oldBaseUrl: string, + entityId: EntityName, + path: string, + ): Promise { + const { kind, namespace, name } = entityId; + + const apiOrigin = await this.getApiOrigin(); + return new URL( + oldBaseUrl, + `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`, + ).toString(); + } +} diff --git a/plugins/techdocs/src/index.ts b/plugins/techdocs/src/index.ts index b33b91e2c5..3bdf8bfec1 100644 --- a/plugins/techdocs/src/index.ts +++ b/plugins/techdocs/src/index.ts @@ -14,17 +14,20 @@ * limitations under the License. */ +export * from './api'; +export { techdocsApiRef, techdocsStorageApiRef } from './api'; +export type { TechDocsApi, TechDocsStorageApi } from './api'; +export { TechDocsClient, TechDocsStorageClient } from './client'; +export type { PanelType } from './home/components/TechDocsCustomHome'; export { - techdocsPlugin, - techdocsPlugin as plugin, - TechdocsPage, - EntityTechdocsContent, DocsCardGrid, DocsTable, + EntityTechdocsContent, TechDocsCustomHome, + TechdocsPage, + techdocsPlugin as plugin, + techdocsPlugin, TechDocsReaderPage, } from './plugin'; -export { Router, EmbeddedDocsRouter } from './Router'; export * from './reader'; -export * from './api'; -export type { PanelType } from './home/components/TechDocsCustomHome'; +export { EmbeddedDocsRouter, Router } from './Router'; diff --git a/plugins/techdocs/src/plugin.ts b/plugins/techdocs/src/plugin.ts index d9b38a2c76..97dd6f2150 100644 --- a/plugins/techdocs/src/plugin.ts +++ b/plugins/techdocs/src/plugin.ts @@ -30,21 +30,17 @@ */ import { - createPlugin, - createRouteRef, - createApiFactory, configApiRef, + createApiFactory, + createComponentExtension, + createPlugin, + createRoutableExtension, + createRouteRef, discoveryApiRef, identityApiRef, - createRoutableExtension, - createComponentExtension, } from '@backstage/core'; -import { - techdocsStorageApiRef, - TechDocsStorageApi, - techdocsApiRef, - TechDocsApi, -} from './api'; +import { techdocsApiRef, techdocsStorageApiRef } from './api'; +import { TechDocsClient, TechDocsStorageClient } from './client'; export const rootRouteRef = createRouteRef({ path: '', @@ -72,7 +68,7 @@ export const techdocsPlugin = createPlugin({ identityApi: identityApiRef, }, factory: ({ configApi, discoveryApi, identityApi }) => - new TechDocsStorageApi({ + new TechDocsStorageClient({ configApi, discoveryApi, identityApi, @@ -86,7 +82,7 @@ export const techdocsPlugin = createPlugin({ identityApi: identityApiRef, }, factory: ({ configApi, discoveryApi, identityApi }) => - new TechDocsApi({ + new TechDocsClient({ configApi, discoveryApi, identityApi, diff --git a/plugins/techdocs/src/types.ts b/plugins/techdocs/src/types.ts index 36cc4e187b..fb068bee09 100644 --- a/plugins/techdocs/src/types.ts +++ b/plugins/techdocs/src/types.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { Entity, Location } from '@backstage/catalog-model'; + export type TechDocsMetadata = { site_name: string; site_description: string; }; + +export type TechDocsEntityMetadata = Entity & { locationMetadata?: Location }; From bf905d9bdeba84c81d7e84e4b506867e662c10ce Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Thu, 22 Apr 2021 12:43:28 +0200 Subject: [PATCH 2/6] Comment out datadog configuration Signed-off-by: Oliver Sand --- app-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index ac59874878..3c4f2d7ea5 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -2,9 +2,9 @@ app: title: Backstage Example App baseUrl: http://localhost:3000 googleAnalyticsTrackingId: # UA-000000-0 - datadogRum: - clientToken: '123456789' - applicationId: qwerty + #datadogRum: + # clientToken: '123456789' + # applicationId: qwerty # site: # datadoghq.eu default = datadoghq.com # env: # optional From a3048a3b7fcebea0394489c1c09ff2e814336bd4 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Thu, 22 Apr 2021 13:08:20 +0200 Subject: [PATCH 3/6] Fix some remaining typing issues Signed-off-by: Oliver Sand --- .../src/reader/components/TechDocsPage.test.tsx | 15 +++++++++++++-- .../src/reader/components/TechDocsPage.tsx | 8 ++++---- .../src/reader/transformers/addBaseUrl.test.ts | 7 +++++-- .../src/reader/transformers/addBaseUrl.ts | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx index 4b578bef38..52ddd3794e 100644 --- a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx @@ -51,8 +51,19 @@ describe('', () => { }); const techdocsApi: Partial = { - getEntityMetadata: () => Promise.resolve([]), - getTechDocsMetadata: () => Promise.resolve([]), + getEntityMetadata: () => + Promise.resolve({ + apiVersion: 'v1', + kind: 'Component', + metadata: { + name: 'backstage', + }, + }), + getTechDocsMetadata: () => + Promise.resolve({ + site_name: 'string', + site_description: 'string', + }), }; const techdocsStorageApi: Partial = { getEntityDocs: (): Promise => Promise.resolve('String'), diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.tsx index f2635c0dfb..c15f3a6a44 100644 --- a/plugins/techdocs/src/reader/components/TechDocsPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsPage.tsx @@ -14,13 +14,13 @@ * limitations under the License. */ +import { Content, Page, useApi } from '@backstage/core'; import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; -import { Content, Page, useApi } from '@backstage/core'; -import { Reader } from './Reader'; import { useAsync } from 'react-use'; -import { TechDocsPageHeader } from './TechDocsPageHeader'; import { techdocsApiRef } from '../../api'; +import { Reader } from './Reader'; +import { TechDocsPageHeader } from './TechDocsPageHeader'; export const TechDocsPage = () => { const [documentReady, setDocumentReady] = useState(false); @@ -33,7 +33,7 @@ export const TechDocsPage = () => { return techdocsApi.getTechDocsMetadata({ kind, namespace, name }); } - return Promise.resolve({ loading: true }); + return Promise.resolve(undefined); }, [kind, namespace, name, techdocsApi, documentReady]); const entityMetadataRequest = useAsync(() => { diff --git a/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts b/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts index 5ba86e42ca..4311de5dae 100644 --- a/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts +++ b/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts @@ -16,14 +16,17 @@ import { createTestShadowDom } from '../../test-utils'; import { addBaseUrl } from '../transformers'; -import { TechDocsStorage } from '../../api'; +import { TechDocsStorageApi } from '../../api'; const DOC_STORAGE_URL = 'https://example-host.storage.googleapis.com'; -const techdocsStorageApi: TechDocsStorage = { +const techdocsStorageApi: TechDocsStorageApi = { getBaseUrl: jest.fn(() => Promise.resolve(DOC_STORAGE_URL)), getEntityDocs: () => new Promise(resolve => resolve('yes!')), syncEntityDocs: () => new Promise(resolve => resolve(true)), + getApiOrigin: jest.fn(), + getBuilder: jest.fn(), + getStorageUrl: jest.fn(), }; const fixture = ` diff --git a/plugins/techdocs/src/reader/transformers/addBaseUrl.ts b/plugins/techdocs/src/reader/transformers/addBaseUrl.ts index 2872ad36cc..17070dcfe0 100644 --- a/plugins/techdocs/src/reader/transformers/addBaseUrl.ts +++ b/plugins/techdocs/src/reader/transformers/addBaseUrl.ts @@ -15,10 +15,10 @@ */ import { EntityName } from '@backstage/catalog-model'; import type { Transformer } from './index'; -import { TechDocsStorage } from '../../api'; +import { TechDocsStorageApi } from '../../api'; type AddBaseUrlOptions = { - techdocsStorageApi: TechDocsStorage; + techdocsStorageApi: TechDocsStorageApi; entityId: EntityName; path: string; }; From 21fddf45244e9a335411627fdbc68cac9250a9b7 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Thu, 22 Apr 2021 15:51:55 +0200 Subject: [PATCH 4/6] Rename changeset Signed-off-by: Oliver Sand --- .../{swift-waves-sleep.md => techdocs-swift-waves-sleep.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changeset/{swift-waves-sleep.md => techdocs-swift-waves-sleep.md} (100%) diff --git a/.changeset/swift-waves-sleep.md b/.changeset/techdocs-swift-waves-sleep.md similarity index 100% rename from .changeset/swift-waves-sleep.md rename to .changeset/techdocs-swift-waves-sleep.md From 92cc589201170b05689d0c310132e3448b8b9602 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Fri, 23 Apr 2021 13:16:10 +0200 Subject: [PATCH 5/6] Remove duplicate @backstage/test-utils dependency Signed-off-by: Oliver Sand --- plugins/techdocs/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index e526f028d5..7bde151663 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -35,7 +35,6 @@ "@backstage/catalog-model": "^0.7.7", "@backstage/core": "^0.7.6", "@backstage/plugin-catalog-react": "^0.1.4", - "@backstage/test-utils": "^0.1.9", "@backstage/theme": "^0.2.6", "@backstage/errors": "^0.1.1", "@material-ui/core": "^4.11.0", From d0b69236542f8cf31043c1f48facc74783c428d5 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Mon, 26 Apr 2021 14:05:04 +0200 Subject: [PATCH 6/6] Adjust changeset Signed-off-by: Oliver Sand --- .changeset/techdocs-swift-waves-sleep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/techdocs-swift-waves-sleep.md b/.changeset/techdocs-swift-waves-sleep.md index 831ecc0001..79d10931cd 100644 --- a/.changeset/techdocs-swift-waves-sleep.md +++ b/.changeset/techdocs-swift-waves-sleep.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-techdocs': patch +'@backstage/plugin-techdocs': minor --- Make `techdocsStorageApiRef` and `techdocsApiRef` use interfaces instead of the