From e605ea490684849f5f1a94a3e43c9e48f925ecfa Mon Sep 17 00:00:00 2001 From: Yevhenii Huselietov Date: Mon, 2 Oct 2023 12:22:18 +0300 Subject: [PATCH 1/2] Add newrelic dashboard to the storybook Signed-off-by: Yevhenii Huselietov --- .changeset/wild-toys-arrive.md | 5 + plugins/newrelic-dashboard/package.json | 1 + .../NewRelicDashboard.stories.tsx | 130 ++++++++++++++++++ yarn.lock | 1 + 4 files changed, 137 insertions(+) create mode 100644 .changeset/wild-toys-arrive.md create mode 100644 plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx diff --git a/.changeset/wild-toys-arrive.md b/.changeset/wild-toys-arrive.md new file mode 100644 index 0000000000..4aad036a96 --- /dev/null +++ b/.changeset/wild-toys-arrive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-newrelic-dashboard': minor +--- + +Add storybook for newrelic-dashboard plugin. diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index af5003dc1a..3c19e9f832 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -48,6 +48,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1" }, "files": [ diff --git a/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx b/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx new file mode 100644 index 0000000000..c4f81b8321 --- /dev/null +++ b/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx @@ -0,0 +1,130 @@ +/* + * 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 { NewRelicDashboard } from './NewRelicDashboard'; +import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { newRelicDashboardApiRef } from '../../api'; +import { NEWRELIC_GUID_ANNOTATION } from '../../constants'; +import { storageApiRef } from '@backstage/core-plugin-api'; + +function createImage( + width: number, + height: number, + bgColor: string, + text: string, +): HTMLCanvasElement { + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + if (ctx !== null) { + ctx.fillStyle = bgColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = '#000'; // text color + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = '20px sans-serif'; + ctx.fillText(text, canvas.width / 2, canvas.height / 2); + } + return canvas; +} + +const entity: any = { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'mocked entity with newrelic service', + title: 'app with newrelic', + [NEWRELIC_GUID_ANNOTATION]: 'some-cool-guid', + }, +}; + +const newRelicApiMockEmpty = { + getDashboardEntity: () => Promise.resolve(undefined), +}; + +const mockedNewRelicDashboard = (apis: any[]) => { + return ( + + + + + + ); +}; + +export const EmptyNewRelicDashboard = () => { + return mockedNewRelicDashboard([ + [newRelicDashboardApiRef, newRelicApiMockEmpty], + ]); +}; + +const resultEntities = [ + { + dashboardParentGuid: 'parent guid', + guid: 'guid', + permalink: 'http://example.com', + name: 'Production metrics', + }, +]; + +const dashboardEntity = { + data: { + actor: { + entitySearch: { + results: { + entities: resultEntities, + }, + }, + }, + }, +}; + +const entitySummary = { + getDashboardEntity: dashboardEntity, +}; + +const dashboardSnapshot = { + getDashboardSnapshot: { + data: { + dashboardCreateSnapshotUrl: createImage( + 1000, + 600, + '#ddd', + 'Example snapshot, imagine NewRelic panels here', + ).toDataURL(), + }, + }, +}; + +const newRelicApiMockFull = { + getDashboardEntity: () => Promise.resolve(entitySummary), + getDashboardSnapshot: () => Promise.resolve(dashboardSnapshot), +}; + +export const NewRelicDashboardWithSnapshots = () => { + return mockedNewRelicDashboard([ + [newRelicDashboardApiRef, newRelicApiMockFull], + [storageApiRef, MockStorageApi.create()], + ]); +}; + +export default { + title: 'NewRelic Dashboard', + component: EmptyNewRelicDashboard, +}; diff --git a/yarn.lock b/yarn.lock index aa15a03032..1718634506 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7941,6 +7941,7 @@ __metadata: "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/test-utils": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 From 74c1c21942509315469178f954298271c775de27 Mon Sep 17 00:00:00 2001 From: Yevhenii Huselietov Date: Thu, 5 Oct 2023 14:34:30 +0300 Subject: [PATCH 2/2] Review comments Signed-off-by: Yevhenii Huselietov --- .../NewRelicDashboard.stories.tsx | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx b/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx index c4f81b8321..a15a4c573c 100644 --- a/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx +++ b/plugins/newrelic-dashboard/src/components/NewRelicDashboard/NewRelicDashboard.stories.tsx @@ -21,6 +21,7 @@ import { EntityProvider } from '@backstage/plugin-catalog-react'; import { newRelicDashboardApiRef } from '../../api'; import { NEWRELIC_GUID_ANNOTATION } from '../../constants'; import { storageApiRef } from '@backstage/core-plugin-api'; +import { Entity } from '@backstage/catalog-model'; function createImage( width: number, @@ -44,13 +45,15 @@ function createImage( return canvas; } -const entity: any = { +const entity: Entity = { apiVersion: '1', kind: 'Component', metadata: { name: 'mocked entity with newrelic service', title: 'app with newrelic', - [NEWRELIC_GUID_ANNOTATION]: 'some-cool-guid', + annotations: { + [NEWRELIC_GUID_ANNOTATION]: 'some-cool-guid', + }, }, }; @@ -58,21 +61,13 @@ const newRelicApiMockEmpty = { getDashboardEntity: () => Promise.resolve(undefined), }; -const mockedNewRelicDashboard = (apis: any[]) => { - return ( - - - - - - ); -}; - -export const EmptyNewRelicDashboard = () => { - return mockedNewRelicDashboard([ - [newRelicDashboardApiRef, newRelicApiMockEmpty], - ]); -}; +export const EmptyNewRelicDashboard = () => ( + + + + + +); const resultEntities = [ { @@ -117,12 +112,18 @@ const newRelicApiMockFull = { getDashboardSnapshot: () => Promise.resolve(dashboardSnapshot), }; -export const NewRelicDashboardWithSnapshots = () => { - return mockedNewRelicDashboard([ - [newRelicDashboardApiRef, newRelicApiMockFull], - [storageApiRef, MockStorageApi.create()], - ]); -}; +export const NewRelicDashboardWithSnapshots = () => ( + + + + + +); export default { title: 'NewRelic Dashboard',