Merge pull request #3890 from ParthS007/3715

This commit is contained in:
Himanshu Mishra
2021-02-03 00:26:51 +01:00
committed by GitHub
23 changed files with 253 additions and 209 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Remove techdocs.requestUrl and techdocs.storageUrl from app-config.yaml
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/techdocs-common': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-techdocs-backend': patch
---
`techdocs.requestUrl` and `techdocs.storageUrl` are now optional configs and the discovery API will be used to get the URL where techdocs plugin is hosted.
-2
View File
@@ -74,8 +74,6 @@ organization:
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
techdocs:
requestUrl: http://localhost:7000/api/techdocs
storageUrl: http://localhost:7000/api/techdocs/static/docs
builder: 'local' # Alternatives - 'external'
generators:
techdocs: 'docker' # Alternatives - 'local'
+11 -9
View File
@@ -13,15 +13,6 @@ configuration options for TechDocs.
# File: app-config.yaml
techdocs:
# TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
requestUrl: http://localhost:7000/api/techdocs
# Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
# to serve files from either a local directory or an External storage provider.
storageUrl: http://localhost:7000/api/techdocs/static/docs
# generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to
# spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of).
# You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running
@@ -101,4 +92,15 @@ techdocs:
# https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json
accountKey:
$env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY
# (Optional and Legacy) TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
# You don't have to specify this anymore.
requestUrl: http://localhost:7000/api/techdocs
# (Optional and Legacy) Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
# to serve files from either a local directory or an External storage provider.
# You don't have to specify this anymore.
storageUrl: http://localhost:7000/api/techdocs/static/docs
```
+3 -18
View File
@@ -150,26 +150,10 @@ app. Now let us tweak some configurations to suit your needs.
**See [TechDocs Configuration Options](configuration.md) for complete
configuration reference.**
### Setting TechDocs URLs
```yaml
techdocs:
storageUrl: http://localhost:7000/api/techdocs/static/docs
requestUrl: http://localhost:7000/api/techdocs/
```
`requestUrl` is used by TechDocs frontend plugin to discover `techdocs-backend`
endpoints, and the `storageUrl` is another endpoint in `techdocs-backend` which
acts as a middleware between TechDocs and the storage (where the static
generated docs site are stored). These default values should mostly work for
you. These options will soon be optional to set.
### Should TechDocs Backend generate docs?
```yaml
techdocs:
storageUrl: http://localhost:7000/api/techdocs/static/docs
requestUrl: http://localhost:7000/api/techdocs/
builder: 'local'
```
@@ -196,8 +180,6 @@ out Backstage for the first time. At a later time, review
```yaml
techdocs:
storageUrl: http://localhost:7000/api/techdocs/static/docs
requestUrl: http://localhost:7000/api/techdocs/
builder: 'local'
publisher:
type: 'local'
@@ -219,6 +201,9 @@ no config is provided.
```yaml
techdocs:
builder: 'local'
publisher:
type: 'local'
generators:
techdocs: local
```
@@ -56,14 +56,13 @@ proxy:
target: 'https://example.com'
changeOrigin: true
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
techdocs:
requestUrl: http://localhost:7000/api/techdocs
storageUrl: http://localhost:7000/api/techdocs/static/docs
builder: 'local'
builder: 'local' # Alternatives - 'external'
generators:
techdocs: 'docker'
techdocs: 'docker' # Alternatives - 'local'
publisher:
type: 'local'
type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives.
auth:
# see https://backstage.io/docs/tutorials/quickstart-app-auth to know more about enabling auth providers
@@ -13,34 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
import fs from 'fs-extra';
import path from 'path';
import {
getVoidLogger,
PluginEndpointDiscovery,
} from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
import mockFs from 'mock-fs';
import * as os from 'os';
import { LocalPublish } from './local';
jest.mock('fs-extra', () => {
const fsOriginal = jest.requireActual('fs-extra');
return {
...fsOriginal,
access: jest.fn().mockImplementation((path, checkType, callback) => {
if (
path.includes('http://localhost:7000/static') &&
checkType === fs.constants.F_OK
) {
callback();
} else {
callback(new Error());
}
}),
};
});
const createMockEntity = (annotations = {}) => {
return {
apiVersion: 'version',
@@ -56,43 +37,33 @@ const createMockEntity = (annotations = {}) => {
const logger = getVoidLogger();
const tmpDir =
os.platform() === 'win32' ? 'C:\\tmp\\generatedDir' : '/tmp/generatedDir';
describe('local publisher', () => {
it('should publish generated documentation dir', async () => {
const testDiscovery: jest.Mocked<PluginEndpointDiscovery> = {
getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7000'),
getExternalBaseUrl: jest.fn(),
};
const mockConfig = new ConfigReader({
techdocs: {
requestUrl: 'http://localhost:7000',
storageUrl: 'http://localhost:7000/static/docs',
mockFs({
[tmpDir]: {
'index.html': '',
},
});
const testDiscovery: jest.Mocked<PluginEndpointDiscovery> = {
getBaseUrl: jest
.fn()
.mockResolvedValue('http://localhost:7000/api/techdocs'),
getExternalBaseUrl: jest.fn(),
};
const mockConfig = new ConfigReader({});
const publisher = new LocalPublish(mockConfig, logger, testDiscovery);
const mockEntity = createMockEntity();
const tempDir = fs.mkdtempSync(`${__dirname}/test-component-folder-`);
expect(tempDir).toBeTruthy();
fs.closeSync(fs.openSync(path.join(tempDir, '/mock-file'), 'w'));
await publisher.publish({ entity: mockEntity, directory: tempDir });
const publishDir = path.resolve(
__dirname,
`../../../../../plugins/techdocs-backend/static/docs/${mockEntity.metadata.name}`,
);
const resultDir = path.resolve(
__dirname,
`../../../../../plugins/techdocs-backend/static/docs/default/${mockEntity.kind}/${mockEntity.metadata.name}`,
);
expect(fs.existsSync(resultDir)).toBeTruthy();
expect(fs.existsSync(path.join(resultDir, '/mock-file'))).toBeTruthy();
await publisher.publish({ entity: mockEntity, directory: tmpDir });
expect(await publisher.hasDocsBeenGenerated(mockEntity)).toBe(true);
fs.removeSync(publishDir);
fs.removeSync(tempDir);
mockFs.restore();
});
});
@@ -13,18 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fetch from 'cross-fetch';
import {
PluginEndpointDiscovery,
resolvePackagePath,
} from '@backstage/backend-common';
import { Entity, EntityName } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import express from 'express';
import fs from 'fs-extra';
import path from 'path';
import os from 'os';
import path from 'path';
import { Logger } from 'winston';
import { Entity, EntityName } from '@backstage/catalog-model';
import {
resolvePackagePath,
PluginEndpointDiscovery,
} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import {
PublisherBase,
PublishRequest,
@@ -52,17 +51,14 @@ try {
* called "static" at the root of techdocs-backend plugin.
*/
export class LocalPublish implements PublisherBase {
private readonly config: Config;
private readonly logger: Logger;
private readonly discovery: PluginEndpointDiscovery;
// TODO: Use a static fromConfig method to create a LocalPublish instance, similar to aws/gcs publishers.
// Move the logic of setting staticDocsDir based on config over to fromConfig,
// and set the value as a class parameter.
constructor(
config: Config,
logger: Logger,
discovery: PluginEndpointDiscovery,
// @ts-ignore
private readonly config: Config,
private readonly logger: Logger,
private readonly discovery: PluginEndpointDiscovery,
) {
this.config = config;
this.logger = logger;
@@ -107,34 +103,25 @@ export class LocalPublish implements PublisherBase {
});
}
fetchTechDocsMetadata(entityName: EntityName): Promise<TechDocsMetadata> {
return new Promise((resolve, reject) => {
this.discovery.getBaseUrl('techdocs').then(techdocsApiUrl => {
const storageUrl = new URL(
new URL(this.config.getString('techdocs.storageUrl')).pathname,
techdocsApiUrl,
).toString();
async fetchTechDocsMetadata(
entityName: EntityName,
): Promise<TechDocsMetadata> {
const metadataPath = path.join(
staticDocsDir,
entityName.namespace,
entityName.kind,
entityName.name,
'techdocs_metadata.json',
);
const entityRootDir = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;
const metadataURL = `${storageUrl}/${entityRootDir}/techdocs_metadata.json`;
fetch(metadataURL)
.then(response =>
response
.json()
.then(techdocsMetadata => resolve(techdocsMetadata))
.catch(err => {
reject(
`Unable to parse metadata JSON for ${entityRootDir}. Error: ${err}`,
);
}),
)
.catch(err => {
reject(
`Unable to fetch metadata for ${entityRootDir}. Error ${err}`,
);
});
});
});
try {
return await fs.readJson(metadataPath);
} catch (err) {
this.logger.error(
`Unable to read techdocs_metadata.json at ${metadataPath}. Error: ${err}`,
);
throw new Error(err.message);
}
}
docsRouter(): express.Handler {
@@ -143,24 +130,21 @@ export class LocalPublish implements PublisherBase {
async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {
const namespace = entity.metadata.namespace ?? 'default';
return new Promise(resolve => {
this.discovery.getBaseUrl('techdocs').then(techdocsApiUrl => {
const storageUrl = new URL(
new URL(this.config.getString('techdocs.storageUrl')).pathname,
techdocsApiUrl,
).toString();
const entityRootDir = `${namespace}/${entity.kind}/${entity.metadata.name}`;
const indexHtmlUrl = `${storageUrl}/${entityRootDir}/index.html`;
// Check if the file exists
fs.access(indexHtmlUrl, fs.constants.F_OK, err => {
if (err) {
resolve(false);
} else {
resolve(true);
}
});
});
});
const indexHtmlPath = path.join(
staticDocsDir,
namespace,
entity.kind,
entity.metadata.name,
'index.html',
);
// Check if the file exists
try {
fs.access(indexHtmlPath, fs.constants.F_OK);
return true;
} catch (err) {
return false;
}
}
}
+8 -7
View File
@@ -14,17 +14,12 @@
* limitations under the License.
*/
/**
* techdocs schema below is an abstract of what's used within techdocs-backend and for its visibility
* to view the complete techdoc schema please refer: plugins/techdocs/config.d.ts
* TechDocs schema below is an abstract of what's used within techdocs-backend and for its visibility
* to view the complete TechDocs schema please refer: plugins/techdocs/config.d.ts
* */
export interface Config {
/** Configuration options for the techdocs-backend plugin */
techdocs: {
/**
* attr: 'storageUrl' - accepts a string value
* e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs
*/
storageUrl: string;
/**
* documentation building process depends on the builder attr
* attr: 'builder' - accepts a string value
@@ -45,5 +40,11 @@ export interface Config {
*/
type: 'local' | 'googleGcs' | 'awsS3';
};
/**
* attr: 'storageUrl' - accepts a string value
* e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs
* @deprecated
*/
storageUrl?: string;
};
}
@@ -102,7 +102,9 @@ export async function createRouter({
router.get('/docs/:namespace/:kind/:name/*', async (req, res) => {
const { kind, namespace, name } = req.params;
const storageUrl = config.getString('techdocs.storageUrl');
const storageUrl =
config.getOptionalString('techdocs.storageUrl') ??
`${await discovery.getBaseUrl('techdocs')}/static/docs`;
const catalogUrl = await discovery.getBaseUrl('catalog');
const triple = [kind, namespace, name].map(encodeURIComponent).join('/');
+13 -11
View File
@@ -17,17 +17,6 @@
export interface Config {
/** Configuration options for the techdocs plugin */
techdocs: {
/**
* attr: 'requestUrl' - accepts a string value
* e.g. requestUrl: http://localhost:7000/api/techdocs
* @visibility frontend
*/
requestUrl: string;
/**
* attr: 'storageUrl' - accepts a string value
* e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs
*/
storageUrl: string;
/**
* documentation building process depends on the builder attr
* attr: 'builder' - accepts a string value
@@ -184,5 +173,18 @@ export interface Config {
credentials?: string;
};
};
/**
* attr: 'requestUrl' - accepts a string value
* e.g. requestUrl: http://localhost:7000/api/techdocs
* @visibility frontend
* @deprecated
*/
requestUrl?: string;
/**
* attr: 'storageUrl' - accepts a string value
* e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs
* @deprecated
*/
storageUrl?: string;
};
}
+29 -6
View File
@@ -13,20 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DiscoveryApi } from '@backstage/core';
import { Config } from '@backstage/config';
import { EntityName } from '@backstage/catalog-model';
import { TechDocsStorage } from '../src/api';
export class TechDocsDevStorageApi implements TechDocsStorage {
public apiOrigin: string;
public configApi: Config;
public discoveryApi: DiscoveryApi;
constructor({ apiOrigin }: { apiOrigin: string }) {
this.apiOrigin = apiOrigin;
constructor({
configApi,
discoveryApi,
}: {
configApi: Config;
discoveryApi: DiscoveryApi;
}) {
this.configApi = configApi;
this.discoveryApi = discoveryApi;
}
async getApiOrigin() {
return (
this.configApi.getOptionalString('techdocs.requestUrl') ??
(await this.discoveryApi.getBaseUrl('techdocs'))
);
}
async getEntityDocs(entityId: EntityName, path: string) {
const { name } = entityId;
const url = `${this.apiOrigin}/${name}/${path}`;
const apiOrigin = await this.getApiOrigin();
const url = `${apiOrigin}/${name}/${path}`;
const request = await fetch(
`${url.endsWith('/') ? url : `${url}/`}index.html`,
@@ -39,8 +57,13 @@ export class TechDocsDevStorageApi implements TechDocsStorage {
return request.text();
}
getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string {
async getBaseUrl(
oldBaseUrl: string,
entityId: EntityName,
path: string,
): Promise<string> {
const { name } = entityId;
return new URL(oldBaseUrl, `${this.apiOrigin}/${name}/${path}`).toString();
const apiOrigin = await this.getApiOrigin();
return new URL(oldBaseUrl, `${apiOrigin}/${name}/${path}`).toString();
}
}
+5 -3
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { configApiRef, discoveryApiRef } from '@backstage/core';
import { createDevApp } from '@backstage/dev-utils';
import { plugin } from '../src/plugin';
import { TechDocsDevStorageApi } from './api';
@@ -22,10 +23,11 @@ import { techdocsStorageApiRef } from '../src';
createDevApp()
.registerApi({
api: techdocsStorageApiRef,
deps: {},
factory: () =>
deps: { configApi: configApiRef, discoveryApi: discoveryApiRef },
factory: ({ configApi, discoveryApi }) =>
new TechDocsDevStorageApi({
apiOrigin: 'http://localhost:3000/api',
configApi,
discoveryApi,
}),
})
.registerPlugin(plugin)
+1
View File
@@ -31,6 +31,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.2",
"@backstage/catalog-model": "^0.7.0",
"@backstage/core": "^0.5.0",
"@backstage/plugin-catalog-react": "^0.0.1",
+22 -10
View File
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Config } from '@backstage/config';
import { UrlPatternDiscovery } from '@backstage/core';
import { TechDocsStorageApi } from './api';
const DOC_STORAGE_URL = 'https://example-storage.com';
const mockEntity = {
kind: 'Component',
namespace: 'default',
@@ -24,19 +24,31 @@ const mockEntity = {
};
describe('TechDocsStorageApi', () => {
it('should return correct base url based on defined storage', () => {
const storageApi = new TechDocsStorageApi({ apiOrigin: DOC_STORAGE_URL });
const mockBaseUrl = 'http://backstage:9191/api/techdocs';
const configApi = {
getOptionalString: () => 'http://backstage:9191/api/techdocs',
} as Partial<Config>;
const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl);
expect(storageApi.getBaseUrl('test.js', mockEntity, '')).toEqual(
`${DOC_STORAGE_URL}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`,
it('should return correct base url based on defined storage', async () => {
// @ts-ignore Partial<Config> not assignable to Config.
const storageApi = new TechDocsStorageApi({ configApi, discoveryApi });
await expect(
storageApi.getBaseUrl('test.js', mockEntity, ''),
).resolves.toEqual(
`${mockBaseUrl}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`,
);
});
it('should return base url with correct entity structure', () => {
const storageApi = new TechDocsStorageApi({ apiOrigin: DOC_STORAGE_URL });
it('should return base url with correct entity structure', async () => {
// @ts-ignore Partial<Config> not assignable to Config.
const storageApi = new TechDocsStorageApi({ configApi, discoveryApi });
expect(storageApi.getBaseUrl('test/', mockEntity, '')).toEqual(
`${DOC_STORAGE_URL}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test/`,
await expect(
storageApi.getBaseUrl('test/', mockEntity, ''),
).resolves.toEqual(
`${mockBaseUrl}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test/`,
);
});
});
+57 -13
View File
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import { createApiRef } from '@backstage/core';
import { createApiRef, DiscoveryApi } from '@backstage/core';
import { Config } from '@backstage/config';
import { EntityName } from '@backstage/catalog-model';
import { TechDocsMetadata } from './types';
@@ -30,7 +31,11 @@ export const techdocsApiRef = createApiRef<TechDocsApi>({
export interface TechDocsStorage {
getEntityDocs(entityId: EntityName, path: string): Promise<string>;
getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string;
getBaseUrl(
oldBaseUrl: string,
entityId: EntityName,
path: string,
): Promise<string>;
}
export interface TechDocs {
@@ -44,10 +49,25 @@ export interface TechDocs {
* @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API
*/
export class TechDocsApi implements TechDocs {
public apiOrigin: string;
public configApi: Config;
public discoveryApi: DiscoveryApi;
constructor({ apiOrigin }: { apiOrigin: string }) {
this.apiOrigin = apiOrigin;
constructor({
configApi,
discoveryApi,
}: {
configApi: Config;
discoveryApi: DiscoveryApi;
}) {
this.configApi = configApi;
this.discoveryApi = discoveryApi;
}
async getApiOrigin() {
return (
this.configApi.getOptionalString('techdocs.requestUrl') ??
(await this.discoveryApi.getBaseUrl('techdocs'))
);
}
/**
@@ -62,7 +82,8 @@ export class TechDocsApi implements TechDocs {
async getTechDocsMetadata(entityId: EntityName) {
const { kind, namespace, name } = entityId;
const requestUrl = `${this.apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`;
const apiOrigin = await this.getApiOrigin();
const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`;
const request = await fetch(`${requestUrl}`);
const res = await request.json();
@@ -81,7 +102,8 @@ export class TechDocsApi implements TechDocs {
async getEntityMetadata(entityId: EntityName) {
const { kind, namespace, name } = entityId;
const requestUrl = `${this.apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`;
const apiOrigin = await this.getApiOrigin();
const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`;
const request = await fetch(`${requestUrl}`);
const res = await request.json();
@@ -96,10 +118,25 @@ export class TechDocsApi implements TechDocs {
* @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API
*/
export class TechDocsStorageApi implements TechDocsStorage {
public apiOrigin: string;
public configApi: Config;
public discoveryApi: DiscoveryApi;
constructor({ apiOrigin }: { apiOrigin: string }) {
this.apiOrigin = apiOrigin;
constructor({
configApi,
discoveryApi,
}: {
configApi: Config;
discoveryApi: DiscoveryApi;
}) {
this.configApi = configApi;
this.discoveryApi = discoveryApi;
}
async getApiOrigin() {
return (
this.configApi.getOptionalString('techdocs.requestUrl') ??
(await this.discoveryApi.getBaseUrl('techdocs'))
);
}
/**
@@ -113,7 +150,8 @@ export class TechDocsStorageApi implements TechDocsStorage {
async getEntityDocs(entityId: EntityName, path: string) {
const { kind, namespace, name } = entityId;
const url = `${this.apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`;
const apiOrigin = await this.getApiOrigin();
const url = `${apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`;
const request = await fetch(
`${url.endsWith('/') ? url : `${url}/`}index.html`,
@@ -132,12 +170,18 @@ export class TechDocsStorageApi implements TechDocsStorage {
return request.text();
}
getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string {
async getBaseUrl(
oldBaseUrl: string,
entityId: EntityName,
path: string,
): Promise<string> {
const { kind, namespace, name } = entityId;
const apiOrigin = await this.getApiOrigin();
return new URL(
oldBaseUrl,
`${this.apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`,
`${apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`,
).toString();
}
}
+9 -7
View File
@@ -34,6 +34,7 @@ import {
createRouteRef,
createApiFactory,
configApiRef,
discoveryApiRef,
} from '@backstage/core';
import {
techdocsStorageApiRef,
@@ -57,24 +58,25 @@ export const rootCatalogDocsRouteRef = createRouteRef({
title: 'Docs',
});
// TODO: Use discovery API for frontend to get URL for techdocs-backend instead of requestUrl
export const plugin = createPlugin({
id: 'techdocs',
apis: [
createApiFactory({
api: techdocsStorageApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) =>
deps: { configApi: configApiRef, discoveryApi: discoveryApiRef },
factory: ({ configApi, discoveryApi }) =>
new TechDocsStorageApi({
apiOrigin: configApi.getString('techdocs.requestUrl'),
configApi,
discoveryApi,
}),
}),
createApiFactory({
api: techdocsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) =>
deps: { configApi: configApiRef, discoveryApi: discoveryApiRef },
factory: ({ configApi, discoveryApi }) =>
new TechDocsApi({
apiOrigin: configApi.getString('techdocs.requestUrl'),
configApi,
discoveryApi,
}),
}),
],
@@ -129,7 +129,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
},
}),
onCssReady({
docStorageUrl: techdocsStorageApi.apiOrigin,
docStorageUrl: techdocsStorageApi.getApiOrigin(),
onLoading: (dom: Element) => {
(dom as HTMLElement).style.setProperty('opacity', '0');
},
@@ -56,7 +56,8 @@ describe('<TechDocsPage />', () => {
};
const techdocsStorageApi: Partial<TechDocsStorageApi> = {
getEntityDocs: (): Promise<string> => Promise.resolve('String'),
getBaseUrl: (): string => '',
getBaseUrl: (): Promise<string> => Promise.resolve('String'),
getApiOrigin: (): Promise<string> => Promise.resolve('String'),
};
const apiRegistry = ApiRegistry.from([
@@ -21,7 +21,7 @@ import { TechDocsStorage } from '../../api';
const DOC_STORAGE_URL = 'https://example-host.storage.googleapis.com';
const techdocsStorageApi: TechDocsStorage = {
getBaseUrl: jest.fn(() => DOC_STORAGE_URL),
getBaseUrl: jest.fn(() => Promise.resolve(DOC_STORAGE_URL)),
getEntityDocs: () => new Promise(resolve => resolve('yes!')),
};
@@ -35,12 +35,12 @@ export const addBaseUrl = ({
): void => {
Array.from(list)
.filter(elem => !!elem.getAttribute(attributeName))
.forEach((elem: T) => {
.forEach(async (elem: T) => {
const elemAttribute = elem.getAttribute(attributeName);
if (!elemAttribute) return;
elem.setAttribute(
attributeName,
techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path),
await techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path),
);
});
};
@@ -22,8 +22,9 @@ import {
} from '../../test-utils';
import { onCssReady } from '../transformers';
const docStorageUrl: string =
'https://techdocs-mock-sites.storage.googleapis.com';
const docStorageUrl: Promise<string> = Promise.resolve(
'https://techdocs-mock-sites.storage.googleapis.com',
);
const fixture = `
<link rel="stylesheet" href="${docStorageUrl}/test.css" />
@@ -17,7 +17,7 @@
import type { Transformer } from './index';
type OnCssReadyOptions = {
docStorageUrl: string;
docStorageUrl: Promise<string>;
onLoading: (dom: Element) => void;
onLoaded: (dom: Element) => void;
};
@@ -30,7 +30,9 @@ export const onCssReady = ({
return dom => {
const cssPages = Array.from(
dom.querySelectorAll('head > link[rel="stylesheet"]'),
).filter(elem => elem.getAttribute('href')?.startsWith(docStorageUrl));
).filter(async elem =>
elem.getAttribute('href')?.startsWith(await docStorageUrl),
);
let count = cssPages.length;