Introduce Lighthouse Backend with Scheduling of Audits
Signed-off-by: Dominik Pfaffenbauer <dominik@pfaffenbauer.at>
This commit is contained in:
@@ -14,181 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export type LighthouseCategoryId =
|
||||
| 'pwa'
|
||||
| 'seo'
|
||||
| 'performance'
|
||||
| 'accessibility'
|
||||
| 'best-practices';
|
||||
|
||||
/** @public */
|
||||
export interface LighthouseCategoryAbbr {
|
||||
id: LighthouseCategoryId;
|
||||
score: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface LASListRequest {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface LASListResponse<Item> {
|
||||
items: Item[];
|
||||
total: number;
|
||||
offset: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface AuditBase {
|
||||
id: string;
|
||||
url: string;
|
||||
timeCreated: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface AuditRunning extends AuditBase {
|
||||
status: 'RUNNING';
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface AuditFailed extends AuditBase {
|
||||
status: 'FAILED';
|
||||
timeCompleted: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface AuditCompleted extends AuditBase {
|
||||
status: 'COMPLETED';
|
||||
timeCompleted: string;
|
||||
report: Object;
|
||||
categories: Record<LighthouseCategoryId, LighthouseCategoryAbbr>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type Audit = AuditRunning | AuditFailed | AuditCompleted;
|
||||
|
||||
/** @public */
|
||||
export interface Website {
|
||||
url: string;
|
||||
audits: Audit[];
|
||||
lastAudit: Audit;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type WebsiteListResponse = LASListResponse<Website>;
|
||||
|
||||
/** @public */
|
||||
export type FormFactor = 'mobile' | 'desktop';
|
||||
|
||||
/** @public */
|
||||
export type LighthouseConfigSettings = {
|
||||
// For lighthouse 7+
|
||||
formFactor: FormFactor;
|
||||
screenEmulation:
|
||||
| {
|
||||
mobile: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
deviceScaleFactor: number;
|
||||
disabled: boolean;
|
||||
}
|
||||
| undefined;
|
||||
// For lighthouse before 7
|
||||
emulatedFormFactor: FormFactor;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface TriggerAuditPayload {
|
||||
url: string;
|
||||
options: {
|
||||
lighthouseConfig: {
|
||||
settings: LighthouseConfigSettings;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class FetchError extends Error {
|
||||
get name(): string {
|
||||
return this.constructor.name;
|
||||
}
|
||||
|
||||
static async forResponse(resp: Response): Promise<FetchError> {
|
||||
return new FetchError(
|
||||
`Request failed with status code ${
|
||||
resp.status
|
||||
}.\nReason: ${await resp.text()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type LighthouseApi = {
|
||||
url: string;
|
||||
getWebsiteList: (listOptions: LASListRequest) => Promise<WebsiteListResponse>;
|
||||
getWebsiteForAuditId: (auditId: string) => Promise<Website>;
|
||||
triggerAudit: (payload: TriggerAuditPayload) => Promise<Audit>;
|
||||
getWebsiteByUrl: (websiteUrl: string) => Promise<Website>;
|
||||
};
|
||||
import { LighthouseApi } from '@backstage/plugin-lighthouse-common';
|
||||
|
||||
/** @public */
|
||||
export const lighthouseApiRef = createApiRef<LighthouseApi>({
|
||||
id: 'plugin.lighthouse.service',
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export class LighthouseRestApi implements LighthouseApi {
|
||||
static fromConfig(config: Config) {
|
||||
return new LighthouseRestApi(config.getString('lighthouse.baseUrl'));
|
||||
}
|
||||
|
||||
constructor(public url: string) {}
|
||||
|
||||
private async fetch<T = any>(input: string, init?: RequestInit): Promise<T> {
|
||||
const resp = await fetch(`${this.url}${input}`, init);
|
||||
if (!resp.ok) throw await FetchError.forResponse(resp);
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
async getWebsiteList(
|
||||
options: LASListRequest = {},
|
||||
): Promise<WebsiteListResponse> {
|
||||
const { limit, offset } = options;
|
||||
const params = new URLSearchParams();
|
||||
if (typeof limit === 'number') params.append('limit', limit.toString());
|
||||
if (typeof offset === 'number') params.append('offset', offset.toString());
|
||||
return await this.fetch<WebsiteListResponse>(
|
||||
`/v1/websites?${params.toString()}`,
|
||||
);
|
||||
}
|
||||
|
||||
async getWebsiteForAuditId(auditId: string): Promise<Website> {
|
||||
return await this.fetch<Website>(
|
||||
`/v1/audits/${encodeURIComponent(auditId)}/website`,
|
||||
);
|
||||
}
|
||||
|
||||
async triggerAudit(payload: TriggerAuditPayload): Promise<Audit> {
|
||||
return await this.fetch<Audit>('/v1/audits', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getWebsiteByUrl(websiteUrl: string): Promise<Website> {
|
||||
return this.fetch<Website>(
|
||||
`/v1/websites/${encodeURIComponent(websiteUrl)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import React from 'react';
|
||||
import {
|
||||
lighthouseApiRef,
|
||||
LighthouseRestApi,
|
||||
WebsiteListResponse,
|
||||
} from '../../api';
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import { useWebsiteForEntity } from '../../hooks/useWebsiteForEntity';
|
||||
import * as data from '../../__fixtures__/website-list-response.json';
|
||||
import { AuditListForEntity } from './AuditListForEntity';
|
||||
|
||||
@@ -25,9 +25,9 @@ import AuditListTable from './AuditListTable';
|
||||
|
||||
import {
|
||||
WebsiteListResponse,
|
||||
lighthouseApiRef,
|
||||
LighthouseRestApi,
|
||||
} from '../../api';
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import { formatTime } from '../../utils';
|
||||
import { setupServer } from 'msw/node';
|
||||
import * as data from '../../__fixtures__/website-list-response.json';
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Website, lighthouseApiRef } from '../../api';
|
||||
import { Website } from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import useInterval from 'react-use/lib/useInterval';
|
||||
import {
|
||||
formatTime,
|
||||
|
||||
@@ -33,10 +33,10 @@ import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import React from 'react';
|
||||
import {
|
||||
lighthouseApiRef,
|
||||
LighthouseRestApi,
|
||||
WebsiteListResponse,
|
||||
} from '../../api';
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import * as data from '../../__fixtures__/website-list-response.json';
|
||||
import AuditList from './index';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Audit } from '../../api';
|
||||
import { Audit } from '@backstage/plugin-lighthouse-common';
|
||||
import {
|
||||
StatusError,
|
||||
StatusOK,
|
||||
|
||||
@@ -38,7 +38,12 @@ import { render } from '@testing-library/react';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import React from 'react';
|
||||
import { Audit, lighthouseApiRef, LighthouseRestApi, Website } from '../../api';
|
||||
import {
|
||||
Audit,
|
||||
LighthouseRestApi,
|
||||
Website,
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import { formatTime } from '../../utils';
|
||||
import * as data from '../../__fixtures__/website-response.json';
|
||||
import AuditView from './index';
|
||||
|
||||
@@ -33,7 +33,8 @@ import {
|
||||
useParams,
|
||||
} from 'react-router-dom';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Audit, lighthouseApiRef, Website } from '../../api';
|
||||
import { Audit, Website } from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import { formatTime } from '../../utils';
|
||||
import AuditStatusIcon from '../AuditStatusIcon';
|
||||
import LighthouseSupportButton from '../SupportButton';
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
AuditCompleted,
|
||||
LighthouseCategoryId,
|
||||
WebsiteListResponse,
|
||||
} from '../../api';
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { useWebsiteForEntity } from '../../hooks/useWebsiteForEntity';
|
||||
import * as data from '../../__fixtures__/website-list-response.json';
|
||||
import { LastLighthouseAuditCard } from './LastLighthouseAuditCard';
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Audit, AuditCompleted, LighthouseCategoryId } from '../../api';
|
||||
import {
|
||||
Audit,
|
||||
AuditCompleted,
|
||||
LighthouseCategoryId,
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { useWebsiteForEntity } from '../../hooks/useWebsiteForEntity';
|
||||
import AuditStatusIcon from '../AuditStatusIcon';
|
||||
import {
|
||||
|
||||
@@ -32,7 +32,8 @@ import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import React from 'react';
|
||||
import { Audit, lighthouseApiRef, LighthouseRestApi } from '../../api';
|
||||
import { Audit, LighthouseRestApi } from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import * as data from '../../__fixtures__/create-audit-response.json';
|
||||
import CreateAudit from './index';
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ import React, { useCallback, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
FormFactor,
|
||||
lighthouseApiRef,
|
||||
LighthouseConfigSettings,
|
||||
} from '../../api';
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../../api';
|
||||
import { useQuery } from '../../utils';
|
||||
import LighthouseSupportButton from '../SupportButton';
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ import { Entity } from '@backstage/catalog-model';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { lighthouseApiRef, WebsiteListResponse } from '../api';
|
||||
import { WebsiteListResponse } from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from '../api';
|
||||
import * as data from '../__fixtures__/website-list-response.json';
|
||||
import { useWebsiteForEntity } from './useWebsiteForEntity';
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { lighthouseApiRef, LighthouseRestApi } from './api';
|
||||
import { LighthouseRestApi } from '@backstage/plugin-lighthouse-common';
|
||||
import { lighthouseApiRef } from './api';
|
||||
import {
|
||||
createPlugin,
|
||||
createRouteRef,
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Website, Audit, LighthouseCategoryId, AuditCompleted } from './api';
|
||||
import {
|
||||
Website,
|
||||
Audit,
|
||||
LighthouseCategoryId,
|
||||
AuditCompleted,
|
||||
} from '@backstage/plugin-lighthouse-common';
|
||||
|
||||
export function useQuery(): URLSearchParams {
|
||||
return new URLSearchParams(useLocation().search);
|
||||
|
||||
Reference in New Issue
Block a user