diff --git a/.changeset/cold-feet-drop.md b/.changeset/cold-feet-drop.md
new file mode 100644
index 0000000000..2d9daf0c1b
--- /dev/null
+++ b/.changeset/cold-feet-drop.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-tech-insights-common': minor
+---
+
+Added new property 'result' in CheckResult in @backstage/plugin-tech-insights-common. This property is later used in `@backstage/plugin-tech-insights` package.
diff --git a/.changeset/hungry-bikes-leave.md b/.changeset/hungry-bikes-leave.md
new file mode 100644
index 0000000000..b6ac827cfe
--- /dev/null
+++ b/.changeset/hungry-bikes-leave.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-tech-insights-backend': patch
+---
+
+Removed unnecessary check for specific server error in `@backstage plugin-tech-insights-backend`.
diff --git a/.changeset/stupid-readers-cough.md b/.changeset/stupid-readers-cough.md
new file mode 100644
index 0000000000..82119ed695
--- /dev/null
+++ b/.changeset/stupid-readers-cough.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-tech-insights': minor
+---
+
+New package containing UI components for the Tech Insights plugin.
diff --git a/packages/app/package.json b/packages/app/package.json
index 09141f7cf7..d0ac17542a 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -44,6 +44,7 @@
"@backstage/plugin-todo": "^0.1.15",
"@backstage/plugin-user-settings": "^0.3.11",
"@backstage/search-common": "^0.2.0",
+ "@backstage/plugin-tech-insights": "^0.0.0",
"@backstage/theme": "^0.2.11",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
diff --git a/plugins/tech-insights-backend/src/service/router.ts b/plugins/tech-insights-backend/src/service/router.ts
index a8951318ea..80902c307c 100644
--- a/plugins/tech-insights-backend/src/service/router.ts
+++ b/plugins/tech-insights-backend/src/service/router.ts
@@ -92,11 +92,6 @@ export async function createRouter<
router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {
const { namespace, kind, name } = req.params;
try {
- if (!('checks' in req.body)) {
- return res.status(422).send({
- message: 'Failed to get checks from request.',
- });
- }
const { checks }: { checks: string[] } = req.body;
const entityTriplet = stringifyEntityRef({ namespace, kind, name });
const checkResult = await factChecker.runChecks(entityTriplet, checks);
diff --git a/plugins/tech-insights-common/api-report.md b/plugins/tech-insights-common/api-report.md
index ddb38cfa85..8618f6266b 100644
--- a/plugins/tech-insights-common/api-report.md
+++ b/plugins/tech-insights-common/api-report.md
@@ -4,6 +4,7 @@
```ts
import { DateTime } from 'luxon';
+import { JsonValue } from '@backstage/types';
// @public
export interface BooleanCheckResult extends CheckResult {
@@ -25,6 +26,7 @@ export interface CheckResponse {
export type CheckResult = {
facts: FactResponse;
check: CheckResponse;
+ result: JsonValue;
};
// @public
diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json
index 26d8922329..2476b120ec 100644
--- a/plugins/tech-insights-common/package.json
+++ b/plugins/tech-insights-common/package.json
@@ -31,7 +31,8 @@
},
"dependencies": {
"@types/luxon": "^2.0.5",
- "luxon": "^2.0.2"
+ "luxon": "^2.0.2",
+ "@backstage/types": "^0.1.1"
},
"devDependencies": {
"@backstage/cli": "^0.9.0"
diff --git a/plugins/tech-insights-common/src/index.ts b/plugins/tech-insights-common/src/index.ts
index 4bfc660748..ecdaa298c1 100644
--- a/plugins/tech-insights-common/src/index.ts
+++ b/plugins/tech-insights-common/src/index.ts
@@ -15,6 +15,7 @@
*/
import { DateTime } from 'luxon';
+import { JsonValue } from '@backstage/types';
/**
* @public
@@ -112,6 +113,7 @@ export type FactResponse = {
export type CheckResult = {
facts: FactResponse;
check: CheckResponse;
+ result: JsonValue;
};
/**
diff --git a/plugins/tech-insights/.eslintrc.js b/plugins/tech-insights/.eslintrc.js
new file mode 100644
index 0000000000..13573efa9c
--- /dev/null
+++ b/plugins/tech-insights/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: [require.resolve('@backstage/cli/config/eslint')],
+};
diff --git a/plugins/tech-insights/README.md b/plugins/tech-insights/README.md
new file mode 100644
index 0000000000..b61cea48ec
--- /dev/null
+++ b/plugins/tech-insights/README.md
@@ -0,0 +1,47 @@
+# Tech Insights
+
+This plugin provides the UI for the `@backstage/tech-insights-backend` plugin, in order to display results of the checks running following the rules and the logic defined in the `@backstage/tech-insights-backend` plugin itself.
+
+Main areas covered by this plugin currently are:
+
+- Providing an overview for default boolean checks in a form of Scorecards.
+
+- Providing an option to render different custom components based on type of the checks running in the backend.
+
+## Installation
+
+### Install the plugin
+
+```bash
+# From your Backstage root directory
+cd packages/app
+yarn add @backstage/plugin-tech-insights
+```
+
+### Add boolean checks overview (Scorecards) page to the EntityPage:
+
+```tsx
+// packages/app/src/components/catalog/EntityPage.tsx
+
+import { EntityTechInsightsScorecardContent } from '@backstage/plugin-tech-insights';
+
+const serviceEntityPage = (
+
+
+ {overviewContent}
+
+
+ {cicdContent}
+
+ ...
+
+
+
+ ...
+
+);
+```
+
+## Links
+
+- [The Backstage homepage](https://backstage.io)
diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md
new file mode 100644
index 0000000000..e7f30a2b30
--- /dev/null
+++ b/plugins/tech-insights/api-report.md
@@ -0,0 +1,23 @@
+## API Report File for "@backstage/plugin-tech-insights"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+///
+
+import { BackstagePlugin } from '@backstage/core-plugin-api';
+import { RouteRef } from '@backstage/core-plugin-api';
+
+// @public (undocumented)
+export const EntityTechInsightsScorecardContent: () => JSX.Element;
+
+// @public (undocumented)
+export const techInsightsPlugin: BackstagePlugin<
+ {
+ root: RouteRef;
+ },
+ {}
+>;
+
+// (No @packageDocumentation comment for this package)
+```
diff --git a/plugins/tech-insights/dev/index.tsx b/plugins/tech-insights/dev/index.tsx
new file mode 100644
index 0000000000..17b1fca00e
--- /dev/null
+++ b/plugins/tech-insights/dev/index.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 React from 'react';
+import { createDevApp } from '@backstage/dev-utils';
+import {
+ techInsightsPlugin,
+ EntityTechInsightsScorecardContent,
+} from '../src/plugin';
+
+createDevApp()
+ .registerPlugin(techInsightsPlugin)
+ .addPage({
+ element: ,
+ title: 'Root Page',
+ path: '/tech-insight-scorecard',
+ })
+ .render();
diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json
new file mode 100644
index 0000000000..79d184f0a5
--- /dev/null
+++ b/plugins/tech-insights/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@backstage/plugin-tech-insights",
+ "version": "0.0.0",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "scripts": {
+ "build": "backstage-cli plugin:build",
+ "start": "backstage-cli plugin:serve",
+ "lint": "backstage-cli lint",
+ "test": "backstage-cli test",
+ "diff": "backstage-cli plugin:diff",
+ "prepack": "backstage-cli prepack",
+ "postpack": "backstage-cli postpack",
+ "clean": "backstage-cli clean"
+ },
+ "dependencies": {
+ "@backstage/core-components": "^0.7.5",
+ "@backstage/core-plugin-api": "^0.2.1",
+ "@backstage/theme": "^0.2.13",
+ "@material-ui/core": "^4.12.2",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.57",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1",
+ "react-use": "^17.2.4",
+ "react-router-dom": "6.0.0-beta.0",
+ "@backstage/plugin-catalog-react": "^0.6.4",
+ "@backstage/plugin-tech-insights-common": "^0.1.0",
+ "@backstage/catalog-model": "^0.9.7",
+ "@backstage/errors": "^0.1.4",
+ "@backstage/types": "^0.1.1"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.9.1",
+ "@backstage/core-app-api": "^0.1.23",
+ "@backstage/dev-utils": "^0.2.13",
+ "@backstage/test-utils": "^0.1.23",
+ "@testing-library/jest-dom": "^5.10.1",
+ "@testing-library/react": "^11.2.5",
+ "@testing-library/user-event": "^13.1.8",
+ "@types/jest": "^26.0.7",
+ "@types/node": "^14.14.32",
+ "msw": "^0.35.0",
+ "cross-fetch": "^3.0.6"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/tech-insights/src/api/TechInsightsApi.ts b/plugins/tech-insights/src/api/TechInsightsApi.ts
new file mode 100644
index 0000000000..2c55930f0a
--- /dev/null
+++ b/plugins/tech-insights/src/api/TechInsightsApi.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 { createApiRef } from '@backstage/core-plugin-api';
+import { CheckResult } from '@backstage/plugin-tech-insights-common';
+import { Check } from './types';
+import { CheckResultRenderer } from '../components/CheckResultRenderer';
+import { EntityName } from '@backstage/catalog-model';
+
+export const techInsightsApiRef = createApiRef({
+ id: 'plugin.techinsights.service',
+ description: 'Used by the tech insights plugin to make requests',
+});
+
+export interface TechInsightsApi {
+ getScorecardsDefinition: (
+ type: string,
+ value: CheckResult[],
+ ) => CheckResultRenderer | undefined;
+ getAllChecks(): Promise;
+ runChecks(entityParams: EntityName, checks?: Check[]): Promise;
+}
diff --git a/plugins/tech-insights/src/api/TechInsightsClient.ts b/plugins/tech-insights/src/api/TechInsightsClient.ts
new file mode 100644
index 0000000000..25002e30a1
--- /dev/null
+++ b/plugins/tech-insights/src/api/TechInsightsClient.ts
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 { TechInsightsApi } from './TechInsightsApi';
+import { CheckResult } from '@backstage/plugin-tech-insights-common';
+import { Check } from './types';
+import { DiscoveryApi } from '@backstage/core-plugin-api';
+import { ResponseError } from '@backstage/errors';
+import { EntityName } from '@backstage/catalog-model';
+
+import {
+ CheckResultRenderer,
+ defaultCheckResultRenderers,
+} from '../components/CheckResultRenderer';
+
+export type Options = {
+ discoveryApi: DiscoveryApi;
+};
+
+export class TechInsightsClient implements TechInsightsApi {
+ private readonly discoveryApi: DiscoveryApi;
+
+ constructor(options: Options) {
+ this.discoveryApi = options.discoveryApi;
+ }
+
+ getScorecardsDefinition(
+ type: string,
+ value: CheckResult[],
+ ): CheckResultRenderer | undefined {
+ const resultRenderers = defaultCheckResultRenderers(value);
+ return resultRenderers.find(d => d.type === type);
+ }
+
+ async getAllChecks(): Promise {
+ const url = await this.discoveryApi.getBaseUrl('tech-insights');
+ const response = await fetch(`${url}/checks`);
+ if (!response.ok) {
+ throw await ResponseError.fromResponse(response);
+ }
+ return await response.json();
+ }
+
+ async runChecks(
+ entityParams: EntityName,
+ checks: Check[],
+ ): Promise {
+ const url = await this.discoveryApi.getBaseUrl('tech-insights');
+ const { namespace, kind, name } = entityParams;
+ const allChecks = checks ? checks : await this.getAllChecks();
+ const checkIds = allChecks.map((check: Check) => check.id);
+ const response = await fetch(
+ `${url}/checks/run/${encodeURIComponent(namespace)}/${encodeURIComponent(
+ kind,
+ )}/${encodeURIComponent(name)}`,
+ {
+ method: 'POST',
+ body: JSON.stringify({ checks: checkIds }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ );
+ if (!response.ok) {
+ throw await ResponseError.fromResponse(response);
+ }
+ return await response.json();
+ }
+}
diff --git a/plugins/tech-insights/src/api/index.ts b/plugins/tech-insights/src/api/index.ts
new file mode 100644
index 0000000000..bcd2575a52
--- /dev/null
+++ b/plugins/tech-insights/src/api/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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.
+ */
+export * from './TechInsightsApi';
+export * from './TechInsightsClient';
diff --git a/plugins/tech-insights/src/api/types.ts b/plugins/tech-insights/src/api/types.ts
new file mode 100644
index 0000000000..20071ba0c9
--- /dev/null
+++ b/plugins/tech-insights/src/api/types.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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.
+ */
+export type Check = {
+ id: string;
+ type: string;
+ name: string;
+ description: string;
+ factIds: string[];
+};
diff --git a/plugins/tech-insights/src/components/BooleanCheck/BooleanCheck.tsx b/plugins/tech-insights/src/components/BooleanCheck/BooleanCheck.tsx
new file mode 100644
index 0000000000..e38e0aa7b3
--- /dev/null
+++ b/plugins/tech-insights/src/components/BooleanCheck/BooleanCheck.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 React from 'react';
+import { makeStyles, List, ListItem, ListItemText } from '@material-ui/core';
+import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline';
+import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
+import { CheckResult } from '@backstage/plugin-tech-insights-common';
+import { BackstageTheme } from '@backstage/theme';
+
+const useStyles = makeStyles((theme: BackstageTheme) => ({
+ listItemText: {
+ paddingRight: theme.spacing(0.5),
+ flex: '0 1 auto',
+ },
+ icon: {
+ marginLeft: 'auto',
+ },
+}));
+
+type Prop = {
+ checkResult: CheckResult[];
+};
+
+export const BooleanCheck = ({ checkResult }: Prop) => {
+ const classes = useStyles();
+
+ return (
+
+ {checkResult.map((check, index) => (
+
+
+ {check.result ? (
+
+ ) : (
+
+ )}
+
+ ))}
+
+ );
+};
diff --git a/plugins/tech-insights/src/components/BooleanCheck/index.ts b/plugins/tech-insights/src/components/BooleanCheck/index.ts
new file mode 100644
index 0000000000..729ab4d62e
--- /dev/null
+++ b/plugins/tech-insights/src/components/BooleanCheck/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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.
+ */
+
+export { BooleanCheck } from './BooleanCheck';
diff --git a/plugins/tech-insights/src/components/CheckResultRenderer.tsx b/plugins/tech-insights/src/components/CheckResultRenderer.tsx
new file mode 100644
index 0000000000..60e0fad9c5
--- /dev/null
+++ b/plugins/tech-insights/src/components/CheckResultRenderer.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { CheckResult } from '@backstage/plugin-tech-insights-common';
+import React from 'react';
+import { BooleanCheck } from './BooleanCheck';
+
+export type CheckResultRenderer = {
+ type: string;
+ title: string;
+ description: string;
+ component: React.ReactElement;
+};
+
+export function defaultCheckResultRenderers(
+ value: CheckResult[],
+): CheckResultRenderer[] {
+ return [
+ {
+ type: 'json-rules-engine',
+ title: 'Boolean scorecard',
+ description:
+ 'This card represents an overview of default boolean Backstage checks:',
+ component: ,
+ },
+ ];
+}
diff --git a/plugins/tech-insights/src/components/ScorecardsOverview/ChecksOverview.tsx b/plugins/tech-insights/src/components/ScorecardsOverview/ChecksOverview.tsx
new file mode 100644
index 0000000000..10025d1ba6
--- /dev/null
+++ b/plugins/tech-insights/src/components/ScorecardsOverview/ChecksOverview.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 React from 'react';
+import { makeStyles, Grid, Typography } from '@material-ui/core';
+import { useApi } from '@backstage/core-plugin-api';
+import { Content, Page, InfoCard } from '@backstage/core-components';
+import { CheckResult } from '@backstage/plugin-tech-insights-common';
+import { techInsightsApiRef } from '../../api/TechInsightsApi';
+import { BackstageTheme } from '@backstage/theme';
+
+const useStyles = makeStyles((theme: BackstageTheme) => ({
+ contentScorecards: {
+ paddingLeft: 0,
+ paddingRight: 0,
+ },
+ subheader: {
+ fontWeight: 'bold',
+ paddingLeft: theme.spacing(0.5),
+ },
+}));
+
+type Checks = {
+ checks: CheckResult[];
+};
+
+export const ChecksOverview = ({ checks }: Checks) => {
+ const classes = useStyles();
+ const api = useApi(techInsightsApiRef);
+ const checkRenderType = api.getScorecardsDefinition(
+ checks[0].check.type,
+ checks,
+ );
+
+ if (checkRenderType) {
+ return (
+
+
+
+
+
+ {checkRenderType.description}
+
+
+ {checkRenderType.component}
+
+
+
+
+
+ );
+ }
+
+ return <>>;
+};
diff --git a/plugins/tech-insights/src/components/ScorecardsOverview/ScorecardsOverview.tsx b/plugins/tech-insights/src/components/ScorecardsOverview/ScorecardsOverview.tsx
new file mode 100644
index 0000000000..92a57bd643
--- /dev/null
+++ b/plugins/tech-insights/src/components/ScorecardsOverview/ScorecardsOverview.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 React from 'react';
+import { useParams } from 'react-router-dom';
+import { useAsync } from 'react-use';
+import { Progress } from '@backstage/core-components';
+import { useApi } from '@backstage/core-plugin-api';
+import { ChecksOverview } from './ChecksOverview';
+import Alert from '@material-ui/lab/Alert';
+import { techInsightsApiRef } from '../../api/TechInsightsApi';
+
+export const ScorecardsOverview = () => {
+ const api = useApi(techInsightsApiRef);
+ const { namespace, kind, name } = useParams();
+
+ const { value, loading, error } = useAsync(
+ async () => await api.runChecks({ namespace, kind, name }),
+ );
+
+ if (loading) {
+ return ;
+ } else if (error) {
+ return {error.message};
+ }
+
+ return ;
+};
diff --git a/plugins/tech-insights/src/components/ScorecardsOverview/index.ts b/plugins/tech-insights/src/components/ScorecardsOverview/index.ts
new file mode 100644
index 0000000000..64198790d9
--- /dev/null
+++ b/plugins/tech-insights/src/components/ScorecardsOverview/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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.
+ */
+
+export { ScorecardsOverview } from './ScorecardsOverview';
diff --git a/plugins/tech-insights/src/index.ts b/plugins/tech-insights/src/index.ts
new file mode 100644
index 0000000000..273c11fd71
--- /dev/null
+++ b/plugins/tech-insights/src/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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.
+ */
+export {
+ techInsightsPlugin,
+ EntityTechInsightsScorecardContent,
+} from './plugin';
diff --git a/plugins/tech-insights/src/plugin.test.ts b/plugins/tech-insights/src/plugin.test.ts
new file mode 100644
index 0000000000..a4a9e6f308
--- /dev/null
+++ b/plugins/tech-insights/src/plugin.test.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 { techInsightsPlugin } from './plugin';
+
+describe('tech insights', () => {
+ it('should export plugin', () => {
+ expect(techInsightsPlugin).toBeDefined();
+ });
+});
diff --git a/plugins/tech-insights/src/plugin.ts b/plugins/tech-insights/src/plugin.ts
new file mode 100644
index 0000000000..f229b654f3
--- /dev/null
+++ b/plugins/tech-insights/src/plugin.ts
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 {
+ createPlugin,
+ createRoutableExtension,
+ createApiFactory,
+ discoveryApiRef,
+} from '@backstage/core-plugin-api';
+import { rootRouteRef } from './routes';
+import { techInsightsApiRef } from './api/TechInsightsApi';
+import { TechInsightsClient } from './api/TechInsightsClient';
+
+/**
+ * @public
+ */
+export const techInsightsPlugin = createPlugin({
+ id: 'tech-insights',
+ apis: [
+ createApiFactory({
+ api: techInsightsApiRef,
+ deps: { discoveryApi: discoveryApiRef },
+ factory: ({ discoveryApi }) => new TechInsightsClient({ discoveryApi }),
+ }),
+ ],
+ routes: {
+ root: rootRouteRef,
+ },
+});
+
+/**
+ * @public
+ */
+export const EntityTechInsightsScorecardContent = techInsightsPlugin.provide(
+ createRoutableExtension({
+ name: 'EntityTechInsightsScorecardContent',
+ component: () =>
+ import('./components/ScorecardsOverview').then(m => m.ScorecardsOverview),
+ mountPoint: rootRouteRef,
+ }),
+);
diff --git a/plugins/tech-insights/src/routes.ts b/plugins/tech-insights/src/routes.ts
new file mode 100644
index 0000000000..b1b7900074
--- /dev/null
+++ b/plugins/tech-insights/src/routes.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 { createRouteRef } from '@backstage/core-plugin-api';
+
+export const rootRouteRef = createRouteRef({
+ id: 'tech-insights',
+});
diff --git a/plugins/tech-insights/src/setupTests.ts b/plugins/tech-insights/src/setupTests.ts
new file mode 100644
index 0000000000..fc6dbd98f8
--- /dev/null
+++ b/plugins/tech-insights/src/setupTests.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * 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 '@testing-library/jest-dom';
+import 'cross-fetch/polyfill';