diff --git a/.changeset/lovely-peaches-fold.md b/.changeset/lovely-peaches-fold.md new file mode 100644 index 0000000000..dcff35f4d7 --- /dev/null +++ b/.changeset/lovely-peaches-fold.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights': patch +--- + +making available the search for the last FACTS executed diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md index 03155a5958..2d25d6d39d 100644 --- a/plugins/tech-insights/api-report.md +++ b/plugins/tech-insights/api-report.md @@ -12,6 +12,7 @@ import { CheckResult } from '@backstage/plugin-tech-insights-common'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; +import { JsonValue } from '@backstage/types'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; @@ -51,6 +52,16 @@ export const EntityTechInsightsScorecardContent: (props: { checksId?: string[] | undefined; }) => JSX.Element; +// @public +export interface InsightFacts { + // (undocumented) + [factId: string]: { + timestamp: string; + version: string; + facts: Record; + }; +} + // @public export const jsonRulesEngineCheckResultRenderer: CheckResultRenderer; @@ -61,6 +72,8 @@ export interface TechInsightsApi { // (undocumented) getCheckResultRenderers: (types: string[]) => CheckResultRenderer[]; // (undocumented) + getFacts(entity: CompoundEntityRef, facts: string[]): Promise; + // (undocumented) runBulkChecks( entities: CompoundEntityRef[], checks?: Check[], @@ -87,6 +100,8 @@ export class TechInsightsClient implements TechInsightsApi { // (undocumented) getCheckResultRenderers(types: string[]): CheckResultRenderer[]; // (undocumented) + getFacts(entity: CompoundEntityRef, facts: string[]): Promise; + // (undocumented) runBulkChecks( entities: CompoundEntityRef[], checks?: Check[], diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index f308017fa0..9c940d4d55 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -38,6 +38,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", + "qs": "^6.9.4", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/tech-insights/src/api/TechInsightsApi.ts b/plugins/tech-insights/src/api/TechInsightsApi.ts index 8ab1090304..166f1d2782 100644 --- a/plugins/tech-insights/src/api/TechInsightsApi.ts +++ b/plugins/tech-insights/src/api/TechInsightsApi.ts @@ -19,7 +19,7 @@ import { CheckResult, BulkCheckResponse, } from '@backstage/plugin-tech-insights-common'; -import { Check } from './types'; +import { Check, InsightFacts } from './types'; import { CheckResultRenderer } from '../components/CheckResultRenderer'; import { CompoundEntityRef } from '@backstage/catalog-model'; @@ -48,4 +48,5 @@ export interface TechInsightsApi { entities: CompoundEntityRef[], checks?: Check[], ): Promise; + getFacts(entity: CompoundEntityRef, facts: string[]): Promise; } diff --git a/plugins/tech-insights/src/api/TechInsightsClient.ts b/plugins/tech-insights/src/api/TechInsightsClient.ts index 8db5de3945..9bdeb119f9 100644 --- a/plugins/tech-insights/src/api/TechInsightsClient.ts +++ b/plugins/tech-insights/src/api/TechInsightsClient.ts @@ -19,15 +19,19 @@ import { BulkCheckResponse, CheckResult, } from '@backstage/plugin-tech-insights-common'; -import { Check } from './types'; +import { Check, InsightFacts } from './types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; import { ResponseError } from '@backstage/errors'; -import { CompoundEntityRef } from '@backstage/catalog-model'; +import { + CompoundEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { CheckResultRenderer, jsonRulesEngineCheckResultRenderer, } from '../components/CheckResultRenderer'; +import qs from 'qs'; /** @public */ export class TechInsightsClient implements TechInsightsApi { @@ -45,76 +49,75 @@ export class TechInsightsClient implements TechInsightsApi { this.renderers = options.renderers; } + async getFacts( + entity: CompoundEntityRef, + facts: string[], + ): Promise { + const query = qs.stringify({ + entity: stringifyEntityRef(entity), + ids: facts, + }); + return await this.api(`/facts/latest?${query}`); + } + getCheckResultRenderers(types: string[]): CheckResultRenderer[] { const renderers = this.renderers ?? [jsonRulesEngineCheckResultRenderer]; return renderers.filter(d => types.includes(d.type)); } async getAllChecks(): Promise { - const url = await this.discoveryApi.getBaseUrl('tech-insights'); - const { token } = await this.identityApi.getCredentials(); - const response = await fetch(`${url}/checks`, { - headers: token - ? { - Authorization: `Bearer ${token}`, - } - : undefined, - }); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - return await response.json(); + return this.api('/checks'); } async runChecks( entityParams: CompoundEntityRef, checks?: string[], ): Promise { - const url = await this.discoveryApi.getBaseUrl('tech-insights'); - const { token } = await this.identityApi.getCredentials(); const { namespace, kind, name } = entityParams; const requestBody = { checks }; - const response = await fetch( - `${url}/checks/run/${encodeURIComponent(namespace)}/${encodeURIComponent( + return this.api( + `/checks/run/${encodeURIComponent(namespace)}/${encodeURIComponent( kind, )}/${encodeURIComponent(name)}`, { method: 'POST', body: JSON.stringify(requestBody), - headers: { - 'Content-Type': 'application/json', - ...(token && { Authorization: `Bearer ${token}` }), - }, }, ); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - return await response.json(); } async runBulkChecks( entities: CompoundEntityRef[], checks?: Check[], ): Promise { - const url = await this.discoveryApi.getBaseUrl('tech-insights'); - const { token } = await this.identityApi.getCredentials(); const checkIds = checks ? checks.map(check => check.id) : []; const requestBody = { entities, checks: checkIds.length > 0 ? checkIds : undefined, }; - const response = await fetch(`${url}/checks/run`, { + return this.api('/checks/run', { method: 'POST', body: JSON.stringify(requestBody), - headers: { - 'Content-Type': 'application/json', - ...(token && { Authorization: `Bearer ${token}` }), - }, }); - if (!response.ok) { - throw await ResponseError.fromResponse(response); + } + + private async api(path: string, init?: RequestInit): Promise { + const url = await this.discoveryApi.getBaseUrl('tech-insights'); + const { token } = await this.identityApi.getCredentials(); + + const request = new Request(`${url}${path}`, init); + if (!request.headers.has('content-type')) { + request.headers.set('content-type', 'application/json'); } - return await response.json(); + if (token && !request.headers.has('authorization')) { + request.headers.set('authorization', `Bearer ${token}`); + } + + return fetch(request).then(async response => { + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + return response.json() as Promise; + }); } } diff --git a/plugins/tech-insights/src/api/types.ts b/plugins/tech-insights/src/api/types.ts index 10dfa06420..ac1f2e44ee 100644 --- a/plugins/tech-insights/src/api/types.ts +++ b/plugins/tech-insights/src/api/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { JsonValue } from '@backstage/types'; + /** * Represents a single check defined on the TechInsights backend. * @@ -26,3 +28,16 @@ export type Check = { description: string; factIds: string[]; }; + +/** + * Represents a Fact defined on the TechInsights backend. + * + * @public + */ +export interface InsightFacts { + [factId: string]: { + timestamp: string; + version: string; + facts: Record; + }; +} diff --git a/plugins/tech-insights/src/index.ts b/plugins/tech-insights/src/index.ts index f3dd05c3aa..9e075df038 100644 --- a/plugins/tech-insights/src/index.ts +++ b/plugins/tech-insights/src/index.ts @@ -20,7 +20,7 @@ export { } from './plugin'; export { techInsightsApiRef, TechInsightsClient } from './api'; -export type { TechInsightsApi, Check } from './api'; +export type { TechInsightsApi, Check, InsightFacts } from './api'; export { BooleanCheck } from './components/BooleanCheck'; export { jsonRulesEngineCheckResultRenderer } from './components/CheckResultRenderer'; export type { CheckResultRenderer } from './components/CheckResultRenderer'; diff --git a/yarn.lock b/yarn.lock index 7776d00e77..659cfd8cad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7229,6 +7229,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 msw: ^0.47.0 + qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0