diff --git a/app-config.yaml b/app-config.yaml
index 22ca1fcaff..57349d213a 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -138,6 +138,11 @@ techdocs:
dynatrace:
baseUrl: https://your.dynatrace.instance.com
+# Score-cards sample configuration.
+scorecards:
+ jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/
+ wikiLinkTemplate: https://link-to-wiki/{id}
+
sentry:
organization: my-company
diff --git a/cypress/src/integration/plugins/score-card.spec.ts b/cypress/src/integration/plugins/score-card.spec.ts
new file mode 100644
index 0000000000..5871a094e1
--- /dev/null
+++ b/cypress/src/integration/plugins/score-card.spec.ts
@@ -0,0 +1,83 @@
+/*
+ * 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 'os';
+
+describe('score-card', () => {
+ describe('Score board', () => {
+ it('displays the score board based on sample data', () => {
+ cy.loginAsGuest();
+
+ cy.visit('/score-board');
+ cy.screenshot({ capture: 'viewport' });
+
+ cy.contains('System scores overview').should('be.visible');
+ cy.checkForErrors();
+ cy.get('span:contains("1-2 of 2")').should('be.visible'); // beware, there is also a hidden
element
+ cy.contains('audio-playback').should('be.visible');
+ cy.contains('team-c').should('be.visible');
+ cy.contains('non-valid-system').should('be.visible');
+ cy.contains('Name').should('be.visible');
+ cy.contains('Date').should('be.visible');
+ cy.contains('Code').should('be.visible');
+ cy.contains('Documentation').should('be.visible');
+ cy.contains('Operations').should('be.visible');
+ cy.contains('Quality').should('be.visible');
+ cy.contains('Security').should('be.visible');
+ cy.contains('Total').should('be.visible');
+ cy.contains('50 %').should('be.visible');
+ cy.contains('75 %').should('be.visible');
+ cy.log('navigating to score card detail for audio-playback');
+ cy.get('a[data-id="audio-playback"]').should('be.visible').click();
+ cy.screenshot({ capture: 'viewport' });
+
+ cy.url().should(
+ 'include',
+ '/catalog/default/System/audio-playback/score',
+ );
+ cy.contains('Scoring').should('be.visible');
+ cy.contains('Total score: 57 %').should('be.visible');
+ cy.contains('Code').should('be.visible');
+ cy.contains('90 %').should('be.visible');
+ cy.contains('Documentation').should('be.visible');
+ cy.contains('75 %').should('be.visible');
+ cy.contains('Operations').should('be.visible');
+ cy.contains('50 %').should('be.visible');
+ cy.contains('Quality').should('be.visible');
+ cy.contains('25 %').should('be.visible');
+ cy.contains('Security');
+ cy.contains('10 %').should('be.visible');
+ cy.checkForErrors();
+
+ cy.log(
+ 'Clicking on button [>] that is first child of the element (td) with value=Code',
+ );
+ cy.get('[value="Code"] > button:first-child').click();
+ cy.checkForErrors();
+ cy.screenshot({ capture: 'viewport' });
+
+ cy.log('Clicking on link for Code');
+ cy.contains('hints: Gitflow: 100%').should('be.visible');
+ cy.get('a[data-id="2157"]')
+ .should('be.visible')
+ .should(
+ 'have.attr',
+ 'href',
+ 'https://TBD/XXX/_wiki/wikis/XXX.wiki/2157',
+ );
+ });
+ });
+});
diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts
index 02723ffc90..62e21a5bef 100644
--- a/cypress/src/support/commands.ts
+++ b/cypress/src/support/commands.ts
@@ -118,3 +118,8 @@ Cypress.Commands.add('waitSectionTwoPage', () => {
Cypress.Commands.add('waitHomePage', () => {
cy.wait(['@entityMetadata', '@syncEntity', '@techdocsMetadata', '@homeHTML']);
});
+
+Cypress.Commands.add('checkForErrors', () => {
+ // when an error occurs there is a with an "alert" role attribute. This can change ofc => we shall add also some positive ("when error occurs") test
+ cy.get('div[role="alert"]').should('not.exist');
+});
diff --git a/cypress/src/types.d.ts b/cypress/src/types.d.ts
index 181b608a9b..dca22112e9 100644
--- a/cypress/src/types.d.ts
+++ b/cypress/src/types.d.ts
@@ -77,5 +77,10 @@ declare namespace Cypress {
* @example cy.isNotInViewport
*/
isNotInViewport(element: string): Chainable;
+ /**
+ * Check if we have not caused error by our last action
+ * @example cy.checkForErrors
+ */
+ checkForErrors(): Chainable;
}
}
diff --git a/packages/app/package.json b/packages/app/package.json
index 4181b036e9..e33092cf3d 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -67,6 +67,7 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@octokit/rest": "^19.0.3",
+ "@oriflame/backstage-plugin-score-card": "^0.5.1",
"@roadiehq/backstage-plugin-buildkite": "^2.0.8",
"@roadiehq/backstage-plugin-github-insights": "^2.0.5",
"@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7",
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 0b8107a216..d6b66d57a7 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -106,6 +106,7 @@ import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
import { PlaylistIndexPage } from '@backstage/plugin-playlist';
import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
+import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card';
const app = createApp({
apis,
@@ -273,6 +274,7 @@ const routes = (
} />
} />
} />
+ } />
);
diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx
index 8b5f0932fb..0c142bafbd 100644
--- a/packages/app/src/components/Root/Root.tsx
+++ b/packages/app/src/components/Root/Root.tsx
@@ -51,6 +51,7 @@ import {
import { MyGroupsSidebarItem } from '@backstage/plugin-org';
import GroupIcon from '@material-ui/icons/People';
import { SearchModal } from '../search/SearchModal';
+import Score from '@material-ui/icons/Score';
const useSidebarLogoStyles = makeStyles({
root: {
@@ -120,6 +121,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
text="Cost Insights"
/>
+
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index c2f297a2d7..f7592eb0b9 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -144,6 +144,7 @@ import {
EntityNewRelicDashboardCard,
} from '@backstage/plugin-newrelic-dashboard';
import { EntityGoCdContent, isGoCdAvailable } from '@backstage/plugin-gocd';
+import { EntityScoreCardContent } from '@oriflame/backstage-plugin-score-card';
import React, { ReactNode, useMemo, useState } from 'react';
@@ -704,6 +705,13 @@ const systemPage = (
+
+
+
+
+
+
+