From 91c4ecf5fe8b0a952752f364b44bdec8cd5d0a1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Thu, 7 Aug 2025 10:01:53 +0100 Subject: [PATCH 1/9] chore: change module main entry (#57) --- .changeset/strong-falcons-sleep.md | 5 +++++ plugins/backstage-plugin/package.json | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/strong-falcons-sleep.md diff --git a/.changeset/strong-falcons-sleep.md b/.changeset/strong-falcons-sleep.md new file mode 100644 index 0000000..cadd82a --- /dev/null +++ b/.changeset/strong-falcons-sleep.md @@ -0,0 +1,5 @@ +--- +'@pagerduty/backstage-plugin': patch +--- + +Change module main entry for backstage-plugin (frontend) diff --git a/plugins/backstage-plugin/package.json b/plugins/backstage-plugin/package.json index 9d8058a..f408653 100644 --- a/plugins/backstage-plugin/package.json +++ b/plugins/backstage-plugin/package.json @@ -2,12 +2,12 @@ "name": "@pagerduty/backstage-plugin", "description": "A Backstage plugin that integrates towards PagerDuty", "version": "0.15.8", - "main": "dist/index.cjs.js", + "main": "dist/index.esm.js", "types": "dist/index.d.ts", "license": "Apache-2.0", "publishConfig": { "access": "public", - "main": "dist/index.cjs.js", + "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, "backstage": { From 2284e180bf704f87c8a7f90e27f4ccfb13cea724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Tue, 12 Aug 2025 14:42:48 +0100 Subject: [PATCH 2/9] Chore: migrate backstage-plugin to new frontend system (#61) * chore: migrate backstage-plugin to new frontend system * update licence placeholder * changeset --- .changeset/three-lemons-return.md | 5 + packages/app/package.json | 15 +- packages/app/src/App-Alpha.tsx | 44 + packages/app/src/index.tsx | 11 +- plugins/backstage-plugin/README.md | 36 + plugins/backstage-plugin/package.json | 19 +- plugins/backstage-plugin/src/alpha.tsx | 102 +++ .../components/EntityPagerDutyCard/index.tsx | 24 +- .../EntityPagerDutySmallCard/index.tsx | 24 +- plugins/backstage-plugin/src/index.ts | 1 + tsconfig.plugins.json | 1 - yarn.lock | 808 +++++++++++++++--- 12 files changed, 928 insertions(+), 162 deletions(-) create mode 100644 .changeset/three-lemons-return.md create mode 100644 packages/app/src/App-Alpha.tsx create mode 100644 plugins/backstage-plugin/README.md create mode 100644 plugins/backstage-plugin/src/alpha.tsx diff --git a/.changeset/three-lemons-return.md b/.changeset/three-lemons-return.md new file mode 100644 index 0000000..658543d --- /dev/null +++ b/.changeset/three-lemons-return.md @@ -0,0 +1,5 @@ +--- +'@pagerduty/backstage-plugin': patch +--- + +Implement new frontend system (alpha) diff --git a/packages/app/package.json b/packages/app/package.json index 59cd0e7..bbea99b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -21,20 +21,21 @@ "@backstage/core-app-api": "^1.17.1", "@backstage/core-components": "^0.17.3", "@backstage/core-plugin-api": "^1.10.8", + "@backstage/frontend-defaults": "^0.2.4", "@backstage/integration-react": "^1.2.8", - "@backstage/plugin-api-docs": "^0.12.8", - "@backstage/plugin-catalog": "^1.31.0", + "@backstage/plugin-api-docs": "^0.12.9", + "@backstage/plugin-catalog": "^1.31.1", "@backstage/plugin-catalog-common": "^1.1.4", "@backstage/plugin-catalog-graph": "^0.4.20", - "@backstage/plugin-catalog-import": "^0.13.1", + "@backstage/plugin-catalog-import": "^0.13.3", "@backstage/plugin-catalog-react": "^1.19.0", "@backstage/plugin-kubernetes": "^0.12.8", - "@backstage/plugin-org": "^0.6.40", + "@backstage/plugin-org": "^0.6.41", "@backstage/plugin-permission-react": "^0.4.35", - "@backstage/plugin-scaffolder": "^1.32.0", - "@backstage/plugin-search": "^1.4.27", + "@backstage/plugin-scaffolder": "^1.33.0", + "@backstage/plugin-search": "^1.4.28", "@backstage/plugin-search-react": "^1.9.1", - "@backstage/plugin-techdocs": "^1.13.0", + "@backstage/plugin-techdocs": "^1.13.2", "@backstage/plugin-techdocs-module-addons-contrib": "^1.1.25", "@backstage/plugin-techdocs-react": "^1.3.0", "@backstage/plugin-user-settings": "^0.8.23", diff --git a/packages/app/src/App-Alpha.tsx b/packages/app/src/App-Alpha.tsx new file mode 100644 index 0000000..2a2175b --- /dev/null +++ b/packages/app/src/App-Alpha.tsx @@ -0,0 +1,44 @@ +import ApiExplorerPlugin from '@backstage/plugin-api-docs/alpha'; +import ApiDocsPlugin from '@backstage/plugin-api-docs/alpha'; +import CatalogPlugin from '@backstage/plugin-catalog/alpha'; +import CatalogImportPlugin from '@backstage/plugin-catalog-import/alpha'; +import ScaffolderPlugin from '@backstage/plugin-scaffolder/alpha'; +import OrgPlugin from '@backstage/plugin-org/alpha'; +import SearchPlugin from '@backstage/plugin-search/alpha'; +import TechDocsPlugin from '@backstage/plugin-techdocs/alpha'; +import { createApp } from '@backstage/frontend-defaults'; +import PagerDutyPlugin from '@pagerduty/backstage-plugin/alpha'; + +// Uncomment the line below if you want to use the overridden version of PagerDuty plugin +// import { EntityPagerDutySmallCard } from '@pagerduty/backstage-plugin'; + +// const OverriddenPagerDutyPlugin = PagerDutyPlugin.withOverrides({ +// extensions: [ +// PagerDutyPlugin.getExtension('entity-card:pagerduty/EntityPagerDutyCard').override({ +// factory: originalFactory => +// originalFactory({ +// params: { +// loader: async () => Promise.resolve() +// } +// }) +// }) +// ] +// }) + +const app = createApp({ + features: [ + ApiExplorerPlugin, + ApiDocsPlugin, + CatalogPlugin, + CatalogImportPlugin, + ScaffolderPlugin, + SearchPlugin, + OrgPlugin, + TechDocsPlugin, + PagerDutyPlugin, + // Uncomment the line below if you want to use the overridden version of PagerDuty plugin + // OverriddenPagerDutyPlugin + ] +}); + +export default app.createRoot(); diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 69d6401..cc8e77a 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -1,6 +1,13 @@ import '@backstage/cli/asset-types'; import ReactDOM from 'react-dom/client'; -import App from './App'; import '@backstage/canon/css/styles.css'; -ReactDOM.createRoot(document.getElementById('root')!).render(); +// Uncomment the lines below if you want to use the old version of the app +// import App from './App'; + +// ReactDOM.createRoot(document.getElementById('root')!).render(); + +// Uncomment the lines below if you want to use the alpha version of the app +import AppAlpha from './App-Alpha'; + +ReactDOM.createRoot(document.getElementById('root')!).render(AppAlpha); diff --git a/plugins/backstage-plugin/README.md b/plugins/backstage-plugin/README.md new file mode 100644 index 0000000..bb81737 --- /dev/null +++ b/plugins/backstage-plugin/README.md @@ -0,0 +1,36 @@ +# PagerDuty Backstage Plugin + +> The PagerDuty plugin reduces the cognitive load on developers responsible for maintaining services in production. +Instead of having to go to PagerDuty's console, you can now access the necessary information directly within Backstage. +This includes finding active incidents or opening a new incident, reviewing recent changes made to the service, +and checking who is on-call. + +## New Frontend System (NFS) + +This frontend plugin is starting the adoption of the [New Frontend System](https://backstage.io/docs/frontend-system/). This allow us to be present in Portal and keep up to date with Backstage's recommended best practices. + +### Migration + +We're still migrating to the NFS, since it is still in alpha. You can find this version of the plugin on the export `@pagerduty/backstage-plugin/alpha`, which allows you to start using it even in Backstage under the new `createApp` helper from `@backstage/frontend-defaults`. + +### Extensions + +The NFS allows for extendable plugins, which means there are parts of it that users can replace to elevate their experience. We've historically exported two components the `EntityPagerDutyCard` and the `EntityPagerDutySmallCard` to expose some PagerDuty's service information on your Backstage entities. In the NFS, we default to `EntityPagerDutyCard` as an entity card extension, which means you can still make use of the `EntityPagerDutySmallCard` through overrides. + +```javascript +import PagerDutyPlugin from '@pagerduty/backstage-plugin/alpha'; +import { EntityPagerDutySmallCard } from '@pagerduty/backstage-plugin'; + +const OverriddenPagerDutyPlugin = PagerDutyPlugin.withOverrides({ + extensions: [ + PagerDutyPlugin.getExtension('entity-card:pagerduty/EntityPagerDutyCard').override({ + factory: originalFactory => + originalFactory({ + params: { + loader: async () => Promise.resolve() + } + }) + }) + ] +}) +``` diff --git a/plugins/backstage-plugin/package.json b/plugins/backstage-plugin/package.json index f408653..22b8f1d 100644 --- a/plugins/backstage-plugin/package.json +++ b/plugins/backstage-plugin/package.json @@ -41,11 +41,14 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/catalog-client": "^1.10.2", "@backstage/catalog-model": "^1.5.0", + "@backstage/core-compat-api": "^0.4.4", "@backstage/core-components": "^0.14.9", "@backstage/core-plugin-api": "^1.9.3", "@backstage/errors": "^1.2.4", - "@backstage/plugin-catalog-react": "^1.12.2", + "@backstage/frontend-plugin-api": "^0.10.4", + "@backstage/plugin-catalog-react": "^1.19.1", "@backstage/plugin-home-react": "^0.1.15", "@backstage/theme": "^0.5.6", "@emotion/react": "^11.11.4", @@ -84,6 +87,20 @@ "config.d.ts", "assets/**/*" ], + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } + }, "configSchema": "config.d.ts", "module": "./dist/index.esm.js" } diff --git a/plugins/backstage-plugin/src/alpha.tsx b/plugins/backstage-plugin/src/alpha.tsx new file mode 100644 index 0000000..6a68075 --- /dev/null +++ b/plugins/backstage-plugin/src/alpha.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2025 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"; +import { + ApiBlueprint, + createFrontendPlugin, + createRouteRef, + FrontendPlugin, + PageBlueprint, + NavItemBlueprint, + discoveryApiRef, + configApiRef, + fetchApiRef, + ConfigApi, + DiscoveryApi, + FetchApi +} from "@backstage/frontend-plugin-api"; +import { compatWrapper } from "@backstage/core-compat-api"; +import { EntityCardBlueprint } from "@backstage/plugin-catalog-react/alpha" +import { pagerDutyApiRef, PagerDutyClient } from './api'; +import { PagerDutyIcon } from './components'; + +export const rootRouteRef = createRouteRef(); + +/** @alpha */ +const PagerDutyAPI = ApiBlueprint.make({ + params: { + factory: { + api: pagerDutyApiRef, + deps: { + discoveryApi: discoveryApiRef, + configApi: configApiRef, + fetchApi: fetchApiRef + }, + factory: ({ + configApi, + discoveryApi, + fetchApi + }: { configApi: ConfigApi; discoveryApi: DiscoveryApi; fetchApi: FetchApi }) => + PagerDutyClient.fromConfig(configApi, { discoveryApi, fetchApi }), + } + } +}); + +/** @alpha */ +const PagerDutyPage = PageBlueprint.make({ + params: { + defaultPath: '/pagerduty', + routeRef: rootRouteRef, + loader: () => + import('./components/PagerDutyPage') + .then(m => compatWrapper()), + } +}); + +/** @alpha */ +const EntityPagerDutyCard = EntityCardBlueprint.make({ + name: 'EntityPagerDutyCard', + params: { + filter: 'kind:component', + loader: async () => import('./components/EntityPagerDutyCard') + .then(m => compatWrapper()), + } +}); + +/** @alpha */ +const PagerDutyNavBarItem = NavItemBlueprint.make({ + name: 'PagerDutyNavBarItem', + params: { + title: 'PagerDuty', + icon: () => , + routeRef: rootRouteRef, + } +}); + +/** @alpha */ +export default createFrontendPlugin({ + pluginId: 'pagerduty', + extensions: [ + EntityPagerDutyCard, + PagerDutyAPI, + PagerDutyPage, + PagerDutyNavBarItem + ], + routes: { + root: rootRouteRef + } +}) as FrontendPlugin; diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx index b28288d..8076a2b 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx @@ -38,13 +38,19 @@ export type EntityPagerDutyCardProps = { export const EntityPagerDutyCard = (props: EntityPagerDutyCardProps) => { const { readOnly, disableChangeEvents, disableOnCall } = props; const { entity } = useEntity(); - const pagerDutyEntity = getPagerDutyEntity(entity); - return ( - - ); + + if (isPluginApplicableToEntity(entity)) { + const pagerDutyEntity = getPagerDutyEntity(entity); + + return ( + + ); + } + + return null; }; diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx index bc87cdc..4f95506 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx @@ -40,13 +40,19 @@ export const EntityPagerDutySmallCard = ( ) => { const { readOnly, disableInsights, disableOnCall } = props; const { entity } = useEntity(); - const pagerDutyEntity = getPagerDutyEntity(entity); - return ( - - ); + + if (isPluginApplicableToEntity(entity)) { + const pagerDutyEntity = getPagerDutyEntity(entity); + + return ( + + ); + } + + return null; }; diff --git a/plugins/backstage-plugin/src/index.ts b/plugins/backstage-plugin/src/index.ts index 3c7950c..5b7f7c9 100644 --- a/plugins/backstage-plugin/src/index.ts +++ b/plugins/backstage-plugin/src/index.ts @@ -33,5 +33,6 @@ export * from './components'; export * from './api'; export * from './deprecated'; +export * from './alpha'; export type { PagerDutyEntity } from './types'; diff --git a/tsconfig.plugins.json b/tsconfig.plugins.json index 173e90b..10a6614 100644 --- a/tsconfig.plugins.json +++ b/tsconfig.plugins.json @@ -1,7 +1,6 @@ { "extends": "@backstage/cli/config/tsconfig.json", "include": [ - "libs/*/src", "plugins/*/src", "plugins/*/config.d.ts", "plugins/*/custom.d.ts", diff --git a/yarn.lock b/yarn.lock index 0443bd8..2a7691e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3639,6 +3639,18 @@ __metadata: languageName: node linkType: hard +"@backstage/catalog-client@npm:^1.10.2": + version: 1.10.2 + resolution: "@backstage/catalog-client@npm:1.10.2" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/errors": "npm:^1.2.7" + cross-fetch: "npm:^4.0.0" + uri-template: "npm:^2.0.0" + checksum: 10c0/9e60ecb00be11aa7d8b77443e8125f25b543b5c1b740a9f501e1b5dd303ff8c64f0e0fca7daa5e23f964139e76c92331b9493ace2c9d17c478f9f7f52a45c997 + languageName: node + linkType: hard + "@backstage/catalog-model@npm:^1.5.0, @backstage/catalog-model@npm:^1.7.0, @backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@npm:^1.7.4": version: 1.7.4 resolution: "@backstage/catalog-model@npm:1.7.4" @@ -3651,6 +3663,18 @@ __metadata: languageName: node linkType: hard +"@backstage/catalog-model@npm:^1.7.5": + version: 1.7.5 + resolution: "@backstage/catalog-model@npm:1.7.5" + dependencies: + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.1" + ajv: "npm:^8.10.0" + lodash: "npm:^4.17.21" + checksum: 10c0/5ab3446c0ca14371a9709117b8c84ce2193a41f59f279231dbde9b84aa7570862ae7033c7d8a08b651ffb0ee1fad37b71630015439e300a6db15ea0c8db69bd7 + languageName: node + linkType: hard + "@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@npm:^0.1.15": version: 0.1.15 resolution: "@backstage/cli-common@npm:0.1.15" @@ -3843,6 +3867,17 @@ __metadata: languageName: node linkType: hard +"@backstage/config@npm:^1.3.3": + version: 1.3.3 + resolution: "@backstage/config@npm:1.3.3" + dependencies: + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.1" + ms: "npm:^2.1.3" + checksum: 10c0/71f6bb34fad63a9801a71211b85b67f1e93b6d4f072a6a59da3692ff1e6f5b73973cc5969b3263d2afc67b04c22aeebe3a68fcd5fc5657933071c1a5987929f2 + languageName: node + linkType: hard + "@backstage/core-app-api@npm:^1.14.0, @backstage/core-app-api@npm:^1.17.1": version: 1.17.1 resolution: "@backstage/core-app-api@npm:1.17.1" @@ -3871,6 +3906,34 @@ __metadata: languageName: node linkType: hard +"@backstage/core-app-api@npm:^1.18.0": + version: 1.18.0 + resolution: "@backstage/core-app-api@npm:1.18.0" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@types/prop-types": "npm:^15.7.3" + history: "npm:^5.0.0" + i18next: "npm:^22.4.15" + lodash: "npm:^4.17.21" + prop-types: "npm:^15.7.2" + react-use: "npm:^17.2.4" + zen-observable: "npm:^0.10.0" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/6ea97d67a4a589c7672831b51d16be1beeb310169c6c938af841ac4780b7bccc783104b87709f9dbe85d35a75e1df7008eaf7f798b2b64c3ae37930f497c88f9 + languageName: node + linkType: hard + "@backstage/core-compat-api@npm:^0.4.3": version: 0.4.3 resolution: "@backstage/core-compat-api@npm:0.4.3" @@ -3892,6 +3955,27 @@ __metadata: languageName: node linkType: hard +"@backstage/core-compat-api@npm:^0.4.4": + version: 0.4.4 + resolution: "@backstage/core-compat-api@npm:0.4.4" + dependencies: + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/version-bridge": "npm:^1.0.11" + lodash: "npm:^4.17.21" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d85c09382e82a9b44a36de47e84d1b8d04e82f5ffca70860e314b5dae70a1574abf8296f04de72d43c488c6126071d1a3d550ee1ccc6099cc056d87d720a1aeb + languageName: node + linkType: hard + "@backstage/core-components@npm:^0.14.9": version: 0.14.10 resolution: "@backstage/core-components@npm:0.14.10" @@ -3995,6 +4079,60 @@ __metadata: languageName: node linkType: hard +"@backstage/core-components@npm:^0.17.4": + version: 0.17.4 + resolution: "@backstage/core-components@npm:0.17.4" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/errors": "npm:^1.2.7" + "@backstage/theme": "npm:^0.6.7" + "@backstage/version-bridge": "npm:^1.0.11" + "@dagrejs/dagre": "npm:^1.1.4" + "@date-io/core": "npm:^1.3.13" + "@material-table/core": "npm:^3.1.0" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:4.0.0-alpha.61" + "@react-hookz/web": "npm:^24.0.0" + "@testing-library/react": "npm:^16.0.0" + "@types/react-sparklines": "npm:^1.7.0" + ansi-regex: "npm:^6.0.1" + classnames: "npm:^2.2.6" + d3-selection: "npm:^3.0.0" + d3-shape: "npm:^3.0.0" + d3-zoom: "npm:^3.0.0" + js-yaml: "npm:^4.1.0" + linkify-react: "npm:4.1.3" + linkifyjs: "npm:4.1.3" + lodash: "npm:^4.17.21" + pluralize: "npm:^8.0.0" + qs: "npm:^6.9.4" + rc-progress: "npm:3.5.1" + react-helmet: "npm:6.1.0" + react-hook-form: "npm:^7.12.2" + react-idle-timer: "npm:5.7.2" + react-markdown: "npm:^8.0.0" + react-sparklines: "npm:^1.7.0" + react-syntax-highlighter: "npm:^15.4.5" + react-use: "npm:^17.3.2" + react-virtualized-auto-sizer: "npm:^1.0.11" + react-window: "npm:^1.8.6" + remark-gfm: "npm:^3.0.1" + zen-observable: "npm:^0.10.0" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5028fdc206bf0416f65c3118cfa05229559748700bbb1aa3ed9f4e5273089f91f7c76144c253dcd962b3362a8a848ee9393759504dd8886aea32096a2279877f + languageName: node + linkType: hard + "@backstage/core-plugin-api@npm:^1.10.8, @backstage/core-plugin-api@npm:^1.9.3": version: 1.10.8 resolution: "@backstage/core-plugin-api@npm:1.10.8" @@ -4016,6 +4154,27 @@ __metadata: languageName: node linkType: hard +"@backstage/core-plugin-api@npm:^1.10.9": + version: 1.10.9 + resolution: "@backstage/core-plugin-api@npm:1.10.9" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + history: "npm:^5.0.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/31bcaf74ba27f46bcaf92243d75b6a0930546f9c9554f45cbcde669bc772155cb7b3a8545dad72e09ed34ba65cf280d77d8c388dd9135c171d19a3d33763e4d1 + languageName: node + linkType: hard + "@backstage/dev-utils@npm:^1.0.35": version: 1.1.11 resolution: "@backstage/dev-utils@npm:1.1.11" @@ -4104,6 +4263,32 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-app-api@npm:^0.11.4": + version: 0.11.4 + resolution: "@backstage/frontend-app-api@npm:0.11.4" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-app-api": "npm:^1.18.0" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-defaults": "npm:^0.2.4" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + lodash: "npm:^4.17.21" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/e13815d3beac5da0a04201811994a8721e3d898246586b4eead515a5b76ae771f5ab27c6ccb6e2939e6dcf98cce5021f0850d53a0039f8072865e277a4f7ef3b + languageName: node + linkType: hard + "@backstage/frontend-defaults@npm:^0.2.3": version: 0.2.3 resolution: "@backstage/frontend-defaults@npm:0.2.3" @@ -4126,6 +4311,28 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-defaults@npm:^0.2.4": + version: 0.2.4 + resolution: "@backstage/frontend-defaults@npm:0.2.4" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-app-api": "npm:^0.11.4" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-app": "npm:^0.1.11" + "@react-hookz/web": "npm:^24.0.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/50a5a6147e86ea9df686bbdc2aea08622d10b42f4f219079e82d887cae26ecb8e75d03639cc0a33d2266e6be24cc01834c27c721661344592c905d3bde7d6cd7 + languageName: node + linkType: hard + "@backstage/frontend-plugin-api@npm:^0.10.3": version: 0.10.3 resolution: "@backstage/frontend-plugin-api@npm:0.10.3" @@ -4150,6 +4357,30 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-plugin-api@npm:^0.10.4": + version: 0.10.4 + resolution: "@backstage/frontend-plugin-api@npm:0.10.4" + dependencies: + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.4" + lodash: "npm:^4.17.21" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.21.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/06577c8e7b25bfa622e2628466d2c154168d042594334a06971759059f1842b30223cbdefad30e31119b46658542230245677aab88b49160312aba91eb7647fa + languageName: node + linkType: hard + "@backstage/frontend-test-utils@npm:^0.3.3": version: 0.3.3 resolution: "@backstage/frontend-test-utils@npm:0.3.3" @@ -4175,6 +4406,31 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-test-utils@npm:^0.3.4": + version: 0.3.4 + resolution: "@backstage/frontend-test-utils@npm:0.3.4" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/frontend-app-api": "npm:^0.11.4" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-app": "npm:^0.1.11" + "@backstage/test-utils": "npm:^1.7.10" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + zod: "npm:^3.22.4" + peerDependencies: + "@testing-library/react": ^16.0.0 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/b9d87f8b8bf91f1bc7be9b6ced21b3094a849dd94c7cb01fd239124a2faae8466684be6193476266af4a7834d4aad127c063b6a660a4cdbbcbf04360d8b9b3e9 + languageName: node + linkType: hard + "@backstage/integration-aws-node@npm:^0.1.12, @backstage/integration-aws-node@npm:^0.1.16": version: 0.1.16 resolution: "@backstage/integration-aws-node@npm:0.1.16" @@ -4211,6 +4467,27 @@ __metadata: languageName: node linkType: hard +"@backstage/integration-react@npm:^1.2.9": + version: 1.2.9 + resolution: "@backstage/integration-react@npm:1.2.9" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/integration": "npm:^1.17.1" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/619541f2492cee6fb3a1be5d5c88611e97cfcfc60a5077d33ec5bcefc4b4bdc4205bcea83287ec8dffe9382d48cf8887e2d01da8d1dc0682b27003dfbc3822ef + languageName: node + linkType: hard + "@backstage/integration@npm:^1.12.0, @backstage/integration@npm:^1.13.0, @backstage/integration@npm:^1.14.0, @backstage/integration@npm:^1.15.0, @backstage/integration@npm:^1.17.0": version: 1.17.0 resolution: "@backstage/integration@npm:1.17.0" @@ -4229,20 +4506,38 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-api-docs@npm:^0.12.8": - version: 0.12.8 - resolution: "@backstage/plugin-api-docs@npm:0.12.8" +"@backstage/integration@npm:^1.17.1": + version: 1.17.1 + resolution: "@backstage/integration@npm:1.17.1" + dependencies: + "@azure/identity": "npm:^4.0.0" + "@azure/storage-blob": "npm:^12.5.0" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@octokit/auth-app": "npm:^4.0.0" + "@octokit/rest": "npm:^19.0.3" + cross-fetch: "npm:^4.0.0" + git-url-parse: "npm:^15.0.0" + lodash: "npm:^4.17.21" + luxon: "npm:^3.0.0" + checksum: 10c0/9208dbcb8f7e56b5b945ce39204b557cab8012559108e0a2221dca891826a22c95484065a264b925bd1ba0831a211f3055e5c91f4965058760b6da3fcafaaa58 + languageName: node + linkType: hard + +"@backstage/plugin-api-docs@npm:^0.12.9": + version: 0.12.9 + resolution: "@backstage/plugin-api-docs@npm:0.12.9" dependencies: "@asyncapi/react-component": "npm:^2.3.3" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/plugin-catalog": "npm:^1.31.0" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-permission-react": "npm:^0.4.35" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog": "npm:^1.31.1" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" "@graphiql/react": "npm:^0.23.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" @@ -4261,7 +4556,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/01ce97f28bb9ac5a697648b1b8c9a2e072e15027fffef7454dc658be2a67ad76caf5225caaeedefbc91708893bc94dba9810673148f058a719f67293109989b6 + checksum: 10c0/0c1dc21db396f854739075238da64c18eb33036c234384cf9215a82fe3d6c837ffe79431835c818cfab7f68f87dd78afc059ebf8c6cd308c5ddf9c779cefe07e languageName: node linkType: hard @@ -4329,6 +4624,33 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-app@npm:^0.1.11": + version: 0.1.11 + resolution: "@backstage/plugin-app@npm:0.1.11" + dependencies: + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/theme": "npm:^0.6.7" + "@backstage/types": "npm:^1.2.1" + "@material-ui/core": "npm:^4.9.13" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:^4.0.0-alpha.61" + react-use: "npm:^17.2.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/fd129828d2f22fd8620445a9d8588ff0c3e2a61c31b4dc6ee1f8b8f69901ac37d7963d571aafa20d0577204ae19964d0995d9c2ab779a60fefb474454436d056 + languageName: node + linkType: hard + "@backstage/plugin-auth-backend-module-github-provider@npm:^0.3.4": version: 0.3.4 resolution: "@backstage/plugin-auth-backend-module-github-provider@npm:0.3.4" @@ -4455,12 +4777,12 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-auth-react@npm:^0.1.16": - version: 0.1.16 - resolution: "@backstage/plugin-auth-react@npm:0.1.16" +"@backstage/plugin-auth-react@npm:^0.1.17": + version: 0.1.17 + resolution: "@backstage/plugin-auth-react@npm:0.1.17" dependencies: - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" "@material-ui/core": "npm:^4.9.13" "@react-hookz/web": "npm:^24.0.0" @@ -4472,7 +4794,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/638617613caaacbcaab6ba89b53fb032d4f555846275ac53102640562741ca4806412121090ee8326eb0903920d8469900e7da2f19e7b7e0a00d663bfe313c5b + checksum: 10c0/7b8128b8161c5a45711c49db8352b84f29eaf5f60e341d332857d588c8e3ef998d86405111afd5e60c2a4a73f5186ce98efeba57745f72d2bb9d91185d724ffb languageName: node linkType: hard @@ -4560,6 +4882,17 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-catalog-common@npm:^1.1.5": + version: 1.1.5 + resolution: "@backstage/plugin-catalog-common@npm:1.1.5" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/plugin-search-common": "npm:^1.2.19" + checksum: 10c0/b360ddbbe30c92ae562500cca0a456ad929ad983d1326c70bbec45560cdc6d7aa99678f78d1e064af1f30e2b9044687ee5b29f2928e0d585cde374bbbd8a120c + languageName: node + linkType: hard + "@backstage/plugin-catalog-graph@npm:^0.4.20": version: 0.4.20 resolution: "@backstage/plugin-catalog-graph@npm:0.4.20" @@ -4592,22 +4925,22 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog-import@npm:^0.13.1": - version: 0.13.2 - resolution: "@backstage/plugin-catalog-import@npm:0.13.2" +"@backstage/plugin-catalog-import@npm:^0.13.3": + version: 0.13.3 + resolution: "@backstage/plugin-catalog-import@npm:0.13.3" dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/config": "npm:^1.3.2" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/integration": "npm:^1.17.0" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-react": "npm:^1.19.0" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/integration": "npm:^1.17.1" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.19.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -4626,7 +4959,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/52302de8f90ffaa0dd8cd04eaad50e61549fcf6601071808c7e7b26bd2978d84a46fc805e407c63507e88963db3438238b686a58ee21f6c92b73aa903a3f1a32 + checksum: 10c0/d5340bd7807a9336996ea035405e7f95ba052172be4689094bca3e21a6b9390ae06cfd07d5c90e2c3380366d7e56515e8b95bf067e9cdb8a9761d946ca606b0c languageName: node linkType: hard @@ -4648,7 +4981,7 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog-react@npm:^1.12.2, @backstage/plugin-catalog-react@npm:^1.19.0": +"@backstage/plugin-catalog-react@npm:^1.19.0": version: 1.19.0 resolution: "@backstage/plugin-catalog-react@npm:1.19.0" dependencies: @@ -4689,26 +5022,67 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog@npm:^1.31.0": - version: 1.31.0 - resolution: "@backstage/plugin-catalog@npm:1.31.0" +"@backstage/plugin-catalog-react@npm:^1.19.1": + version: 1.19.1 + resolution: "@backstage/plugin-catalog-react@npm:1.19.1" dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/plugin-scaffolder-common": "npm:^1.5.11" - "@backstage/plugin-search-common": "npm:^1.2.18" - "@backstage/plugin-search-react": "npm:^1.9.1" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/frontend-test-utils": "npm:^0.3.4" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:4.0.0-alpha.61" + "@react-hookz/web": "npm:^24.0.0" + classnames: "npm:^2.2.6" + lodash: "npm:^4.17.21" + material-ui-popup-state: "npm:^1.9.3" + qs: "npm:^6.9.4" + react-use: "npm:^17.2.4" + yaml: "npm:^2.0.0" + zen-observable: "npm:^0.10.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5de9d0b0954e543a351e8dc51000ee7d61fcbab0addd5dd04669e7e64b5e70df963f5cf706878b9c2d185fccb2480e32ac68897c6ea14f24efd1896d8fdee8e9 + languageName: node + linkType: hard + +"@backstage/plugin-catalog@npm:^1.31.1": + version: 1.31.1 + resolution: "@backstage/plugin-catalog@npm:1.31.1" + dependencies: + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/plugin-scaffolder-common": "npm:^1.6.0" + "@backstage/plugin-search-common": "npm:^1.2.19" + "@backstage/plugin-search-react": "npm:^1.9.2" "@backstage/plugin-techdocs-common": "npm:^0.1.1" - "@backstage/plugin-techdocs-react": "npm:^1.3.0" + "@backstage/plugin-techdocs-react": "npm:^1.3.1" "@backstage/types": "npm:^1.2.1" "@backstage/version-bridge": "npm:^1.0.11" "@material-ui/core": "npm:^4.12.2" @@ -4731,7 +5105,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/27e52869ac0746db472801dd78683b28fb5a45b4211d73e9b05229ebc2dccb1591b8c050fc352010e0e1db78252b58048ea6d58b8626bc39a8a19bd5a985f75f + checksum: 10c0/bdd40d48e7195572a70bd2c15c5ab18d187125db77e049191cee1156ec34b314fe03d66d7fd9926a73e3b175022b6cf355c25aa58329c1307143f6c66622d1b8 languageName: node linkType: hard @@ -4933,17 +5307,17 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-org@npm:^0.6.40": - version: 0.6.40 - resolution: "@backstage/plugin-org@npm:0.6.40" +"@backstage/plugin-org@npm:^0.6.41": + version: 0.6.41 + resolution: "@backstage/plugin-org@npm:0.6.41" dependencies: - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-react": "npm:^1.19.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.19.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -4960,7 +5334,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/610975f1160611f1e937a8c713a9920d75b6404490139afed03326613c085bb83f172d3fbe35eda6c0fde6f795cb972b01e44225d5296099fabd7e00c177caff + checksum: 10c0/5773fb094f0070217d78cab2e036143e746d48805795ca28c9a2a2b66caa27ca5d9df13a9b50b3663dec74487ea43f61cab1a467dd8d3b8db53c47e32e6465bb languageName: node linkType: hard @@ -5040,6 +5414,21 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-permission-common@npm:^0.9.1": + version: 0.9.1 + resolution: "@backstage/plugin-permission-common@npm:0.9.1" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.1" + cross-fetch: "npm:^4.0.0" + uuid: "npm:^11.0.0" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.20.4" + checksum: 10c0/702452feccd24bcefe7f50c2d6b87ec8b85cd9122738102ba35b3f507291b4896fb51a002bcbd6f4209e4017535c9a3f5f3ff3ea7ec9b20b4213bc4cdcce5a07 + languageName: node + linkType: hard + "@backstage/plugin-permission-node@npm:^0.10.1": version: 0.10.1 resolution: "@backstage/plugin-permission-node@npm:0.10.1" @@ -5116,6 +5505,26 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-permission-react@npm:^0.4.36": + version: 0.4.36 + resolution: "@backstage/plugin-permission-react@npm:0.4.36" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/plugin-permission-common": "npm:^0.9.1" + swr: "npm:^2.0.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/43f69d71630c922a56d38b5fb02556e1a21630cdce94687c8e2f7718c5c52745d513775f6396bc2c32273134ef441132a8568e400004fc9f6a9cc666ebd29248 + languageName: node + linkType: hard + "@backstage/plugin-proxy-backend@npm:^0.6.3": version: 0.6.3 resolution: "@backstage/plugin-proxy-backend@npm:0.6.3" @@ -5344,6 +5753,17 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-scaffolder-common@npm:^1.6.0": + version: 1.6.0 + resolution: "@backstage/plugin-scaffolder-common@npm:1.6.0" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/types": "npm:^1.2.1" + checksum: 10c0/8f34ab2f3eeed757bc79610582b3e9fe75c492e062fc4aff64ba82d5bbe2d13c3634b0f9d8426ac2168d316fa57f5c45af1d75c19b8e190f0e814f24d325c23b + languageName: node + linkType: hard + "@backstage/plugin-scaffolder-node@npm:^0.4.7, @backstage/plugin-scaffolder-node@npm:^0.4.8": version: 0.4.12 resolution: "@backstage/plugin-scaffolder-node@npm:0.4.12" @@ -5396,19 +5816,19 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-scaffolder-react@npm:^1.17.0": - version: 1.17.0 - resolution: "@backstage/plugin-scaffolder-react@npm:1.17.0" - dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/plugin-scaffolder-common": "npm:^1.5.11" - "@backstage/theme": "npm:^0.6.6" +"@backstage/plugin-scaffolder-react@npm:^1.18.0": + version: 1.18.0 + resolution: "@backstage/plugin-scaffolder-react@npm:1.18.0" + dependencies: + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/plugin-scaffolder-common": "npm:^1.6.0" + "@backstage/theme": "npm:^0.6.7" "@backstage/types": "npm:^1.2.1" "@backstage/version-bridge": "npm:^1.0.11" "@material-ui/core": "npm:^4.12.2" @@ -5444,28 +5864,28 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/5c86e320627fda02afbd0503263c1ac87aa0615a479fba039aa2a32504a7935ea09a97074ace285bc1a4fe9028fbe304a321ad298abdc7e625d73a4030251310 + checksum: 10c0/96e4529c0b844fbf3280eb860dd9c5eb2dcf84f5eaacc545db8878845e0c9cded8f51ca029d00ccf1ea27a3a3c16086df1cf1e65abb05285b9da58f6e9bde6c3 languageName: node linkType: hard -"@backstage/plugin-scaffolder@npm:^1.32.0": - version: 1.32.0 - resolution: "@backstage/plugin-scaffolder@npm:1.32.0" +"@backstage/plugin-scaffolder@npm:^1.33.0": + version: 1.33.0 + resolution: "@backstage/plugin-scaffolder@npm:1.33.0" dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/integration": "npm:^1.17.0" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/plugin-scaffolder-common": "npm:^1.5.11" - "@backstage/plugin-scaffolder-react": "npm:^1.17.0" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/integration": "npm:^1.17.1" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/plugin-scaffolder-common": "npm:^1.6.0" + "@backstage/plugin-scaffolder-react": "npm:^1.18.0" "@backstage/types": "npm:^1.2.1" "@codemirror/language": "npm:^6.0.0" "@codemirror/legacy-modes": "npm:^6.1.0" @@ -5505,7 +5925,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/69723a73308e4b5fa94e03278e07190628c5700bb4264cb58cd709262b5e15647c5e56bf83a279ad5dbecd0407f58eaf7599581fdeff6e6b14efed458e19e33e + checksum: 10c0/dcdcc7aff51ee15f910fe8213664f5e97f48f2177cc0578b18c5482a9a731279c45fb25230f7efaff0f123136b4f795e99b599312c53fde158700715d87b56e5 languageName: node linkType: hard @@ -5614,6 +6034,16 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-search-common@npm:^1.2.19": + version: 1.2.19 + resolution: "@backstage/plugin-search-common@npm:1.2.19" + dependencies: + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/types": "npm:^1.2.1" + checksum: 10c0/3d474fcce2edeb9fc4fae7eeb427af6ed24235e5aa45d1bff12993423d8c94ac4d9a273f699eedd847589d1a9317d74d804f4d8fdcd6baeabd87fb1c2d216490 + languageName: node + linkType: hard + "@backstage/plugin-search-react@npm:^1.9.1": version: 1.9.1 resolution: "@backstage/plugin-search-react@npm:1.9.1" @@ -5644,18 +6074,48 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-search@npm:^1.4.27": - version: 1.4.27 - resolution: "@backstage/plugin-search@npm:1.4.27" +"@backstage/plugin-search-react@npm:^1.9.2": + version: 1.9.2 + resolution: "@backstage/plugin-search-react@npm:1.9.2" dependencies: - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-search-common": "npm:^1.2.19" + "@backstage/theme": "npm:^0.6.7" + "@backstage/types": "npm:^1.2.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:4.0.0-alpha.61" + lodash: "npm:^4.17.21" + qs: "npm:^6.9.4" + react-use: "npm:^17.3.2" + uuid: "npm:^11.0.2" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/18f3622e6ad730446a7c4d93e319196e9851067f7c35d536c5cac243c05fd4d4da4723cee46e5e16b004e9acad6dd3ae204532ef9ce37fb4b499a7a34852cfc7 + languageName: node + linkType: hard + +"@backstage/plugin-search@npm:^1.4.28": + version: 1.4.28 + resolution: "@backstage/plugin-search@npm:1.4.28" + dependencies: + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-search-common": "npm:^1.2.18" - "@backstage/plugin-search-react": "npm:^1.9.1" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-search-common": "npm:^1.2.19" + "@backstage/plugin-search-react": "npm:^1.9.2" "@backstage/types": "npm:^1.2.1" "@backstage/version-bridge": "npm:^1.0.11" "@material-ui/core": "npm:^4.12.2" @@ -5670,7 +6130,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/42c8f48d7a7dfc014505e8a722f378f88ab41abf15472d62ae59d4c529ab19a8605c66d91f5a4db4102b68226d1b59ab63c08745179ae0c4813e96e00a4f09b1 + checksum: 10c0/f482db567468a149ffbfa4826f79572953532b7268c4c3cbd81b8b7070d10f5d6087182efda8aaf392dfd8acdeba8911f23901f7e06a17817149401dc0014107 languageName: node linkType: hard @@ -5821,27 +6281,56 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-techdocs@npm:^1.13.0": - version: 1.13.1 - resolution: "@backstage/plugin-techdocs@npm:1.13.1" +"@backstage/plugin-techdocs-react@npm:^1.3.1": + version: 1.3.1 + resolution: "@backstage/plugin-techdocs-react@npm:1.3.1" dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/config": "npm:^1.3.2" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-techdocs-common": "npm:^0.1.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/styles": "npm:^4.11.0" + jss: "npm:~10.10.0" + lodash: "npm:^4.17.21" + react-helmet: "npm:6.1.0" + react-use: "npm:^17.2.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7c7d28b7ff324cac2f0c7d7af737e48dcb0a05e36289806690b405dacfe4651bbe4fbe7f46873c53a123cd9b41a3cda6510144720be8a920dbcdfb77b87206f5 + languageName: node + linkType: hard + +"@backstage/plugin-techdocs@npm:^1.13.2": + version: 1.13.2 + resolution: "@backstage/plugin-techdocs@npm:1.13.2" + dependencies: + "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-compat-api": "npm:^0.4.4" + "@backstage/core-components": "npm:^0.17.4" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/integration": "npm:^1.17.0" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-auth-react": "npm:^0.1.16" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/plugin-search-common": "npm:^1.2.18" - "@backstage/plugin-search-react": "npm:^1.9.1" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/integration": "npm:^1.17.1" + "@backstage/integration-react": "npm:^1.2.9" + "@backstage/plugin-auth-react": "npm:^0.1.17" + "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-search-common": "npm:^1.2.19" + "@backstage/plugin-search-react": "npm:^1.9.2" "@backstage/plugin-techdocs-common": "npm:^0.1.1" - "@backstage/plugin-techdocs-react": "npm:^1.3.0" - "@backstage/theme": "npm:^0.6.6" + "@backstage/plugin-techdocs-react": "npm:^1.3.1" + "@backstage/theme": "npm:^0.6.7" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -5861,7 +6350,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/a6dfe74738a8e2c85b9ee90411bb2076b5628406eb3e24d8cce0e229e04e268f044c015bdd7356396073df7547b5290316b2fb2c7111bd301a6b0fe08c765387 + checksum: 10c0/67616bf938e16572b2f659872a0136c818ba2ffd295dadaf46d2849c42ab90b08f50753d91aecc8b64da4a19c4a5f80f8d2b9791dad9c3ddf152c585a2285097 languageName: node linkType: hard @@ -5941,6 +6430,35 @@ __metadata: languageName: node linkType: hard +"@backstage/test-utils@npm:^1.7.10": + version: 1.7.10 + resolution: "@backstage/test-utils@npm:1.7.10" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-app-api": "npm:^1.18.0" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/theme": "npm:^0.6.7" + "@backstage/types": "npm:^1.2.1" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + cross-fetch: "npm:^4.0.0" + i18next: "npm:^22.4.15" + zen-observable: "npm:^0.10.0" + peerDependencies: + "@testing-library/react": ^16.0.0 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5f8f8e9757961143bbf24ed118dca8d817e1151cb6185b735175b9b4976f6bf3dc31a08b78af49aa966edbd6367afa914b5566b6e046f7d883dfc40aa8523534 + languageName: node + linkType: hard + "@backstage/theme@npm:^0.5.6": version: 0.5.7 resolution: "@backstage/theme@npm:0.5.7" @@ -5977,6 +6495,26 @@ __metadata: languageName: node linkType: hard +"@backstage/theme@npm:^0.6.7": + version: 0.6.7 + resolution: "@backstage/theme@npm:0.6.7" + dependencies: + "@emotion/react": "npm:^11.10.5" + "@emotion/styled": "npm:^11.10.5" + "@mui/material": "npm:^5.12.2" + peerDependencies: + "@material-ui/core": ^4.12.2 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/53f43c01d0af7affbad748761c3b4d0767aba53ad05eabfb76703234e76d0b52515e003ba1f851225f4b24be24094eca1ed748b967c5926c345c70c8bcf5d894 + languageName: node + linkType: hard + "@backstage/types@npm:^1.1.1, @backstage/types@npm:^1.2.1": version: 1.2.1 resolution: "@backstage/types@npm:1.2.1" @@ -10151,14 +10689,17 @@ __metadata: version: 0.0.0-use.local resolution: "@pagerduty/backstage-plugin@workspace:plugins/backstage-plugin" dependencies: + "@backstage/catalog-client": "npm:^1.10.2" "@backstage/catalog-model": "npm:^1.5.0" "@backstage/cli": "npm:^0.33.0" "@backstage/core-app-api": "npm:^1.14.0" + "@backstage/core-compat-api": "npm:^0.4.4" "@backstage/core-components": "npm:^0.14.9" "@backstage/core-plugin-api": "npm:^1.9.3" "@backstage/dev-utils": "npm:^1.0.35" "@backstage/errors": "npm:^1.2.4" - "@backstage/plugin-catalog-react": "npm:^1.12.2" + "@backstage/frontend-plugin-api": "npm:^0.10.4" + "@backstage/plugin-catalog-react": "npm:^1.19.1" "@backstage/plugin-home-react": "npm:^0.1.15" "@backstage/test-utils": "npm:^1.5.8" "@backstage/theme": "npm:^0.5.6" @@ -17131,20 +17672,21 @@ __metadata: "@backstage/core-app-api": "npm:^1.17.1" "@backstage/core-components": "npm:^0.17.3" "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/frontend-defaults": "npm:^0.2.4" "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-api-docs": "npm:^0.12.8" - "@backstage/plugin-catalog": "npm:^1.31.0" + "@backstage/plugin-api-docs": "npm:^0.12.9" + "@backstage/plugin-catalog": "npm:^1.31.1" "@backstage/plugin-catalog-common": "npm:^1.1.4" "@backstage/plugin-catalog-graph": "npm:^0.4.20" - "@backstage/plugin-catalog-import": "npm:^0.13.1" + "@backstage/plugin-catalog-import": "npm:^0.13.3" "@backstage/plugin-catalog-react": "npm:^1.19.0" "@backstage/plugin-kubernetes": "npm:^0.12.8" - "@backstage/plugin-org": "npm:^0.6.40" + "@backstage/plugin-org": "npm:^0.6.41" "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/plugin-scaffolder": "npm:^1.32.0" - "@backstage/plugin-search": "npm:^1.4.27" + "@backstage/plugin-scaffolder": "npm:^1.33.0" + "@backstage/plugin-search": "npm:^1.4.28" "@backstage/plugin-search-react": "npm:^1.9.1" - "@backstage/plugin-techdocs": "npm:^1.13.0" + "@backstage/plugin-techdocs": "npm:^1.13.2" "@backstage/plugin-techdocs-module-addons-contrib": "npm:^1.1.25" "@backstage/plugin-techdocs-react": "npm:^1.3.0" "@backstage/plugin-user-settings": "npm:^0.8.23" From 27efe946364e6bd3230d1fad2207d48d0e120cf5 Mon Sep 17 00:00:00 2001 From: sandornagy517 <67263678+sandornagy517@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:55:19 +0200 Subject: [PATCH 3/9] feat: Migrate entity EntityPagerDutySmall card to backstage UI #62 (#64) * feat: Migrate the relevant components of PagerDutySmallCard to Backstage UI * chore: Adjust unit tests after migrating EntityPagerDutySmallCard * chore: Update the imports of backstage ui css * style: Remove useless line breaks * chore: Fix failing unit tests * feat: Include backstage ui css in the app package * fix: Adjust styles for dark theme * docs: Add tests for dark theme to the PR checklist --- app-config.yaml | 1 + packages/app/package.json | 1 + packages/app/src/index.tsx | 1 + plugins/backstage-plugin/dev/index.tsx | 1 + plugins/backstage-plugin/package.json | 1 + .../EntityPagerDutyCard/index.test.tsx | 60 +++++--- .../EntityPagerDutySmallCard/index.test.tsx | 60 +++++--- .../components/Escalation/Escalation.test.tsx | 34 +++-- .../components/Escalation/EscalationUser.tsx | 24 ++-- .../components/PagerDutyCard/index.test.tsx | 55 ++++--- .../PagerDutyCardCommon/InsightsCard.tsx | 3 +- .../PagerDutyCardCommon/OpenServiceButton.tsx | 45 +++--- .../ServiceStandardsCard.tsx | 134 +++++++++--------- .../PagerDutyCardCommon/StatusCard.tsx | 4 +- .../TriggerIncidentButton.tsx | 47 +++--- .../PagerDutySmallCard/index.test.tsx | 54 ++++--- .../components/PagerDutySmallCard/index.tsx | 115 ++++++--------- .../components/TriggerButton/index.test.tsx | 17 ++- .../TriggerDialog/TriggerDialog.test.tsx | 15 ++ .../TriggerDialog/TriggerDialog.tsx | 23 +-- pull_request_template.md | 7 +- yarn.lock | 83 +++++++++++ 22 files changed, 496 insertions(+), 289 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index e9b3816..f83df5f 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -122,3 +122,4 @@ pagerDuty: clientId: ${PAGERDUTY_CLIENT_ID} clientSecret: ${PAGERDUTY_CLIENT_SECRET} subDomain: ${PAGERDUTY_SUBDOMAIN} + region: ${PAGERDUTY_OAUTH_REGION} diff --git a/packages/app/package.json b/packages/app/package.json index bbea99b..2b4c1f1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -40,6 +40,7 @@ "@backstage/plugin-techdocs-react": "^1.3.0", "@backstage/plugin-user-settings": "^0.8.23", "@backstage/theme": "^0.6.6", + "@backstage/ui": "^0.6.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@pagerduty/backstage-plugin": "workspace:^", diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index cc8e77a..07d1441 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -1,6 +1,7 @@ import '@backstage/cli/asset-types'; import ReactDOM from 'react-dom/client'; import '@backstage/canon/css/styles.css'; +import '@backstage/ui/css/styles.css'; // Uncomment the lines below if you want to use the old version of the app // import App from './App'; diff --git a/plugins/backstage-plugin/dev/index.tsx b/plugins/backstage-plugin/dev/index.tsx index dfe2ae2..541a19d 100644 --- a/plugins/backstage-plugin/dev/index.tsx +++ b/plugins/backstage-plugin/dev/index.tsx @@ -26,6 +26,7 @@ import { pagerDutyApiRef } from '../src/api'; import { mockPagerDutyApi } from './mockPagerDutyApi'; import { mockEntity } from './mockEntity'; import { Grid } from '@material-ui/core'; +import '@backstage/ui/css/styles.css'; createDevApp() .registerApi({ diff --git a/plugins/backstage-plugin/package.json b/plugins/backstage-plugin/package.json index 22b8f1d..c64f881 100644 --- a/plugins/backstage-plugin/package.json +++ b/plugins/backstage-plugin/package.json @@ -51,6 +51,7 @@ "@backstage/plugin-catalog-react": "^1.19.1", "@backstage/plugin-home-react": "^0.1.15", "@backstage/theme": "^0.5.6", + "@backstage/ui": "^0.6.1", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@material-ui/core": "^4.12.2", diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx index 49f88cc..417f852 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx @@ -133,6 +133,22 @@ const apis = TestApiRegistry.from( ); describe('isPluginApplicableToEntity', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); + describe('when entity has no annotations', () => { it('returns false', () => { expect(isPluginApplicableToEntity(entityWithoutAnnotations)).toBe(false); @@ -180,9 +196,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -248,7 +266,7 @@ describe('EntityPagerDutyCard', () => { .fn() .mockImplementationOnce(async () => ({ service })); - const { getByText, queryByTestId, getByRole } = render( + const { getByText, queryByTestId, getByRole, getByLabelText } = render( wrapInTestApp( @@ -260,7 +278,7 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - const triggerLink = getByText('Create new incident'); + const triggerLink = getByLabelText('create-incident'); await act(async () => { fireEvent.click(triggerLink); }); @@ -290,9 +308,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -397,9 +417,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -426,9 +448,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -477,9 +501,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); expect(() => getByText('Create new incident')).toThrow(); }); }); diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.test.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.test.tsx index 8ab1923..c9b463c 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.test.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.test.tsx @@ -133,6 +133,21 @@ const apis = TestApiRegistry.from( ); describe('isPluginApplicableToEntity', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); describe('when entity has no annotations', () => { it('returns false', () => { expect(isPluginApplicableToEntity(entityWithoutAnnotations)).toBe(false); @@ -174,15 +189,18 @@ describe('EntityPagerDutyCard', () => { ), ); await waitFor(() => !queryByTestId('progress')); + expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -248,7 +266,7 @@ describe('EntityPagerDutyCard', () => { .fn() .mockImplementationOnce(async () => ({ service })); - const { getByText, queryByTestId, getByRole } = render( + const { getByText, queryByTestId, getByRole, getByLabelText } = render( wrapInTestApp( @@ -260,7 +278,7 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - const triggerLink = getByText('Create new incident'); + const triggerLink = getByLabelText('create-incident'); await act(async () => { fireEvent.click(triggerLink); }); @@ -289,9 +307,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -395,9 +415,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -423,9 +445,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -473,9 +497,11 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); expect(() => getByText('Create new incident')).toThrow(); }); }); diff --git a/plugins/backstage-plugin/src/components/Escalation/Escalation.test.tsx b/plugins/backstage-plugin/src/components/Escalation/Escalation.test.tsx index d0c57ba..c46389b 100644 --- a/plugins/backstage-plugin/src/components/Escalation/Escalation.test.tsx +++ b/plugins/backstage-plugin/src/components/Escalation/Escalation.test.tsx @@ -27,6 +27,21 @@ const mockPagerDutyApi = { const apis = TestApiRegistry.from([pagerDutyApiRef, mockPagerDutyApi]); describe('Escalation', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); it('Handles an empty response', async () => { mockPagerDutyApi.getOnCallByPolicyId = jest .fn() @@ -47,9 +62,11 @@ describe('Escalation', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); expect(mockPagerDutyApi.getOnCallByPolicyId).toHaveBeenCalledWith( '456', undefined, @@ -135,7 +152,7 @@ describe('Escalation', () => { ] as PagerDutyUser[], ); - const { getByText, queryByTestId, getByAltText } = render( + const { getByText, queryByTestId } = render( wrapInTestApp( { expect(getByText('person1')).toBeInTheDocument(); expect(getByText('person1@example.com')).toBeInTheDocument(); - expect(getByAltText('person1')).toHaveAttribute( - 'src', - 'https://gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?f=y', - ); + // TODO: once Backstage UI avatar supports ALT tags uncomment this + // expect(getByAltText('person1')).toHaveAttribute( + // 'src', + // 'https://gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?f=y', + // ); expect(mockPagerDutyApi.getOnCallByPolicyId).toHaveBeenCalledWith( 'abc', undefined, diff --git a/plugins/backstage-plugin/src/components/Escalation/EscalationUser.tsx b/plugins/backstage-plugin/src/components/Escalation/EscalationUser.tsx index 50c9782..465eb4a 100644 --- a/plugins/backstage-plugin/src/components/Escalation/EscalationUser.tsx +++ b/plugins/backstage-plugin/src/components/Escalation/EscalationUser.tsx @@ -20,13 +20,12 @@ import { Tooltip, ListItemText, makeStyles, - IconButton, Typography, } from '@material-ui/core'; -import Avatar from '@material-ui/core/Avatar'; import { PagerDutyUser } from '@pagerduty/backstage-plugin-common'; import NotificationsIcon from '@material-ui/icons/Notifications'; import { BackstageTheme } from '@backstage/theme'; +import { Avatar, Button } from '@backstage/ui'; const useStyles = makeStyles(theme => ({ listItemPrimary: { @@ -38,12 +37,9 @@ const useStyles = makeStyles(theme => ({ marginTop: '-5px', }, buttonStyle: { - marginLeft: '-11px', - marginTop: '-10px', + marginLeft: '-5px', fontSize: '15px', - color: theme.palette.text.primary, '&:hover': { - backgroundColor: 'transparent', textDecoration: 'underline', }, }, @@ -62,6 +58,7 @@ const useStyles = makeStyles(theme => ({ display: 'flex', alignItems: 'center', fontWeight: 'bold', + color: theme.palette.text.primary, }, iconStyle: { fontSize: '25px', @@ -94,7 +91,7 @@ export const EscalationUser = ({ user, policyUrl, policyName }: Props) => { @@ -103,7 +100,8 @@ export const EscalationUser = ({ user, policyUrl, policyName }: Props) => { primary={ <> - navigateToUrl(user.html_url)} className={classes.userTextButtonStyle} @@ -111,7 +109,7 @@ export const EscalationUser = ({ user, policyUrl, policyName }: Props) => { {user.name} - + { } secondary={ - navigateToUrl(policyUrl)} + variant="tertiary" + size="small" className={classes.buttonStyle} + iconStart={} > - {policyName} - + } /> diff --git a/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx b/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx index 9559213..a131a5b 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx @@ -81,6 +81,21 @@ const apis = TestApiRegistry.from( ); describe('PagerDutyCard', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); it('Render pagerduty', async () => { mockPagerDutyApi.getServiceByPagerDutyEntity = jest .fn() @@ -100,9 +115,11 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -162,7 +179,7 @@ describe('PagerDutyCard', () => { .fn() .mockImplementationOnce(async () => ({ service })); - const { getByText, queryByTestId, getByRole } = render( + const { getByText, queryByTestId, getByRole, getByLabelText } = render( wrapInTestApp( @@ -172,7 +189,7 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - const triggerLink = getByText('Create new incident'); + const triggerLink = getByLabelText('create-incident'); await act(async () => { fireEvent.click(triggerLink); }); @@ -199,9 +216,11 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -310,9 +329,11 @@ describe('PagerDutyCard', () => { expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -335,13 +356,15 @@ describe('PagerDutyCard', () => { ), ); await waitFor(() => !queryByTestId('progress')); - expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + getByText('Open service in PagerDuty'); + getByText('Nice! No incidents found!'); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); expect(() => getByText('Create new incident')).toThrow(); }); }); diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/InsightsCard.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/InsightsCard.tsx index 96bb0f0..ec4a051 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/InsightsCard.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/InsightsCard.tsx @@ -1,5 +1,6 @@ import { BackstageTheme } from '@backstage/theme'; -import { Card, Typography, makeStyles } from '@material-ui/core'; +import { Card } from '@backstage/ui'; +import { Typography, makeStyles } from '@material-ui/core'; import validateColor from 'validate-color'; type Props = { diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx index c7a55f0..0b0354e 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx @@ -14,11 +14,11 @@ * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports -import { makeStyles, IconButton, Typography } from '@material-ui/core'; +import { makeStyles, Typography } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import OpenInBrowser from '@material-ui/icons/OpenInBrowser'; +import { ButtonIcon } from '@backstage/ui'; type OpenServiceButtonProps = { serviceUrl: string; @@ -31,46 +31,37 @@ export function OpenServiceButton({ compact, }: OpenServiceButtonProps) { const useStyles = makeStyles(theme => ({ - buttonStyle: { - color: theme.palette.text.primary, - '&:hover': { - backgroundColor: 'transparent', - textDecoration: 'underline', - }, - }, containerStyle: { + color: theme.palette.text.primary, fontSize: compact !== true ? '12px' : '10px', width: compact !== true ? '85px' : '70px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + textAlign: 'center', }, iconStyle: { - fontSize: '30px', - marginBottom: '-10px', - }, - textStyle: { - marginBottom: '-10px', + color: theme.palette.text.primary, }, })); - const { buttonStyle, containerStyle, iconStyle, textStyle } = useStyles(); + const { containerStyle, iconStyle } = useStyles(); function navigateToService() { window.open(serviceUrl, '_blank'); } return ( - <> - + -
- - - Open service in PagerDuty - -
-
- + variant="tertiary" + icon={} + /> + + Open service in PagerDuty + ); } diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx index 19b3d7b..d0951e2 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx @@ -1,10 +1,7 @@ import { BackstageTheme } from '@backstage/theme'; import { - Card, - IconButton, LinearProgress, Theme, - Tooltip, Typography, makeStyles, withStyles, @@ -13,6 +10,7 @@ import InfoIcon from '@material-ui/icons/Info'; import { PagerDutyServiceStandard } from '@pagerduty/backstage-plugin-common'; import CheckCircle from '@material-ui/icons/CheckCircle'; import RadioButtonUncheckedIcon from '@material-ui/icons/RadioButtonUnchecked'; +import { ButtonIcon, Card, Flex, Tooltip, TooltipTrigger } from '@backstage/ui'; type Props = { total: number | undefined; @@ -21,7 +19,7 @@ type Props = { compact?: boolean; }; -function colorFromPercentage(theme: Theme, percentage: number) { +export function colorFromPercentage(theme: Theme, percentage: number) { if (percentage < 0.5) { return theme.palette.error.main; } else if (percentage < 0.8) { @@ -34,15 +32,10 @@ function ServiceStandardsCard({ total, completed, standards, compact }: Props) { const useStyles = makeStyles(theme => ({ cardStyle: { height: compact !== true ? '120px' : '80px', - display: 'grid', - gridTemplateRows: '1fr auto auto', + padding: 0, + position: 'relative', backgroundColor: 'rgba(0, 0, 0, 0.03)', }, - containerStyle: { - display: 'flex', - justifyContent: 'center', - marginTop: compact !== true ? '-100px' : '-50px', - }, largeTextStyle: { fontSize: compact !== true ? '50px' : '40px', color: @@ -57,18 +50,38 @@ function ServiceStandardsCard({ total, completed, standards, compact }: Props) { fontSize: compact !== true ? '14px' : '12px', fontWeight: 'bold', alignSelf: 'center', - justifyContent: 'center', - marginLeft: '-2px', - marginTop: compact !== true ? '25px' : '20px', + marginLeft: '-20px', + marginBottom: '-20px', }, - tooltipContainer: {}, tooltipIcon: { marginRight: '5px', }, + infoIcon: { + color: 'gray', + '&:hover': { + backgroundColor: 'transparent', + }, + }, standardItem: { display: 'flex', alignItems: 'center', }, + linearProgressContainer: { + left: 0, + position: 'absolute', + bottom: 0, + width: '100%', + padding: '0px', + }, + textContainerStyle: { + position: 'absolute', + top: compact ? '5px' : '20px', + width: '100%', + }, + tooltipTriggerStyles: { + position: 'relative', + zIndex: 1, + }, })); const BorderLinearProgress = withStyles(theme => ({ @@ -92,12 +105,14 @@ function ServiceStandardsCard({ total, completed, standards, compact }: Props) { const { cardStyle, - containerStyle, largeTextStyle, smallTextStyle, - tooltipContainer, + linearProgressContainer, tooltipIcon, + textContainerStyle, + infoIcon, standardItem, + tooltipTriggerStyles, } = useStyles(); if ( @@ -107,65 +122,52 @@ function ServiceStandardsCard({ total, completed, standards, compact }: Props) { ) { return ( -
+ Unable to retrieve Scores -
+
); } return ( - {completed !== undefined && total !== undefined ? ( - <> -
- - - {standards?.map((standard, key) => ( - - {standard.pass ? ( - - {' '} - {standard.name} - - ) : ( - - {' '} - {standard.name} - - )} - - ))} - - } - > - - - -
-
- {completed} - /{total} -
-
- -
- - ) : ( -
- - Unable to retrieve Scores - + + + } + variant="tertiary" + /> + + {standards?.map((standard, key) => ( + + {standard.pass ? ( + + {standard.name} + + ) : ( + + {' '} + {standard.name} + + )} + + ))} + + + + {completed} + /{total} + +
+
- )} +
); } diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/StatusCard.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/StatusCard.tsx index 1f009d0..020badc 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/StatusCard.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/StatusCard.tsx @@ -1,4 +1,3 @@ -import { Card, Typography } from '@material-ui/core'; import { useEffect } from 'react'; import { Theme, makeStyles } from '@material-ui/core/styles'; import { BackstageTheme } from '@backstage/theme'; @@ -7,6 +6,8 @@ import { pagerDutyApiRef } from '../../api'; import { useAsyncFn } from 'react-use'; import Alert from '@material-ui/lab/Alert/Alert'; import { Progress } from '@backstage/core-components'; +import { Card } from '@backstage/ui'; +import { Typography } from '@material-ui/core'; type Props = { serviceId: string; @@ -89,7 +90,6 @@ function StatusCard({ serviceId, refreshStatus, account, compact }: Props) { status !== undefined ? colorFromStatus(theme, status) : colorFromStatus(theme, 'active'), - marginRight: '10px', }, largeTextStyle: { color: 'white', diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx index 4d7fd9e..a62f434 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx @@ -16,11 +16,12 @@ // eslint-disable-next-line @backstage/no-undeclared-imports import { useCallback, useState } from 'react'; -import { makeStyles, IconButton, Typography } from '@material-ui/core'; +import { makeStyles, Typography } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import { TriggerDialog } from '../TriggerDialog'; import AddAlert from '@material-ui/icons/AddAlert'; +import { ButtonIcon } from '@backstage/ui'; /** @public */ export type TriggerIncidentButtonProps = { @@ -38,28 +39,25 @@ export function TriggerIncidentButton({ handleRefresh, }: TriggerIncidentButtonProps) { const useStyles = makeStyles(theme => ({ - buttonStyle: { - color: theme.palette.text.primary, - '&:hover': { - backgroundColor: 'transparent', - textDecoration: 'underline', - }, - }, containerStyle: { fontSize: compact !== true ? '12px' : '10px', width: compact !== true ? '80px' : '60px', - marginRight: '-10px', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + color: theme.palette.text.primary, }, + iconStyle: { - fontSize: '30px', - marginBottom: '-10px', + color: theme.palette.text.primary, }, + textStyle: { - marginBottom: '-10px', + textAlign: 'center', }, })); - const { buttonStyle, containerStyle, iconStyle, textStyle } = useStyles(); + const { containerStyle, textStyle, iconStyle } = useStyles(); const [dialogShown, setDialogShown] = useState(false); const showDialog = useCallback(() => { @@ -73,17 +71,18 @@ export function TriggerIncidentButton({ return ( <> - -
- - Create new incident -
-
+
+ } + /> + + Create new incident +
{integrationKey && ( { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); it('Render pagerduty', async () => { mockPagerDutyApi.getServiceByPagerDutyEntity = jest .fn() @@ -96,10 +111,11 @@ describe('PagerDutySmallCard', () => { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -159,7 +175,7 @@ describe('PagerDutySmallCard', () => { .fn() .mockImplementationOnce(async () => ({ service })); - const { getByText, queryByTestId, getByRole } = render( + const { getByText, queryByTestId, getByRole, getByLabelText } = render( wrapInTestApp( @@ -169,8 +185,8 @@ describe('PagerDutySmallCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - const triggerLink = getByText('Create new incident'); - await act(async () => { + const triggerLink = getByLabelText('create-incident'); + await act(() => { fireEvent.click(triggerLink); }); expect(getByRole('dialog')).toBeInTheDocument(); @@ -194,9 +210,11 @@ describe('PagerDutySmallCard', () => { expect(getByText('Create new incident')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); it('Handles custom error for missing token', async () => { @@ -304,9 +322,11 @@ describe('PagerDutySmallCard', () => { expect(getByText('Create new incident')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); }); }); @@ -332,9 +352,11 @@ describe('PagerDutySmallCard', () => { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); await waitFor(() => !queryByTestId('escalation-progress')); - expect( - getByText('No one is on-call. Update the escalation policy.'), - ).toBeInTheDocument(); + await waitFor(() => + expect( + getByText('No one is on-call. Update the escalation policy.'), + ).toBeInTheDocument(), + ); expect(() => getByText('Create new incident')).toThrow(); }); }); diff --git a/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx b/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx index 3081ba1..a998dd5 100644 --- a/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx @@ -19,11 +19,10 @@ import { Accordion, AccordionDetails, AccordionSummary, - Card, CardHeader, - Grid, Typography, } from '@material-ui/core'; +import { Card, Flex, Grid } from '@backstage/ui'; import useAsync from 'react-use/lib/useAsync'; import { pagerDutyApiRef, UnauthorizedError } from '../../api'; import { MissingTokenError, ServiceNotFoundError } from '../Errors'; @@ -58,42 +57,10 @@ const useStyles = makeStyles(theme => ? 'rgba(0, 0, 0, 0.54)' : 'rgba(255, 255, 255, 0.7)', }, - headerStyle: { - marginBottom: '0px', - fontSize: '0px', - }, - overviewHeaderContainerStyle: { - display: 'flex', - margin: '0px', - padding: '15px', - marginBottom: '5px', - }, - headerWithSubheaderContainerStyle: { - display: 'flex', - alignItems: 'center', - }, subheaderTextStyle: { fontSize: '10px', - marginLeft: '5px', - }, - overviewCardsContainerStyle: { - display: 'flex', - margin: '15px', - marginTop: '-15px', - }, - onCallAccordionDetails: { - display: 'flex', - width: '100%', - marginTop: '-25px', - marginBottom: '-15px', - }, - incidentMetricsContainerStyle: { - display: 'flex', - height: '100%', - justifyContent: 'center', - columnSpan: 'all', - margin: '15px', - marginTop: '-15px', + paddingLeft: '5px', + paddingTop: '3px', }, }), ); @@ -185,9 +152,13 @@ export const PagerDutySmallCard = (props: PagerDutyCardProps) => { } return ( - + @@ -197,7 +168,7 @@ export const PagerDutySmallCard = (props: PagerDutyCardProps) => { } action={ !readOnly && props.integrationKey ? ( -
+ { handleRefresh={handleRefresh} /> -
+ ) : ( ) } /> - - + + + STATUS - - + + STANDARDS - - + + - - + + - - + + { : undefined } /> - - + + + {disableInsights !== true ? ( { aria-controls="panel1a-content" id="panel1a-header" > - - - INSIGHTS - - - (last 30 days) - + + INSIGHTS + + + (last 30 days) - - + { label="interruptions" color={theme.palette.textSubtle} /> - - + + { label="high urgency" color={theme.palette.warning.main} /> - - + + { label="incidents" color={theme.palette.error.main} /> - - + + ) : ( @@ -332,7 +305,7 @@ export const PagerDutySmallCard = (props: PagerDutyCardProps) => { ON CALL - + { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); const mockTriggerAlarmFn = jest.fn(); const mockPagerDutyApi = { triggerAlarm: mockTriggerAlarmFn, @@ -65,7 +80,7 @@ describe('TriggerButton', () => { expect(screen.getByRole('dialog')).toBeInTheDocument(); }); - const closeButton = screen.getByText('Close'); + const closeButton = screen.getByText('CLOSE'); await act(async () => { fireEvent.click(closeButton); }); diff --git a/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.test.tsx b/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.test.tsx index b3ba34d..2fb9b0a 100644 --- a/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.test.tsx +++ b/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.test.tsx @@ -27,6 +27,21 @@ import { } from '@backstage/core-plugin-api'; describe('TriggerDialog', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); const mockIdentityApi: Partial = { getBackstageIdentity: async () => ({ type: 'user', diff --git a/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.tsx index e53bfaf..1809396 100644 --- a/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.tsx +++ b/plugins/backstage-plugin/src/components/TriggerDialog/TriggerDialog.tsx @@ -21,10 +21,10 @@ import { DialogTitle, TextField, DialogActions, - Button, DialogContent, Typography, CircularProgress, + useTheme, } from '@material-ui/core'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import { pagerDutyApiRef } from '../../api'; @@ -35,6 +35,7 @@ import { identityApiRef, } from '@backstage/core-plugin-api'; import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model'; +import { Button } from '@backstage/ui'; type Props = { showDialog: boolean; @@ -55,6 +56,7 @@ export const TriggerDialog = ({ const identityApi = useApi(identityApiRef); const api = useApi(pagerDutyApiRef); const [description, setDescription] = useState(''); + const theme = useTheme(); const [{ value, loading, error }, handleTriggerAlarm] = useAsyncFn( async (descriptions: string) => { @@ -147,16 +149,21 @@ export const TriggerDialog = ({ - diff --git a/pull_request_template.md b/pull_request_template.md index 6da68bf..990e9b8 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,6 +1,6 @@ ### Description -*Please include a summary of the change or which issue is fixed.* +_Please include a summary of the change or which issue is fixed._ **Issue number:** (e.g. #123) @@ -21,8 +21,9 @@ - [ ] I have performed a self-review of this change - [ ] Changes have been tested +- [ ] Changes have been tested in dark theme - [ ] Changes are documented -- [ ] Changes generate *no new warnings* +- [ ] Changes generate _no new warnings_ - [ ] PR title follows [conventional commit semantics](https://www.conventionalcommits.org/en/v1.0.0/) If this is a breaking change 👇 @@ -34,4 +35,4 @@ If this is a breaking change 👇 By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. -**Disclaimer:** We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. \ No newline at end of file +**Disclaimer:** We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful. diff --git a/yarn.lock b/yarn.lock index 2a7691e..4436ee1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6522,6 +6522,28 @@ __metadata: languageName: node linkType: hard +"@backstage/ui@npm:^0.6.1": + version: 0.6.1 + resolution: "@backstage/ui@npm:0.6.1" + dependencies: + "@base-ui-components/react": "npm:1.0.0-alpha.7" + "@remixicon/react": "npm:^4.6.0" + "@tanstack/react-table": "npm:^8.21.3" + clsx: "npm:^2.1.1" + motion: "npm:^12.20.1" + react-aria-components: "npm:^1.10.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/8197be8c3bdec464dfc1ce1246e3fffd662e749e73a01fca6f8338611e1d14a6f36562943cc73d7c8125434b003b6553cfb48b4f3d250ca603bdc2086d191baa + languageName: node + linkType: hard + "@backstage/version-bridge@npm:^1.0.11, @backstage/version-bridge@npm:^1.0.8": version: 1.0.11 resolution: "@backstage/version-bridge@npm:1.0.11" @@ -10703,6 +10725,7 @@ __metadata: "@backstage/plugin-home-react": "npm:^0.1.15" "@backstage/test-utils": "npm:^1.5.8" "@backstage/theme": "npm:^0.5.6" + "@backstage/ui": "npm:^0.6.1" "@emotion/react": "npm:^11.11.4" "@emotion/styled": "npm:^11.11.5" "@material-ui/core": "npm:^4.12.2" @@ -17692,6 +17715,7 @@ __metadata: "@backstage/plugin-user-settings": "npm:^0.8.23" "@backstage/test-utils": "npm:^1.7.9" "@backstage/theme": "npm:^0.6.6" + "@backstage/ui": "npm:^0.6.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@pagerduty/backstage-plugin": "workspace:^" @@ -23319,6 +23343,28 @@ __metadata: languageName: node linkType: hard +"framer-motion@npm:^12.23.12": + version: 12.23.12 + resolution: "framer-motion@npm:12.23.12" + dependencies: + motion-dom: "npm:^12.23.12" + motion-utils: "npm:^12.23.6" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10c0/40dfb57bf714075c4f6dd0bbe5b84dd11310114474ebf603846ef9b888ed475fa653271c1fd98ec57a6a1d0b781cdf8b3ebcd5e2c6a3620e934b46304ae0fd39 + languageName: node + linkType: hard + "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -29074,6 +29120,43 @@ __metadata: languageName: node linkType: hard +"motion-dom@npm:^12.23.12": + version: 12.23.12 + resolution: "motion-dom@npm:12.23.12" + dependencies: + motion-utils: "npm:^12.23.6" + checksum: 10c0/1b6a4b86c1aed5b5da7b8a5d1f8310ad169125235bdc1953b8c41cf9f4e2c460ee90bb48ffdae54daecb8db1d7006566ceb5f5c9ccdc82606d548c527cb2631e + languageName: node + linkType: hard + +"motion-utils@npm:^12.23.6": + version: 12.23.6 + resolution: "motion-utils@npm:12.23.6" + checksum: 10c0/c058e8ba6423b3baa63e985bcc669877ee7d9579d938f5348b4e60c5ea1b4b33dd7f4877434436a4a5807f3cf00370d3fd4079a6fdd6309c5c87aa62b311a897 + languageName: node + linkType: hard + +"motion@npm:^12.20.1": + version: 12.23.12 + resolution: "motion@npm:12.23.12" + dependencies: + framer-motion: "npm:^12.23.12" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10c0/48137c82b4fc8e55e06031f17219b2eb4385f028e77717aa6b2e87238c1e42d4222fb4b59b6527ebb66f98ea5f1234edd17c15682985e690b8cf48a5f3e44e67 + languageName: node + linkType: hard + "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4" From d52a5d799decb250b3f206870e05eb7343b6e1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Mon, 18 Aug 2025 14:09:23 +0100 Subject: [PATCH 4/9] chore: remove remainings of old backend system (#63) * chore: remove remainings of old backend system * changeset --- .changeset/great-cooks-crash.md | 5 ++ plugins/backstage-plugin-backend/src/run.ts | 17 ----- .../src/service/standaloneServer.ts | 63 ------------------- 3 files changed, 5 insertions(+), 80 deletions(-) create mode 100644 .changeset/great-cooks-crash.md delete mode 100644 plugins/backstage-plugin-backend/src/run.ts delete mode 100644 plugins/backstage-plugin-backend/src/service/standaloneServer.ts diff --git a/.changeset/great-cooks-crash.md b/.changeset/great-cooks-crash.md new file mode 100644 index 0000000..3ed6199 --- /dev/null +++ b/.changeset/great-cooks-crash.md @@ -0,0 +1,5 @@ +--- +'@pagerduty/backstage-plugin-backend': patch +--- + +Remove remainings of old backend system diff --git a/plugins/backstage-plugin-backend/src/run.ts b/plugins/backstage-plugin-backend/src/run.ts deleted file mode 100644 index 79c6bd6..0000000 --- a/plugins/backstage-plugin-backend/src/run.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { getRootLogger } from '@backstage/backend-common'; -import yn from 'yn'; -import { startStandaloneServer } from './service/standaloneServer'; - -const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; -const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); -const logger = getRootLogger(); - -startStandaloneServer({ port, enableCors, logger }).catch(err => { - logger.error(err); - process.exit(1); -}); - -process.on('SIGINT', () => { - logger.info('CTRL+C pressed; exiting.'); - process.exit(0); -}); diff --git a/plugins/backstage-plugin-backend/src/service/standaloneServer.ts b/plugins/backstage-plugin-backend/src/service/standaloneServer.ts deleted file mode 100644 index 019f167..0000000 --- a/plugins/backstage-plugin-backend/src/service/standaloneServer.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - createServiceBuilder, - DatabaseManager, - HostDiscovery, - loadBackendConfig, -} from '@backstage/backend-common'; -import { ConfigReader } from '@backstage/config'; -import { Server } from 'http'; -import { createRouter } from './router'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { PagerDutyBackendDatabase } from '../db'; -import { PagerDutyBackendStore } from '../db/PagerDutyBackendDatabase'; - -export interface ServerOptions { - port: number; - enableCors: boolean; - logger: LoggerService; -} - -export async function startStandaloneServer( - options: ServerOptions, -): Promise { - const logger = options.logger.child({ service: 'pagerduty-backend' }); - const config = await loadBackendConfig({ logger, argv: process.argv }); - - const manager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { client: 'better-sqlite3', connection: ':memory:' }, - }, - }), - ); - const database = manager.forPlugin('pagerduty'); - - const store: PagerDutyBackendStore = await PagerDutyBackendDatabase.create( - await database.getClient(), - { skipMigrations: true }, - ); - - const discovery = HostDiscovery.fromConfig(config); - - logger.debug('Starting application server...'); - const router = await createRouter({ - config, - logger, - store, - discovery, - }); - - let service = createServiceBuilder(module) - .setPort(options.port) - .addRouter('/pagerduty', router); - if (options.enableCors) { - service = service.enableCors({ origin: 'http://localhost:3000' }); - } - - return service.start().catch(err => { - logger.error(err); - process.exit(1); - }); -} - -module.hot?.accept(); From 3add435ecbc31dcff299a4c5461728e9b809c691 Mon Sep 17 00:00:00 2001 From: sandornagy517 <67263678+sandornagy517@users.noreply.github.com> Date: Mon, 18 Aug 2025 18:27:35 +0200 Subject: [PATCH 5/9] feat: Migrate PagerDutyCard to Backstage UI (#65) * feat: Migrate PagerDutyCard to backstage UI * chore: Add changeset * chore: Add changeset * chore: Get rid of wrong changeset --- .changeset/heavy-chefs-rhyme.md | 5 + .../ChangeEvents/ChangeEventListItem.tsx | 65 ++++---- .../ChangeEvents/ChangeEvents.test.tsx | 23 ++- .../components/ChangeEvents/ChangeEvents.tsx | 1 - .../components/Incident/IncidentListItem.tsx | 27 ++-- .../components/Incident/Incidents.test.tsx | 17 +- .../src/components/PagerDutyCard/index.tsx | 153 ++++++++---------- 7 files changed, 153 insertions(+), 138 deletions(-) create mode 100644 .changeset/heavy-chefs-rhyme.md diff --git a/.changeset/heavy-chefs-rhyme.md b/.changeset/heavy-chefs-rhyme.md new file mode 100644 index 0000000..fd5347a --- /dev/null +++ b/.changeset/heavy-chefs-rhyme.md @@ -0,0 +1,5 @@ +--- +'@pagerduty/backstage-plugin': patch +--- + +Migrate backstage plugin's EntityPagerDutyCard to Backstage UI diff --git a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx index 3f8de46..33c8be2 100644 --- a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx +++ b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx @@ -14,17 +14,14 @@ * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports -import { Link } from '@backstage/core-components'; import { ListItem, ListItemSecondaryAction, - Tooltip, ListItemText, makeStyles, - IconButton, Typography, } from '@material-ui/core'; +import { ButtonIcon, Tooltip, TooltipTrigger } from '@backstage/ui'; import { DateTime, Duration } from 'luxon'; import { PagerDutyChangeEvent } from '@pagerduty/backstage-plugin-common'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; @@ -42,16 +39,8 @@ const useStyles = makeStyles(theme => ({ listItemPrimary: { fontWeight: 'bold', }, - smallExternalLinkIconStyle: { - color: theme.palette.text.primary, - }, - smallExternalLinkWithoutMarginIconStyle: { - color: theme.palette.text.primary, - marginRight: '-20px', - }, smallIconStyle: { color: theme.palette.text.primary, - marginRight: '-20px', }, })); @@ -67,23 +56,29 @@ export const ChangeEventListItem = ({ changeEvent }: Props) => { .minus(Duration.fromMillis(duration)) .toRelative({ locale: 'en' }); + const handleExternalLinkClick = (url: string) => { + window.open(url, '_blank', 'noopener,noreferrer'); + }; + + const handlePagerDutyClick = () => { + if (changeEvent.html_url) { + window.open(changeEvent.html_url, '_blank', 'noopener,noreferrer'); + } + }; + let externalLinkElem: JSX.Element | undefined; - if (changeEvent.links.length > 0) { + if (changeEvent.links.length > 0 && changeEvent.links[0]?.href) { const text: string = changeEvent.links[0].text; + const linkHref = changeEvent.links[0].href; externalLinkElem = ( - - - - - + + } + variant="tertiary" + onClick={() => handleExternalLinkClick(linkHref)} + /> + {text} + ); } @@ -104,15 +99,15 @@ export const ChangeEventListItem = ({ changeEvent }: Props) => { {externalLinkElem} {changeEvent.html_url === undefined ? null : ( - - - - - + + } + variant="tertiary" + onClick={handlePagerDutyClick} + /> + View in PagerDuty + )} diff --git a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.test.tsx b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.test.tsx index 1175bc0..59c27c3 100644 --- a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.test.tsx +++ b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.test.tsx @@ -27,6 +27,21 @@ const mockPagerDutyApi = { const apis = TestApiRegistry.from([pagerDutyApiRef, mockPagerDutyApi]); describe('Incidents', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); it('Renders an empty state when there are no change events', async () => { mockPagerDutyApi.getChangeEventsByServiceId = jest .fn() @@ -98,7 +113,7 @@ describe('Incidents', () => { }, ] as PagerDutyChangeEvent[], })); - const { getByText, getAllByTitle, queryByTestId } = render( + const { getByText, getAllByLabelText, queryByTestId } = render( wrapInTestApp( @@ -110,7 +125,7 @@ describe('Incidents', () => { expect(getByText('sum of EVENT')).toBeInTheDocument(); // assert links, mailto and hrefs, date calculation - expect(getAllByTitle('View in PagerDuty').length).toEqual(2); + expect(getAllByLabelText('view-in-pd-button').length).toEqual(2); }); it('Does not render a pagerduty link when html_url is not present in response', async () => { @@ -145,7 +160,7 @@ describe('Incidents', () => { }, ] as PagerDutyChangeEvent[], })); - const { getByText, getAllByTitle, queryByTestId } = render( + const { getByText, getAllByLabelText, queryByTestId } = render( wrapInTestApp( @@ -157,7 +172,7 @@ describe('Incidents', () => { expect(getByText('sum of EVENT')).toBeInTheDocument(); // assert links, mailto and hrefs, date calculation - expect(getAllByTitle('View in PagerDuty').length).toEqual(1); + expect(getAllByLabelText('view-in-pd-button').length).toEqual(1); }); it('Handle errors', async () => { diff --git a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx index 5e776f5..1af32dd 100644 --- a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx +++ b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports import { useEffect } from 'react'; import { List } from '@material-ui/core'; import { ChangeEventListItem } from './ChangeEventListItem'; diff --git a/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx b/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx index c38e641..404c61e 100644 --- a/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx +++ b/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx @@ -17,13 +17,12 @@ import { ListItem, ListItemSecondaryAction, - Tooltip, ListItemText, makeStyles, - IconButton, Typography, Chip, } from '@material-ui/core'; +import { ButtonIcon, Tooltip, TooltipTrigger } from '@backstage/ui'; import { DateTime, Duration } from 'luxon'; import { PagerDutyIncident } from '@pagerduty/backstage-plugin-common'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; @@ -87,7 +86,6 @@ const useStyles = makeStyles(theme => ({ }, smallIconStyle: { color: theme.palette.text.primary, - marginRight: '-20px', }, })); @@ -104,6 +102,10 @@ export const IncidentListItem = ({ incident }: Props) => { .toRelative({ locale: 'en' }); const user = incident.assignments[0]?.assignee; + const handleIncidentClick = () => { + window.open(incident.html_url, '_blank', 'noopener,noreferrer'); + }; + return ( { } /> - - - - - + + } + variant="tertiary" + onClick={handleIncidentClick} + /> + View in PagerDuty + ); diff --git a/plugins/backstage-plugin/src/components/Incident/Incidents.test.tsx b/plugins/backstage-plugin/src/components/Incident/Incidents.test.tsx index a971922..d276ff4 100644 --- a/plugins/backstage-plugin/src/components/Incident/Incidents.test.tsx +++ b/plugins/backstage-plugin/src/components/Incident/Incidents.test.tsx @@ -27,6 +27,21 @@ const mockPagerDutyApi = { const apis = TestApiRegistry.from([pagerDutyApiRef, mockPagerDutyApi]); describe('Incidents', () => { + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + }); it('Renders an empty state when there are no incidents', async () => { mockPagerDutyApi.getIncidentsByServiceId = jest .fn() @@ -134,7 +149,7 @@ describe('Incidents', () => { expect(screen.getByTestId('chip-acknowledged')).toBeInTheDocument(); // assert links, mailto and hrefs, date calculation - expect(screen.getAllByTitle('View in PagerDuty').length).toEqual(2); + expect(screen.getAllByLabelText('view-in-pd-button').length).toEqual(2); }); it('Handle errors', async () => { diff --git a/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx b/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx index 107a3b7..2c3cad7 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports + import { ReactNode, useCallback, useState } from 'react'; import { - Card, CardHeader, - Divider, CardContent, - Grid, Typography, + Divider, } from '@material-ui/core'; import { Incidents } from '../Incident'; import { EscalationPolicy } from '../Escalation'; @@ -52,6 +50,7 @@ import { import { createStyles, makeStyles, useTheme } from '@material-ui/core/styles'; import { BackstageTheme } from '@backstage/theme'; import { PagerDutyCardServiceResponse } from '../../api/types'; +import { Card, Flex, Grid } from '@backstage/ui'; const useStyles = makeStyles(theme => createStyles({ @@ -72,33 +71,12 @@ const useStyles = makeStyles(theme => ? 'rgba(0, 0, 0, 0.54)' : 'rgba(255, 255, 255, 0.7)', }, - headerStyle: { - marginBottom: '0px', - fontSize: '0px', - }, - overviewHeaderContainerStyle: { - display: 'flex', - margin: '15px', - marginBottom: '20px', - }, - headerWithSubheaderContainerStyle: { - display: 'flex', - alignItems: 'center', - }, + subheaderTextStyle: { fontSize: '10px', - marginLeft: '5px', - }, - overviewCardsContainerStyle: { - display: 'flex', - margin: '15px', - marginTop: '-15px', - }, - incidentMetricsContainerStyle: { - display: 'flex', - height: '100%', - justifyContent: 'center', - columnSpan: 'all', + marginLeft: '-10px', + paddingTop: '3px', + color: theme.palette.text.secondary, }, }), ); @@ -195,9 +173,13 @@ export const PagerDutyCard = (props: PagerDutyCardProps) => { } return ( - + @@ -207,7 +189,7 @@ export const PagerDutyCard = (props: PagerDutyCardProps) => { } action={ !readOnly && props.integrationKey ? ( -
+ { handleRefresh={handleRefresh} /> -
+ ) : ( ) } /> - - + + STATUS - - - + + + INSIGHTS (last 30 days) - - - + + + STANDARDS - - - - + + + + + - - - - 0 - ? service?.metrics[0].total_interruptions - : undefined - } - label="interruptions" - color={theme.palette.textSubtle} - /> - - - 0 - ? service?.metrics[0].total_high_urgency_incidents - : undefined - } - label="high urgency" - color={theme.palette.warning.main} - /> - - - 0 - ? service?.metrics[0].total_incident_count - : undefined - } - label="incidents" - color={theme.palette.error.main} - /> - - - + + + + + 0 + ? service?.metrics[0].total_interruptions + : undefined + } + label="interruptions" + color={theme.palette.textSubtle} + /> + + + 0 + ? service?.metrics[0].total_high_urgency_incidents + : undefined + } + label="high urgency" + color={theme.palette.warning.main} + /> + + + 0 + ? service?.metrics[0].total_incident_count + : undefined + } + label="incidents" + color={theme.palette.error.main} + /> + + + + { : undefined } /> - - + + From 0af1d4c23831047db6b5b339a0617840cb3e5cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Wed, 27 Aug 2025 17:20:46 +0100 Subject: [PATCH 6/9] chore: fix `package.json` metadata (#68) * Fix package.json metadata * Update .changeset/sad-teeth-show.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .changeset/sad-teeth-show.md | 8 ++++++++ plugins/backstage-plugin-entity-processor/package.json | 4 ++-- plugins/backstage-plugin-scaffolder-actions/package.json | 4 ++-- plugins/backstage-plugin/package.json | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 .changeset/sad-teeth-show.md diff --git a/.changeset/sad-teeth-show.md b/.changeset/sad-teeth-show.md new file mode 100644 index 0000000..57ae413 --- /dev/null +++ b/.changeset/sad-teeth-show.md @@ -0,0 +1,8 @@ +--- +'@pagerduty/backstage-plugin-scaffolder-actions': patch +'@pagerduty/backstage-plugin-entity-processor': patch +'@pagerduty/backstage-plugin-backend': patch +'@pagerduty/backstage-plugin': patch +--- + +Fix package.json metadata to improve Portal relations diff --git a/plugins/backstage-plugin-entity-processor/package.json b/plugins/backstage-plugin-entity-processor/package.json index bc678e0..288dade 100644 --- a/plugins/backstage-plugin-entity-processor/package.json +++ b/plugins/backstage-plugin-entity-processor/package.json @@ -10,9 +10,9 @@ "types": "dist/index.d.ts" }, "backstage": { - "role": "backend-plugin-module", "pluginId": "catalog", - "pluginPackage": "pagerduty-entity-processor" + "role": "backend-plugin-module", + "pluginPackage": "@backstage/plugin-catalog-backend" }, "homepage": "https://pagerduty.github.io/backstage-plugin-docs/index.html", "repository": { diff --git a/plugins/backstage-plugin-scaffolder-actions/package.json b/plugins/backstage-plugin-scaffolder-actions/package.json index d80f582..8b186b6 100644 --- a/plugins/backstage-plugin-scaffolder-actions/package.json +++ b/plugins/backstage-plugin-scaffolder-actions/package.json @@ -10,9 +10,9 @@ "types": "dist/index.d.ts" }, "backstage": { + "pluginId": "scaffolder", "role": "backend-plugin-module", - "pluginPackage": "scaffolder", - "pluginId": "pagerduty-actions" + "pluginPackage": "@backstage/plugin-scaffolder-backend" }, "homepage": "https://pagerduty.github.io/backstage-plugin-docs/index.html", "repository": { diff --git a/plugins/backstage-plugin/package.json b/plugins/backstage-plugin/package.json index c64f881..221c618 100644 --- a/plugins/backstage-plugin/package.json +++ b/plugins/backstage-plugin/package.json @@ -11,8 +11,8 @@ "types": "dist/index.d.ts" }, "backstage": { - "role": "frontend-plugin", "pluginId": "pagerduty", + "role": "frontend-plugin", "pluginPackages": [ "@pagerduty/backstage-plugin", "@pagerduty/backstage-plugin-common", From 029b6c0df98e4aaad5b9fd4c8f491862042cfba6 Mon Sep 17 00:00:00 2001 From: sandornagy517 <67263678+sandornagy517@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:28:39 +0200 Subject: [PATCH 7/9] feat: Migrate PagerDutyPage to Backstage UI (#67) * feat: Migrate PagerDutyPage to Backstage UI * chore: Undo entities.yaml * fix: Fix margins and use className instead of style --- .changeset/quick-signs-switch.md | 5 + packages/app/src/App-Alpha.tsx | 4 +- packages/app/src/index.tsx | 4 +- plugins/backstage-plugin/dev/index.tsx | 9 +- .../ChangeEvents/ChangeEventListItem.tsx | 7 +- .../components/ChangeEvents/ChangeEvents.tsx | 18 +- .../EntityPagerDutyCard/index.test.tsx | 28 ++- .../components/EntityPagerDutyCard/index.tsx | 2 +- .../EntityPagerDutySmallCard/index.test.tsx | 28 ++- .../EntityPagerDutySmallCard/index.tsx | 6 +- .../Escalation/EscalationPolicy.tsx | 19 +- .../components/Escalation/EscalationUser.tsx | 15 +- .../components/Incident/IncidentListItem.tsx | 5 +- .../src/components/Incident/Incidents.tsx | 18 +- .../components/PagerDutyCard/index.test.tsx | 15 +- .../src/components/PagerDutyCard/index.tsx | 156 ++++++++--------- .../PagerDutyCardCommon/OpenServiceButton.tsx | 13 +- .../ServiceStandardsCard.tsx | 4 +- .../TriggerIncidentButton.tsx | 14 +- .../components/PagerDutyPage/MappingTable.tsx | 35 ++-- .../src/components/PagerDutyPage/index.tsx | 164 ++++++++---------- .../components/PagerDutySmallCard/index.tsx | 23 ++- 22 files changed, 305 insertions(+), 287 deletions(-) create mode 100644 .changeset/quick-signs-switch.md diff --git a/.changeset/quick-signs-switch.md b/.changeset/quick-signs-switch.md new file mode 100644 index 0000000..f23822b --- /dev/null +++ b/.changeset/quick-signs-switch.md @@ -0,0 +1,5 @@ +--- +'@pagerduty/backstage-plugin': patch +--- + +Migrated the PagerDutyCard component to backtage ui diff --git a/packages/app/src/App-Alpha.tsx b/packages/app/src/App-Alpha.tsx index 2a2175b..148da30 100644 --- a/packages/app/src/App-Alpha.tsx +++ b/packages/app/src/App-Alpha.tsx @@ -15,7 +15,7 @@ import PagerDutyPlugin from '@pagerduty/backstage-plugin/alpha'; // const OverriddenPagerDutyPlugin = PagerDutyPlugin.withOverrides({ // extensions: [ // PagerDutyPlugin.getExtension('entity-card:pagerduty/EntityPagerDutyCard').override({ -// factory: originalFactory => +// factory: originalFactory => // originalFactory({ // params: { // loader: async () => Promise.resolve() @@ -38,7 +38,7 @@ const app = createApp({ PagerDutyPlugin, // Uncomment the line below if you want to use the overridden version of PagerDuty plugin // OverriddenPagerDutyPlugin - ] + ], }); export default app.createRoot(); diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 07d1441..8271cf2 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -11,4 +11,6 @@ import '@backstage/ui/css/styles.css'; // Uncomment the lines below if you want to use the alpha version of the app import AppAlpha from './App-Alpha'; -ReactDOM.createRoot(document.getElementById('root')!).render(AppAlpha); +ReactDOM.createRoot(document.getElementById('root')!).render( +
{AppAlpha}
, +); diff --git a/plugins/backstage-plugin/dev/index.tsx b/plugins/backstage-plugin/dev/index.tsx index 541a19d..c26768a 100644 --- a/plugins/backstage-plugin/dev/index.tsx +++ b/plugins/backstage-plugin/dev/index.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports import { EntityProvider } from '@backstage/plugin-catalog-react'; import { createDevApp } from '@backstage/dev-utils'; import { @@ -40,7 +39,9 @@ createDevApp() title: 'PagerDuty', element: ( - +
+ +
), }) @@ -50,7 +51,9 @@ createDevApp() element: ( - +
+ +
), diff --git a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx index 33c8be2..3d41d7a 100644 --- a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx +++ b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEventListItem.tsx @@ -28,7 +28,7 @@ import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import LinkIcon from '@material-ui/icons/Link'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(() => ({ denseListIcon: { marginRight: 0, display: 'flex', @@ -39,9 +39,6 @@ const useStyles = makeStyles(theme => ({ listItemPrimary: { fontWeight: 'bold', }, - smallIconStyle: { - color: theme.palette.text.primary, - }, })); type Props = { @@ -73,7 +70,7 @@ export const ChangeEventListItem = ({ changeEvent }: Props) => { externalLinkElem = ( } + icon={} variant="tertiary" onClick={() => handleExternalLinkClick(linkHref)} /> diff --git a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx index 1af32dd..f11dc9c 100644 --- a/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx +++ b/plugins/backstage-plugin/src/components/ChangeEvents/ChangeEvents.tsx @@ -15,7 +15,7 @@ */ import { useEffect } from 'react'; -import { List } from '@material-ui/core'; +import { createStyles, List, makeStyles } from '@material-ui/core'; import { ChangeEventListItem } from './ChangeEventListItem'; import { ChangeEventEmptyState } from './ChangeEventEmptyState'; import { ChangeEventForbiddenState } from './ChangeEventForbiddenState'; @@ -24,6 +24,7 @@ import { pagerDutyApiRef } from '../../api'; import { useApi } from '@backstage/core-plugin-api'; import { Progress } from '@backstage/core-components'; import { Alert } from '@material-ui/lab'; +import { BackstageTheme } from '@backstage/theme'; type Props = { serviceId: string; @@ -31,8 +32,17 @@ type Props = { refreshEvents: boolean; }; +const useStyles = makeStyles(() => + createStyles({ + loadingStyles: { + height: '253px', + }, + }), +); + export const ChangeEvents = ({ serviceId, account, refreshEvents }: Props) => { const api = useApi(pagerDutyApiRef); + const { loadingStyles } = useStyles(); const [{ value: changeEvents, loading, error }, getChangeEvents] = useAsyncFn( async () => { @@ -61,7 +71,11 @@ export const ChangeEvents = ({ serviceId, account, refreshEvents }: Props) => { } if (loading) { - return ; + return ( +
+ +
+ ); } if (!changeEvents?.length) { diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx index 417f852..cd2ac57 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.test.tsx @@ -192,7 +192,9 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -304,7 +306,9 @@ describe('EntityPagerDutyCard', () => { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(queryByTestId('trigger-incident-button')).not.toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -413,7 +417,9 @@ describe('EntityPagerDutyCard', () => { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -444,7 +450,9 @@ describe('EntityPagerDutyCard', () => { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(queryByTestId('change-events')).not.toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -473,8 +481,12 @@ describe('EntityPagerDutyCard', () => { ); await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - expect(getByText('Change Events')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Change Events')).toBeInTheDocument(), + ); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); expect(queryByTestId('oncall-card')).not.toBeInTheDocument(); }); }); @@ -497,7 +509,9 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx index 8076a2b..ad13c53 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutyCard/index.tsx @@ -41,7 +41,7 @@ export const EntityPagerDutyCard = (props: EntityPagerDutyCardProps) => { if (isPluginApplicableToEntity(entity)) { const pagerDutyEntity = getPagerDutyEntity(entity); - + return ( { expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -303,7 +305,9 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(queryByTestId('trigger-incident-button')).not.toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -411,7 +415,9 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -441,7 +447,9 @@ describe('EntityPagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(queryByTestId('change-events')).not.toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -470,8 +478,12 @@ describe('EntityPagerDutyCard', () => { ); await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - expect(getByText('Change Events')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Change Events')).toBeInTheDocument(), + ); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); expect(queryByTestId('oncall-card')).not.toBeInTheDocument(); }); }); @@ -493,7 +505,9 @@ describe('EntityPagerDutyCard', () => { ); await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); diff --git a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx index 4f95506..f09bb36 100644 --- a/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx +++ b/plugins/backstage-plugin/src/components/EntityPagerDutySmallCard/index.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// eslint-disable-next-line @backstage/no-undeclared-imports + import { Entity } from '@backstage/catalog-model'; import { PAGERDUTY_INTEGRATION_KEY, PAGERDUTY_SERVICE_ID } from '../constants'; import { useEntity } from '@backstage/plugin-catalog-react'; @@ -41,9 +41,9 @@ export const EntityPagerDutySmallCard = ( const { readOnly, disableInsights, disableOnCall } = props; const { entity } = useEntity(); - if (isPluginApplicableToEntity(entity)) { + if (isPluginApplicableToEntity(entity)) { const pagerDutyEntity = getPagerDutyEntity(entity); - + return ( (() => - createStyles({ - listStyle: { - marginLeft: '-15px', - }, - }), -); export const EscalationPolicy = ({ policyId, @@ -52,7 +38,6 @@ export const EscalationPolicy = ({ account, }: Props) => { const api = useApi(pagerDutyApiRef); - const classes = useStyles(); const { value: users, @@ -87,7 +72,7 @@ export const EscalationPolicy = ({ } return ( - + {users!.map((user, index) => ( (theme => ({ +const useStyles = makeStyles(() => ({ listItemPrimary: { fontWeight: 'bold', }, @@ -35,20 +35,16 @@ const useStyles = makeStyles(theme => ({ fontWeight: 'normal', textDecoration: 'underline', marginTop: '-5px', + paddingLeft: '5px', }, buttonStyle: { - marginLeft: '-5px', fontSize: '15px', '&:hover': { textDecoration: 'underline', }, }, userTextButtonStyle: { - marginLeft: '-11px', - marginTop: '-10px', - marginBottom: '-10px', fontSize: '15px', - color: theme.palette.text.primary, '&:hover': { backgroundColor: 'transparent', textDecoration: 'underline', @@ -58,18 +54,13 @@ const useStyles = makeStyles(theme => ({ display: 'flex', alignItems: 'center', fontWeight: 'bold', - color: theme.palette.text.primary, }, iconStyle: { fontSize: '25px', marginLeft: '-4px', - color: theme.palette.text.primary, - }, - smallIconStyle: { - color: theme.palette.text.primary, }, avatarStyle: { - marginTop: '-20px', + marginTop: '-30px', }, })); diff --git a/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx b/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx index 404c61e..47a99bf 100644 --- a/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx +++ b/plugins/backstage-plugin/src/components/Incident/IncidentListItem.tsx @@ -84,9 +84,6 @@ const useStyles = makeStyles(theme => ({ display: 'flex', alignItems: 'baseline', }, - smallIconStyle: { - color: theme.palette.text.primary, - }, })); type Props = { @@ -151,7 +148,7 @@ export const IncidentListItem = ({ incident }: Props) => { } + icon={} variant="tertiary" onClick={handleIncidentClick} /> diff --git a/plugins/backstage-plugin/src/components/Incident/Incidents.tsx b/plugins/backstage-plugin/src/components/Incident/Incidents.tsx index 0abb245..c696d69 100644 --- a/plugins/backstage-plugin/src/components/Incident/Incidents.tsx +++ b/plugins/backstage-plugin/src/components/Incident/Incidents.tsx @@ -15,7 +15,7 @@ */ // eslint-disable-next-line @backstage/no-undeclared-imports import { useEffect } from 'react'; -import { List } from '@material-ui/core'; +import { createStyles, List, makeStyles } from '@material-ui/core'; import { IncidentListItem } from './IncidentListItem'; import { IncidentsEmptyState } from './IncidentEmptyState'; import useAsyncFn from 'react-use/lib/useAsyncFn'; @@ -25,6 +25,7 @@ import { Alert } from '@material-ui/lab'; import { useApi } from '@backstage/core-plugin-api'; import { Progress } from '@backstage/core-components'; import { IncidentForbiddenState } from './IncidentForbiddenState'; +import { BackstageTheme } from '@backstage/theme'; type Props = { serviceId: string; @@ -32,8 +33,17 @@ type Props = { refreshIncidents: boolean; }; +const useStyles = makeStyles(() => + createStyles({ + loadingStyles: { + height: '253px', + }, + }), +); + export const Incidents = ({ serviceId, account, refreshIncidents }: Props) => { const api = useApi(pagerDutyApiRef); + const { loadingStyles } = useStyles(); const [{ value: incidents, loading, error }, getIncidents] = useAsyncFn( async () => { @@ -62,7 +72,11 @@ export const Incidents = ({ serviceId, account, refreshIncidents }: Props) => { } if (loading) { - return ; + return ( +
+ +
+ ); } if (!incidents?.length) { diff --git a/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx b/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx index a131a5b..1992f8c 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCard/index.test.tsx @@ -111,8 +111,9 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); - + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); await waitFor(() => @@ -212,7 +213,9 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); @@ -326,7 +329,9 @@ describe('PagerDutyCard', () => { await waitFor(() => !queryByTestId('progress')); expect(getByText('Open service in PagerDuty')).toBeInTheDocument(); expect(getByText('Create new incident')).toBeInTheDocument(); - expect(getByText('Nice! No incidents found!')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Nice! No incidents found!')).toBeInTheDocument(), + ); await waitFor(() => !queryByTestId('escalation-progress')); await waitFor(() => @@ -357,7 +362,7 @@ describe('PagerDutyCard', () => { ); await waitFor(() => !queryByTestId('progress')); getByText('Open service in PagerDuty'); - getByText('Nice! No incidents found!'); + await waitFor(() => getByText('Nice! No incidents found!')); await waitFor(() => !queryByTestId('escalation-progress')); await waitFor(() => diff --git a/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx b/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx index 2c3cad7..25a90f3 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCard/index.tsx @@ -13,14 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { ReactNode, useCallback, useState } from 'react'; -import { - CardHeader, - CardContent, - Typography, - Divider, -} from '@material-ui/core'; +import { Typography, Divider } from '@material-ui/core'; import { Incidents } from '../Incident'; import { EscalationPolicy } from '../Escalation'; import useAsync from 'react-use/lib/useAsync'; @@ -32,12 +26,7 @@ import PDWhiteImage from '../../assets/PD-White.svg'; import { useApi } from '@backstage/core-plugin-api'; import { NotFoundError } from '@backstage/errors'; -import { - Progress, - TabbedCard, - CardTab, - InfoCard, -} from '@backstage/core-components'; +import { Progress, InfoCard } from '@backstage/core-components'; import { PagerDutyEntity } from '../../types'; import { ForbiddenError } from '../Errors/ForbiddenError'; import { @@ -50,7 +39,7 @@ import { import { createStyles, makeStyles, useTheme } from '@material-ui/core/styles'; import { BackstageTheme } from '@backstage/theme'; import { PagerDutyCardServiceResponse } from '../../api/types'; -import { Card, Flex, Grid } from '@backstage/ui'; +import { Card, Flex, Grid, Tab, TabList, TabPanel, Tabs } from '@backstage/ui'; const useStyles = makeStyles(theme => createStyles({ @@ -66,6 +55,7 @@ const useStyles = makeStyles(theme => fontSize: '14px', fontWeight: 500, marginTop: '10px', + marginLeft: '10px', color: theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.54)' @@ -76,7 +66,13 @@ const useStyles = makeStyles(theme => fontSize: '10px', marginLeft: '-10px', paddingTop: '3px', - color: theme.palette.text.secondary, + }, + logoContainerStyles: { + height: '100%', + }, + cardStyles: { + paddingLeft: '20px', + paddingRight: '20px', }, }), ); @@ -173,36 +169,39 @@ export const PagerDutyCard = (props: PagerDutyCardProps) => { } return ( - - - ) : ( - PagerDuty - ) - } - action={ - !readOnly && props.integrationKey ? ( - - + + + + + {theme.palette.type === 'dark' ? ( + PagerDuty + ) : ( + PagerDuty + )} + + + + + {!readOnly && props.integrationKey ? ( + + + + + ) : ( - - ) : ( - - ) - } - /> + )} + + + @@ -293,45 +292,44 @@ export const PagerDutyCard = (props: PagerDutyCardProps) => { - - - - + + Incidents + {disableChangeEvents !== true && Change Events} + + + + + {disableChangeEvents !== true && ( + + - - {disableChangeEvents !== true ? ( - - - - ) : ( - <> - )} - - {disableOnCall !== true ? ( - <> - - ON CALL - - - - ) : ( - <> + )} - + + {disableOnCall !== true && ( + <> + + ON CALL + + + + )} ); }; diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx index 0b0354e..0497a6a 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/OpenServiceButton.tsx @@ -30,9 +30,8 @@ export function OpenServiceButton({ serviceUrl, compact, }: OpenServiceButtonProps) { - const useStyles = makeStyles(theme => ({ + const useStyles = makeStyles(() => ({ containerStyle: { - color: theme.palette.text.primary, fontSize: compact !== true ? '12px' : '10px', width: compact !== true ? '85px' : '70px', display: 'flex', @@ -40,12 +39,12 @@ export function OpenServiceButton({ alignItems: 'center', textAlign: 'center', }, - iconStyle: { - color: theme.palette.text.primary, + textStyle: { + fontSize: '12px', }, })); - const { containerStyle, iconStyle } = useStyles(); + const { containerStyle, textStyle } = useStyles(); function navigateToService() { window.open(serviceUrl, '_blank'); @@ -58,10 +57,10 @@ export function OpenServiceButton({ size="medium" onClick={navigateToService} variant="tertiary" - icon={} + icon={} /> - Open service in PagerDuty + Open service in PagerDuty
); } diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx index d0951e2..f732efb 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/ServiceStandardsCard.tsx @@ -50,8 +50,8 @@ function ServiceStandardsCard({ total, completed, standards, compact }: Props) { fontSize: compact !== true ? '14px' : '12px', fontWeight: 'bold', alignSelf: 'center', - marginLeft: '-20px', - marginBottom: '-20px', + marginLeft: '-17px', + marginBottom: '-26px', }, tooltipIcon: { marginRight: '5px', diff --git a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx index a62f434..5881666 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyCardCommon/TriggerIncidentButton.tsx @@ -38,26 +38,22 @@ export function TriggerIncidentButton({ compact, handleRefresh, }: TriggerIncidentButtonProps) { - const useStyles = makeStyles(theme => ({ + const useStyles = makeStyles(() => ({ containerStyle: { fontSize: compact !== true ? '12px' : '10px', width: compact !== true ? '80px' : '60px', display: 'flex', flexDirection: 'column', alignItems: 'center', - color: theme.palette.text.primary, }, - - iconStyle: { - color: theme.palette.text.primary, - }, - textStyle: { textAlign: 'center', + fontSize: '12px', + minWidth: '30px', }, })); - const { containerStyle, textStyle, iconStyle } = useStyles(); + const { containerStyle, textStyle } = useStyles(); const [dialogShown, setDialogShown] = useState(false); const showDialog = useCallback(() => { @@ -78,7 +74,7 @@ export function TriggerIncidentButton({ aria-label="create-incident" onClick={showDialog} isDisabled={disabled} - icon={} + icon={} /> Create new incident diff --git a/plugins/backstage-plugin/src/components/PagerDutyPage/MappingTable.tsx b/plugins/backstage-plugin/src/components/PagerDutyPage/MappingTable.tsx index c43f7d4..721d0f5 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyPage/MappingTable.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyPage/MappingTable.tsx @@ -12,10 +12,9 @@ import { DialogActions, DialogContent, DialogTitle, - IconButton, - Tooltip, Typography, } from '@material-ui/core'; +import { Flex, Tooltip, TooltipTrigger, ButtonIcon } from '@backstage/ui'; import { QueryClient, QueryClientProvider, @@ -281,25 +280,29 @@ export const MappingTable = ({ ), renderRowActions: ({ row, table }) => ( - - - + + { getEntityOptions(); table.setEditingRow(row); }} - > - - - - - } + /> + Edit + + + openInBrowser(row.getValue('serviceUrl'))} - > - - - - + icon={} + /> + Open in PagerDuty + + ), state: { isLoading: mappings.length === 0 || catalogEntities.length === 0, diff --git a/plugins/backstage-plugin/src/components/PagerDutyPage/index.tsx b/plugins/backstage-plugin/src/components/PagerDutyPage/index.tsx index 10745fc..af36e90 100644 --- a/plugins/backstage-plugin/src/components/PagerDutyPage/index.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutyPage/index.tsx @@ -1,12 +1,6 @@ import { useEffect, useState } from 'react'; -import { - Card, - FormControlLabel, - Grid, - Radio, - RadioGroup, - Typography, -} from '@material-ui/core'; +import { createStyles, makeStyles, Typography } from '@material-ui/core'; +import { Card, Grid, RadioGroup, Radio } from '@backstage/ui'; import { Header, Page, @@ -17,12 +11,36 @@ import { ServiceMappingComponent } from './ServiceMappingComponent'; import { useApi } from '@backstage/core-plugin-api'; import { pagerDutyApiRef } from '../../api'; import { NotFoundError } from '@backstage/errors'; +import { BackstageTheme } from '@backstage/theme'; + +enum StoreSettings { + backstage = 'backstage', + pagerduty = 'pagerduty', + both = 'both', + disabled = 'disabled', +} const SERVICE_DEPENDENCY_SYNC_STRATEGY = 'settings::service-dependency-sync-strategy'; +const useStyles = makeStyles(() => + createStyles({ + cardStyles: { + padding: '15px', + marginTop: '16px', + }, + textContainerStyles: { + marginTop: '16px', + }, + linkStyles: { + color: 'cadetblue', + }, + }), +); + /** @public */ export const PagerDutyPage = () => { + const { cardStyles, textContainerStyles, linkStyles } = useStyles(); const pagerDutyApi = useApi(pagerDutyApiRef); const [ selectedServiceDependencyStrategy, @@ -49,11 +67,8 @@ export const PagerDutyPage = () => { fetchSetting(); }, [pagerDutyApi]); - const handleChange = (event: React.ChangeEvent) => { - const value = getSelectedValue((event.target as HTMLInputElement).value); - + const handleChange = (value: StoreSettings) => { setSelectedServiceDependencyStrategy(value); - pagerDutyApi.storeSettings([ { id: SERVICE_DEPENDENCY_SYNC_STRATEGY, @@ -62,108 +77,69 @@ export const PagerDutyPage = () => { ]); }; - function getSelectedValue( - value: string, - ): 'backstage' | 'pagerduty' | 'both' | 'disabled' { - switch (value) { - case 'backstage': - return 'backstage'; - case 'pagerduty': - return 'pagerduty'; - case 'both': - return 'both'; - default: - return 'disabled'; - } - } - return (
- - - {/* Service to Entity mapping */} - + + + Easily map your existing PagerDuty services to entities in Backstage without the need to add anotations to all your projects. - + Warning: Only 1:1 mapping is allowed at this time. - - + + - - + + - - - Plugin configuration - - Configure your PagerDuty plugin configuration here - - + <> + Plugin configuration + + Configure your PagerDuty plugin configuration here + + - <> - - Service dependency synchronization strategy - - - Select the main source of truth for your service - dependencies - - - } - label="Backstage" - /> - } - label="PagerDuty" - /> - } - label="Both" - /> - } - label="Disabled" - /> - - - -
-
- - Warning: Changing this setting will affect how your - service dependencies are synchronized and may cause data loss. - Check the{' '} - - {' '} - documentation{' '} - {' '} - for more information. + + Service dependency synchronization strategy + handleChange(value as StoreSettings)} + > + Backstage + PagerDuty + Both + Disabled + + +
+ + Warning: Changing this setting will affect how your + service dependencies are synchronized and may cause data + loss. Check the{' '} + + documentation + {' '} + for more information. + +
-
+
diff --git a/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx b/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx index a998dd5..57d6289 100644 --- a/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx +++ b/plugins/backstage-plugin/src/components/PagerDutySmallCard/index.tsx @@ -62,6 +62,16 @@ const useStyles = makeStyles(theme => paddingLeft: '5px', paddingTop: '3px', }, + accordionStyle: { + background: 'transparent', + }, + gridRootStyle: { + width: '100%', + }, + cardStyles: { + paddingLeft: '10px', + paddingRight: '10px', + }, }), ); @@ -152,12 +162,7 @@ export const PagerDutySmallCard = (props: PagerDutyCardProps) => { } return ( - + { {disableInsights !== true ? ( - + } aria-controls="panel1a-content" @@ -248,7 +253,7 @@ export const PagerDutySmallCard = (props: PagerDutyCardProps) => { gap="1" pl="1" pr="1" - style={{ width: '100%' }} + className={classes.gridRootStyle} > { )} {disableOnCall !== true ? ( - + } aria-controls="panel1a-content" From 8ec5d2149b5a1e3ea0cfbe0e1381e59c156bbcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Wed, 1 Oct 2025 14:01:07 +0100 Subject: [PATCH 8/9] Implement NFS best practices (#74) * implement nfs best practices * apply pr recommendations * move backstage/ui back to dependencies * apply pr suggestions --- .changeset/slimy-mangos-write.md | 9 + .yarn/plugins/@yarnpkg/plugin-backstage.cjs | 9 + .yarnrc.yml | 16 +- packages/app/package.json | 30 +- packages/app/src/App-Alpha.tsx | 22 +- plugins/backstage-plugin/dev/app-config.yaml | 18 + plugins/backstage-plugin/dev/index.tsx | 82 +- .../backstage-plugin/dev/mockCatalogApi.ts | 40 + plugins/backstage-plugin/package.json | 40 +- plugins/backstage-plugin/src/alpha.tsx | 102 --- plugins/backstage-plugin/src/alpha/api.ts | 26 + .../src/alpha/entity-cards.tsx | 67 ++ plugins/backstage-plugin/src/alpha/index.ts | 1 + .../backstage-plugin/src/alpha/nav-items.tsx | 14 + plugins/backstage-plugin/src/alpha/pages.tsx | 13 + plugins/backstage-plugin/src/alpha/plugin.ts | 40 + plugins/backstage-plugin/src/plugin.ts | 5 +- .../{dev/mockEntity.ts => src/routes.ts} | 22 +- yarn.lock | 837 ++++++++++++++---- 19 files changed, 987 insertions(+), 406 deletions(-) create mode 100644 .changeset/slimy-mangos-write.md create mode 100644 .yarn/plugins/@yarnpkg/plugin-backstage.cjs create mode 100644 plugins/backstage-plugin/dev/app-config.yaml create mode 100644 plugins/backstage-plugin/dev/mockCatalogApi.ts delete mode 100644 plugins/backstage-plugin/src/alpha.tsx create mode 100644 plugins/backstage-plugin/src/alpha/api.ts create mode 100644 plugins/backstage-plugin/src/alpha/entity-cards.tsx create mode 100644 plugins/backstage-plugin/src/alpha/index.ts create mode 100644 plugins/backstage-plugin/src/alpha/nav-items.tsx create mode 100644 plugins/backstage-plugin/src/alpha/pages.tsx create mode 100644 plugins/backstage-plugin/src/alpha/plugin.ts rename plugins/backstage-plugin/{dev/mockEntity.ts => src/routes.ts} (55%) diff --git a/.changeset/slimy-mangos-write.md b/.changeset/slimy-mangos-write.md new file mode 100644 index 0000000..e687d0d --- /dev/null +++ b/.changeset/slimy-mangos-write.md @@ -0,0 +1,9 @@ +--- +'@pagerduty/backstage-plugin': minor +--- + +Best practice implementation of the new frontend system + +- Better separation of concerns. +- New use of the API for new frontend system. +- Made the @backstage/ui dependency a peer-dependency that needs to be imported and used by Backstage users. diff --git a/.yarn/plugins/@yarnpkg/plugin-backstage.cjs b/.yarn/plugins/@yarnpkg/plugin-backstage.cjs new file mode 100644 index 0000000..bd5302e --- /dev/null +++ b/.yarn/plugins/@yarnpkg/plugin-backstage.cjs @@ -0,0 +1,9 @@ +/* eslint-disable */ +//prettier-ignore +module.exports = { +name: "@yarnpkg/plugin-backstage", +factory: function (require) { +"use strict";var plugin=(()=>{var F=Object.create;var v=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var G=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var p=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var J=(e,t)=>{for(var r in t)v(e,r,{get:t[r],enumerable:!0})},S=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of N(t))!I.call(e,o)&&o!==r&&v(e,o,{get:()=>t[o],enumerable:!(n=_(t,o))||n.enumerable});return e};var L=(e,t,r)=>(r=e!=null?F(G(e)):{},S(t||!e||!e.__esModule?v(r,"default",{value:e,enumerable:!0}):r,e)),z=e=>S(v({},"__esModule",{value:!0}),e);var ae={};J(ae,{default:()=>se});var P=p("@yarnpkg/core");var w=p("@yarnpkg/core");var W=L(p("assert")),j=p("semver"),y=p("@yarnpkg/fslib");var u=L(p("fs")),g=p("path");function A(e,t){let r=e;for(let n=0;n<1e3;n++){let o=(0,g.resolve)(r,"package.json");if(u.default.existsSync(o)&&t(o))return r;let i=(0,g.dirname)(r);if(i===r)return;r=i}throw new Error(`Iteration limit reached when searching for root package.json at ${e}`)}function K(e){let t=A(e,()=>!0);if(!t)throw new Error(`No package.json found while searching for package root of ${e}`);return t}function Y(e){if(!u.default.existsSync((0,g.resolve)(e,"src")))throw new Error("Tried to access monorepo package root dir outside of Backstage repository");return(0,g.resolve)(e,"../..")}function b(e){let t=K(e),r=u.default.realpathSync(process.cwd()).replace(/^[a-z]:/,s=>s.toLocaleUpperCase("en-US")),n="",o=()=>(n||(n=Y(t)),n),a="",i=()=>(a||(a=A(r,s=>{try{let m=u.default.readFileSync(s,"utf8");return!!JSON.parse(m).workspaces}catch(m){throw new Error(`Failed to parse package.json file while searching for root, ${m}`)}})??r),a);return{ownDir:t,get ownRoot(){return o()},targetDir:r,get targetRoot(){return i()},resolveOwn:(...s)=>(0,g.resolve)(t,...s),resolveOwnRoot:(...s)=>(0,g.resolve)(o(),...s),resolveTarget:(...s)=>(0,g.resolve)(r,...s),resolveTargetRoot:(...s)=>(0,g.resolve)(i(),...s)}}var x="backstage.json";var V=e=>{let t=!1,r;return()=>(t||(r=e(),t=!0),r)};var h=p("@yarnpkg/fslib");var C=()=>h.npath.toPortablePath(b(h.npath.fromPortablePath(h.ppath.cwd())).targetRoot);var k=V(()=>{let e=y.ppath.join(C(),x),t=null;try{t=(0,j.valid)(y.xfs.readJsonSync(e).version),(0,W.default)(t!==null)}catch{throw new Error("Valid version string not found in backstage.json")}return t});var d=p("@yarnpkg/core");var q="https://versions.backstage.io",Q="https://raw.githubusercontent.com/backstage/versions/main";function X(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>{t.aborted||r()},e);t.addEventListener("abort",()=>{clearTimeout(o),n(new Error("Aborted"))})})}async function Z(e,t,r){let n=new AbortController,o=new AbortController,a=e(n.signal).then(s=>(o.abort(),s)),i=X(r,o.signal).then(()=>t(o.signal)).then(s=>(n.abort(),s));return Promise.any([a,i]).catch(()=>a)}async function D(e){let t=encodeURIComponent(e.version),r=e.fetch??fetch,n=e.versionsBaseUrl??q,o=e.gitHubRawBaseUrl??Q,a=await Z(i=>r(`${n}/v1/releases/${t}/manifest.json`,{signal:i}),i=>r(`${o}/v1/releases/${t}/manifest.json`,{signal:i}),500);if(a.status===404)throw new Error(`No release found for ${e.version} version`);if(a.status!==200)throw new Error(`Unexpected response status ${a.status} when fetching release from ${a.url}.`);return a.json()}var c="backstage:";var f=async(e,t)=>{let r=d.structUtils.stringifyIdent(e),n=d.structUtils.parseRange(e.range);if(n.protocol!==c)throw new Error(`Unsupported version protocol in version range "${e.range}" for package ${r}`);if(n.selector!=="^")throw new Error(`Unexpected version selector "${n.selector}" for package ${r}`);let o=k(),i=(await D({version:o,fetch:async s=>{let m=await d.httpUtils.get(s,{configuration:t,jsonResponse:!0});return{status:200,url:s,json:()=>m}}})).packages.find(s=>s.name===r);if(!i)throw new Error(`Package ${r} not found in manifest for Backstage v${o}. This means the specified package is not included in this Backstage release. This may imply the package has been replaced with an alternative - please review the documentation for the package. If you need to continue using this package, it will be necessary to switch to manually managing its version.`);return i.version};var ee=e=>w.structUtils.parseRange(e).protocol===c,te=(e,t,r)=>e!=="dependencies"?e:r.manifest.ensureDependencyMeta(w.structUtils.makeDescriptor(t,"unknown")).optional?"optionalDependencies":e,B=async(e,t)=>{for(let r of["dependencies","devDependencies"]){let n=Array.from(e.manifest.getForScope(r).values()).filter(o=>o.range.startsWith(c));for(let o of n){let a=w.structUtils.stringifyIdent(o);if(w.structUtils.parseRange(o.range).selector!=="^")throw new Error(`Unexpected version range "${o.range}" for dependency on "${a}"`);let s=te(r,o,e);t[s][a]=`^${await f(o,e.project.configuration)}`}}if(["dependencies","devDependencies","optionalDependencies"].some(r=>Object.values(t[r]??{}).some(ee)))throw new Error(`Failed to replace all "backstage:" ranges in manifest for ${t.name}`)};var O=p("@yarnpkg/core");var $=async(e,t)=>{let r=O.structUtils.parseRange(e.range);if(r.protocol!==c)return e;if(r.selector!=="^")throw new Error(`Invalid backstage: version range found: ${e.range}`);return O.structUtils.bindDescriptor(e,{backstage:k(),npm:await f(e,t.configuration)})};var H=p("@yarnpkg/core");var U=async(e,t,r,n)=>{let o=H.structUtils.parseRange(r.range);if(r.scope==="backstage"&&o.protocol!==c){let a=r.range;try{r.range=`${c}^`,await f(r,e.project.configuration),console.info(`Setting ${r.scope}/${r.name} to ${c}^`)}catch{r.range=a}}};var M=p("@yarnpkg/core");var E=async(e,t,r,n)=>{let o=M.structUtils.parseRange(n.range);n.scope==="backstage"&&o.protocol!==c&&console.warn(`${n.name} should be set to "${c}^" instead of "${n.range}". Make sure this change is intentional and not a mistake.`)};var l=p("@yarnpkg/core"),T=p("@yarnpkg/plugin-npm");var R=class e{static protocol=c;supportsDescriptor=t=>t.range.startsWith(e.protocol);async getCandidates(t,r,n){let o=l.structUtils.parseRange(t.range).params?.npm;if(!o||Array.isArray(o))throw new Error(`Missing npm parameter on backstage: range "${t.range}"`);return new T.NpmSemverResolver().getCandidates(l.structUtils.makeDescriptor(t,`npm:^${o}`),r,n)}getResolutionDependencies(t){let r=l.structUtils.parseRange(t.range).params?.npm;if(!r)throw new Error(`Missing npm parameter on backstage: range "${t.range}".`);return{[l.structUtils.stringifyIdent(t)]:l.structUtils.makeDescriptor(t,`npm:^${r}`)}}async getSatisfying(t,r,n,o){let a=t,i=l.structUtils.parseRange(a.range);if(i.protocol===c){let s=i.params?.npm;a=l.structUtils.makeDescriptor(t,`npm:^${s}`)}return new T.NpmSemverResolver().getSatisfying(a,r,n,o)}bindDescriptor=t=>t;supportsLocator=()=>!1;shouldPersistResolution=()=>{throw new Error("Unreachable: BackstageNpmResolver should never persist resolution as it uses npm: protocol")};resolve=async()=>{throw new Error("Unreachable: BackstageNpmResolver should never resolve as it uses npm: protocol")}};var re="\x1B[31;1m",oe="\x1B[0m";P.semverUtils.satisfiesWithPrereleases(P.YarnVersion,"^4.1.1")||(console.error(),console.error(`${re}Unsupported yarn version${oe}: The Backstage yarn plugin only works with yarn ^4.1.1. Please upgrade yarn, or remove this plugin with "yarn plugin remove @yarnpkg/plugin-backstage".`),console.error());var ne={hooks:{afterWorkspaceDependencyAddition:U,afterWorkspaceDependencyReplacement:E,reduceDependency:$,beforeWorkspacePacking:B},resolvers:[R]},se=ne;return z(ae);})(); +return plugin; +} +}; \ No newline at end of file diff --git a/.yarnrc.yml b/.yarnrc.yml index 1fbc713..ba553d1 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,11 +1,18 @@ nodeLinker: node-modules + enableGlobalCache: true + nmHoistingLimits: none + nmMode: hardlinks-local + pnpFallbackMode: none + supportedArchitectures: - os: [current] - cpu: [current] + os: + - current + cpu: + - current npmRegistryServer: 'https://registry.npmjs.org/' @@ -14,4 +21,9 @@ npmScopes: npmAlwaysAuth: true npmAuthToken: NPM_TOKEN +plugins: + - checksum: 8af7b3f2d7d19cacc7a3712f871efcb6208ba283a1f532260b0cba80c2cb66ed772b207b5ba41b8c5d64dd8d5e0c0e15bbb445bd14afac491712965211ba027c + path: .yarn/plugins/@yarnpkg/plugin-backstage.cjs + spec: "https://versions.backstage.io/v1/releases/1.42.5/yarn-plugin" + yarnPath: .yarn/releases/yarn-4.4.1.cjs diff --git a/packages/app/package.json b/packages/app/package.json index 2b4c1f1..26b6e67 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -14,21 +14,21 @@ "lint": "backstage-cli package lint" }, "dependencies": { - "@backstage/app-defaults": "^1.6.3", + "@backstage/app-defaults": "^1.7.0", "@backstage/canon": "^0.5.0", - "@backstage/catalog-model": "^1.7.4", - "@backstage/cli": "^0.33.0", - "@backstage/core-app-api": "^1.17.1", - "@backstage/core-components": "^0.17.3", - "@backstage/core-plugin-api": "^1.10.8", - "@backstage/frontend-defaults": "^0.2.4", - "@backstage/integration-react": "^1.2.8", - "@backstage/plugin-api-docs": "^0.12.9", - "@backstage/plugin-catalog": "^1.31.1", - "@backstage/plugin-catalog-common": "^1.1.4", - "@backstage/plugin-catalog-graph": "^0.4.20", - "@backstage/plugin-catalog-import": "^0.13.3", - "@backstage/plugin-catalog-react": "^1.19.0", + "@backstage/catalog-model": "^1.7.5", + "@backstage/cli": "^0.34.3", + "@backstage/core-app-api": "^1.19.0", + "@backstage/core-components": "^0.18.0", + "@backstage/core-plugin-api": "^1.11.0", + "@backstage/frontend-defaults": "^0.3.1", + "@backstage/integration-react": "^1.2.10", + "@backstage/plugin-api-docs": "^0.12.11", + "@backstage/plugin-catalog": "^1.31.3", + "@backstage/plugin-catalog-common": "^1.1.5", + "@backstage/plugin-catalog-graph": "^0.5.0", + "@backstage/plugin-catalog-import": "^0.13.5", + "@backstage/plugin-catalog-react": "^1.21.0", "@backstage/plugin-kubernetes": "^0.12.8", "@backstage/plugin-org": "^0.6.41", "@backstage/plugin-permission-react": "^0.4.35", @@ -40,7 +40,7 @@ "@backstage/plugin-techdocs-react": "^1.3.0", "@backstage/plugin-user-settings": "^0.8.23", "@backstage/theme": "^0.6.6", - "@backstage/ui": "^0.6.1", + "@backstage/ui": "^0.7.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@pagerduty/backstage-plugin": "workspace:^", diff --git a/packages/app/src/App-Alpha.tsx b/packages/app/src/App-Alpha.tsx index 148da30..66a4188 100644 --- a/packages/app/src/App-Alpha.tsx +++ b/packages/app/src/App-Alpha.tsx @@ -7,23 +7,7 @@ import OrgPlugin from '@backstage/plugin-org/alpha'; import SearchPlugin from '@backstage/plugin-search/alpha'; import TechDocsPlugin from '@backstage/plugin-techdocs/alpha'; import { createApp } from '@backstage/frontend-defaults'; -import PagerDutyPlugin from '@pagerduty/backstage-plugin/alpha'; - -// Uncomment the line below if you want to use the overridden version of PagerDuty plugin -// import { EntityPagerDutySmallCard } from '@pagerduty/backstage-plugin'; - -// const OverriddenPagerDutyPlugin = PagerDutyPlugin.withOverrides({ -// extensions: [ -// PagerDutyPlugin.getExtension('entity-card:pagerduty/EntityPagerDutyCard').override({ -// factory: originalFactory => -// originalFactory({ -// params: { -// loader: async () => Promise.resolve() -// } -// }) -// }) -// ] -// }) +import pagerDutyPlugin from '@pagerduty/backstage-plugin/alpha'; const app = createApp({ features: [ @@ -35,9 +19,7 @@ const app = createApp({ SearchPlugin, OrgPlugin, TechDocsPlugin, - PagerDutyPlugin, - // Uncomment the line below if you want to use the overridden version of PagerDuty plugin - // OverriddenPagerDutyPlugin + pagerDutyPlugin, ], }); diff --git a/plugins/backstage-plugin/dev/app-config.yaml b/plugins/backstage-plugin/dev/app-config.yaml new file mode 100644 index 0000000..6b40b25 --- /dev/null +++ b/plugins/backstage-plugin/dev/app-config.yaml @@ -0,0 +1,18 @@ +app: + title: Backstage Example App + baseUrl: http://localhost:3000 + extensions: + # Redirect from the root to the PagerDuty page + - 'page:pagerduty': + config: + path: '/' + # Enable the small PagerDuty entity card + - 'entity-card:pagerduty/small': true + # Hide these entity cards from the catalog + - 'entity-card:catalog/has-subcomponents': false + - 'entity-card:catalog/depends-on-components': false + - 'entity-card:catalog/depends-on-resources': false +backend: + baseUrl: http://localhost:7007 + listen: + port: 7007 diff --git a/plugins/backstage-plugin/dev/index.tsx b/plugins/backstage-plugin/dev/index.tsx index c26768a..13e0773 100644 --- a/plugins/backstage-plugin/dev/index.tsx +++ b/plugins/backstage-plugin/dev/index.tsx @@ -14,48 +14,48 @@ * limitations under the License. */ -import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { createDevApp } from '@backstage/dev-utils'; -import { - pagerDutyPlugin, - EntityPagerDutyCard, - EntityPagerDutySmallCard, -} from '../src/plugin'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { pagerDutyApiRef } from '../src/api'; import { mockPagerDutyApi } from './mockPagerDutyApi'; -import { mockEntity } from './mockEntity'; -import { Grid } from '@material-ui/core'; import '@backstage/ui/css/styles.css'; -createDevApp() - .registerApi({ - api: pagerDutyApiRef, - deps: {}, - factory: () => mockPagerDutyApi, - }) - .registerPlugin(pagerDutyPlugin) - .addPage({ - path: '/pagerduty', - title: 'PagerDuty', - element: ( - -
- -
-
- ), - }) - .addPage({ - path: '/pagerduty-small', - title: 'PagerDuty Small Card', - element: ( - - -
- -
-
-
- ), - }) - .render(); +import ReactDOM from 'react-dom/client'; +import { createApp } from '@backstage/frontend-defaults'; +import pagerDutyPlugin from '../src/alpha'; +import catalogPlugin from '@backstage/plugin-catalog/alpha'; +import { mockCatalogApi } from './mockCatalogApi'; + +const catalogPluginOverrides = catalogPlugin.withOverrides({ + extensions: [ + catalogPlugin.getExtension('api:catalog').override({ + params: defineParams => + defineParams({ + api: catalogApiRef, + deps: {}, + factory: () => mockCatalogApi + }) + }) + ] +}) + +const pagerDutyPluginOverrides = pagerDutyPlugin.withOverrides({ + extensions: [ + pagerDutyPlugin.getExtension('api:pagerduty').override({ + params: defineParams => + defineParams({ + api: pagerDutyApiRef, + deps: {}, + factory: () => mockPagerDutyApi, + }) + }) + ] +}) + + +const app = createApp({ + features: [catalogPluginOverrides, pagerDutyPluginOverrides], +}) + +const root = app.createRoot(); + +ReactDOM.createRoot(document.getElementById('root')!).render(root); diff --git a/plugins/backstage-plugin/dev/mockCatalogApi.ts b/plugins/backstage-plugin/dev/mockCatalogApi.ts new file mode 100644 index 0000000..41e68d5 --- /dev/null +++ b/plugins/backstage-plugin/dev/mockCatalogApi.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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 { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; + +export const mockCatalogApi = catalogApiMock({ + entities: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + annotations: { + 'github.com/project-slug': 'backstage/backstage', + 'pagerduty.com/service-id': 'foo', + 'pagerduty.com/integration-key': 'foo', + }, + }, + spec: { + lifecycle: 'production', + type: 'website', + owner: 'user:guest', + }, + }, + ], +}); diff --git a/plugins/backstage-plugin/package.json b/plugins/backstage-plugin/package.json index 0dcd5cb..6b4571a 100644 --- a/plugins/backstage-plugin/package.json +++ b/plugins/backstage-plugin/package.json @@ -6,9 +6,7 @@ "types": "dist/index.d.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "backstage": { "pluginId": "pagerduty", @@ -30,9 +28,10 @@ "plugin", "pagerduty" ], + "sideEffects": false, "scripts": { "build": "backstage-cli package build && copyfiles -u 1 src/assets/*.svg ./", - "start": "backstage-cli package start", + "start": "backstage-cli package start --config ./dev/app-config.yaml", "lint": "backstage-cli package lint", "test": "backstage-cli package test", "prepare": "husky install", @@ -41,15 +40,16 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/catalog-client": "^1.10.2", - "@backstage/catalog-model": "^1.5.0", - "@backstage/core-compat-api": "^0.4.4", - "@backstage/core-components": "^0.14.9", - "@backstage/core-plugin-api": "^1.9.3", - "@backstage/errors": "^1.2.4", - "@backstage/frontend-plugin-api": "^0.10.4", - "@backstage/plugin-catalog-react": "^1.19.1", - "@backstage/plugin-home-react": "^0.1.15", + "@backstage/catalog-client": "^1.12.0", + "@backstage/catalog-model": "^1.7.5", + "@backstage/core-compat-api": "^0.5.2", + "@backstage/core-components": "^0.18.0", + "@backstage/core-plugin-api": "^1.11.0", + "@backstage/errors": "^1.2.7", + "@backstage/frontend-plugin-api": "^0.12.0", + "@backstage/plugin-catalog": "^1.31.3", + "@backstage/plugin-catalog-react": "^1.21.0", + "@backstage/plugin-home-react": "^0.1.30", "@backstage/theme": "^0.5.6", "@backstage/ui": "^0.6.1", "@emotion/react": "^11.11.4", @@ -75,10 +75,11 @@ "react-router-dom": "^6.3.0" }, "devDependencies": { - "@backstage/cli": "^0.33.0", - "@backstage/core-app-api": "^1.14.0", - "@backstage/dev-utils": "^1.0.35", - "@backstage/test-utils": "^1.5.8", + "@backstage/cli": "^0.34.3", + "@backstage/core-app-api": "^1.19.0", + "@backstage/dev-utils": "^1.1.14", + "@backstage/frontend-defaults": "^0.3.1", + "@backstage/test-utils": "^1.7.11", "@testing-library/jest-dom": "^6.6.3", "@types/copyfiles": "^2", "copyfiles": "^2.4.1" @@ -90,12 +91,13 @@ ], "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.tsx" + "./alpha": "./src/alpha/index.ts", + "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.tsx" + "src/alpha/index.ts" ], "package.json": [ "package.json" diff --git a/plugins/backstage-plugin/src/alpha.tsx b/plugins/backstage-plugin/src/alpha.tsx deleted file mode 100644 index 6a68075..0000000 --- a/plugins/backstage-plugin/src/alpha.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2025 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"; -import { - ApiBlueprint, - createFrontendPlugin, - createRouteRef, - FrontendPlugin, - PageBlueprint, - NavItemBlueprint, - discoveryApiRef, - configApiRef, - fetchApiRef, - ConfigApi, - DiscoveryApi, - FetchApi -} from "@backstage/frontend-plugin-api"; -import { compatWrapper } from "@backstage/core-compat-api"; -import { EntityCardBlueprint } from "@backstage/plugin-catalog-react/alpha" -import { pagerDutyApiRef, PagerDutyClient } from './api'; -import { PagerDutyIcon } from './components'; - -export const rootRouteRef = createRouteRef(); - -/** @alpha */ -const PagerDutyAPI = ApiBlueprint.make({ - params: { - factory: { - api: pagerDutyApiRef, - deps: { - discoveryApi: discoveryApiRef, - configApi: configApiRef, - fetchApi: fetchApiRef - }, - factory: ({ - configApi, - discoveryApi, - fetchApi - }: { configApi: ConfigApi; discoveryApi: DiscoveryApi; fetchApi: FetchApi }) => - PagerDutyClient.fromConfig(configApi, { discoveryApi, fetchApi }), - } - } -}); - -/** @alpha */ -const PagerDutyPage = PageBlueprint.make({ - params: { - defaultPath: '/pagerduty', - routeRef: rootRouteRef, - loader: () => - import('./components/PagerDutyPage') - .then(m => compatWrapper()), - } -}); - -/** @alpha */ -const EntityPagerDutyCard = EntityCardBlueprint.make({ - name: 'EntityPagerDutyCard', - params: { - filter: 'kind:component', - loader: async () => import('./components/EntityPagerDutyCard') - .then(m => compatWrapper()), - } -}); - -/** @alpha */ -const PagerDutyNavBarItem = NavItemBlueprint.make({ - name: 'PagerDutyNavBarItem', - params: { - title: 'PagerDuty', - icon: () => , - routeRef: rootRouteRef, - } -}); - -/** @alpha */ -export default createFrontendPlugin({ - pluginId: 'pagerduty', - extensions: [ - EntityPagerDutyCard, - PagerDutyAPI, - PagerDutyPage, - PagerDutyNavBarItem - ], - routes: { - root: rootRouteRef - } -}) as FrontendPlugin; diff --git a/plugins/backstage-plugin/src/alpha/api.ts b/plugins/backstage-plugin/src/alpha/api.ts new file mode 100644 index 0000000..a0b8d7c --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/api.ts @@ -0,0 +1,26 @@ +import { + ApiBlueprint, + configApiRef, + discoveryApiRef, + fetchApiRef +} from "@backstage/frontend-plugin-api"; +import { pagerDutyApiRef, PagerDutyClient } from "../api"; + +/** @alpha */ +export const pagerDutyApi = ApiBlueprint.make({ + params: defineParams => + defineParams({ + api: pagerDutyApiRef, + deps: { + configApi: configApiRef, + fetchApi: fetchApiRef, + discoveryApi: discoveryApiRef, + }, + factory({ configApi, fetchApi, discoveryApi }) { + return PagerDutyClient.fromConfig(configApi, { + fetchApi, + discoveryApi, + }); + }, + }), +}); diff --git a/plugins/backstage-plugin/src/alpha/entity-cards.tsx b/plugins/backstage-plugin/src/alpha/entity-cards.tsx new file mode 100644 index 0000000..f9371c5 --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/entity-cards.tsx @@ -0,0 +1,67 @@ +import { compatWrapper } from '@backstage/core-compat-api'; +import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; +import { PAGERDUTY_INTEGRATION_KEY, PAGERDUTY_SERVICE_ID } from '../components/constants'; + +/** @alpha */ +export const pagerDutyEntityCard = EntityCardBlueprint.makeWithOverrides({ + name: 'EntityPagerDutyCard', + config: { + schema: { + readOnly: z => z.boolean().optional(), + disableChangeEvents: z => z.boolean().optional(), + disableOnCall: z => z.boolean().optional(), + } + }, + factory(originalFactory, { config }) { + return originalFactory({ + filter: entity => Boolean( + entity.metadata?.annotations?.[PAGERDUTY_INTEGRATION_KEY] || + entity.metadata?.annotations?.[PAGERDUTY_SERVICE_ID] + ), + async loader() { + const { EntityPagerDutyCard } = await import('../components/EntityPagerDutyCard'); + + return compatWrapper( + + ); + } + }) + } +}); + +/** @alpha */ +export const pagerDutyEntitySmallCard = EntityCardBlueprint.makeWithOverrides({ + name: 'EntityPagerDutySmallCard', + disabled: true, + config: { + schema: { + readOnly: z => z.boolean().optional(), + disableOnCall: z => z.boolean().optional(), + disableInsights: z => z.boolean().optional(), + }, + }, + factory(originalFactory, { config }) { + return originalFactory({ + filter: entity => Boolean( + entity.metadata?.annotations?.[PAGERDUTY_INTEGRATION_KEY] || + entity.metadata?.annotations?.[PAGERDUTY_SERVICE_ID] + ), + async loader() { + const { EntityPagerDutySmallCard } = await import( + '../components/EntityPagerDutySmallCard' + ); + return compatWrapper( + , + ); + }, + }); + }, +}); diff --git a/plugins/backstage-plugin/src/alpha/index.ts b/plugins/backstage-plugin/src/alpha/index.ts new file mode 100644 index 0000000..69bd0ef --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/index.ts @@ -0,0 +1 @@ +export { pagerDutyPlugin as default } from './plugin'; diff --git a/plugins/backstage-plugin/src/alpha/nav-items.tsx b/plugins/backstage-plugin/src/alpha/nav-items.tsx new file mode 100644 index 0000000..8622cce --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/nav-items.tsx @@ -0,0 +1,14 @@ +import { NavItemBlueprint } from "@backstage/frontend-plugin-api"; +import { rootRouteRef } from "../routes"; +import { PagerDutyIcon } from "../components"; +import { convertLegacyRouteRef } from "@backstage/core-compat-api"; + +/** @alpha */ +export const pagerDutyNavBarItem = NavItemBlueprint.make({ + name: 'PagerDutyNavBarItem', + params: { + title: 'PagerDuty', + icon: PagerDutyIcon, + routeRef: convertLegacyRouteRef(rootRouteRef), + } +}); diff --git a/plugins/backstage-plugin/src/alpha/pages.tsx b/plugins/backstage-plugin/src/alpha/pages.tsx new file mode 100644 index 0000000..907b2ed --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/pages.tsx @@ -0,0 +1,13 @@ +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; +import { rootRouteRef } from '../routes'; +import { PageBlueprint } from '@backstage/frontend-plugin-api'; + +/** @alpha */ +export const pagerDutyPage = PageBlueprint.make({ + params: { + path: '/pagerduty', + routeRef: convertLegacyRouteRef(rootRouteRef), + loader: () => + import('../components/PagerDutyPage').then(m => ), + } +}); diff --git a/plugins/backstage-plugin/src/alpha/plugin.ts b/plugins/backstage-plugin/src/alpha/plugin.ts new file mode 100644 index 0000000..048ddd8 --- /dev/null +++ b/plugins/backstage-plugin/src/alpha/plugin.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2025 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 { createFrontendPlugin } from "@backstage/frontend-plugin-api"; +import { pagerDutyEntityCard, pagerDutyEntitySmallCard } from "../alpha/entity-cards"; +import { pagerDutyApi } from "../alpha/api"; +import { pagerDutyPage } from "../alpha/pages"; +import { pagerDutyNavBarItem } from "../alpha/nav-items"; +import { convertLegacyRouteRefs } from "@backstage/core-compat-api"; +import { rootRouteRef } from "../routes"; +import '@backstage/ui/css/styles.css'; + +/** @alpha */ +export const pagerDutyPlugin = createFrontendPlugin({ + pluginId: 'pagerduty', + info: { packageJson: () => import('../../package.json')}, + extensions: [ + pagerDutyEntityCard, + pagerDutyEntitySmallCard, + pagerDutyApi, + pagerDutyPage, + pagerDutyNavBarItem + ], + routes: convertLegacyRouteRefs({ + root: rootRouteRef + }) +}); diff --git a/plugins/backstage-plugin/src/plugin.ts b/plugins/backstage-plugin/src/plugin.ts index 97d15e5..9377c56 100644 --- a/plugins/backstage-plugin/src/plugin.ts +++ b/plugins/backstage-plugin/src/plugin.ts @@ -17,7 +17,6 @@ import { pagerDutyApiRef, PagerDutyClient } from './api'; import { createApiFactory, createPlugin, - createRouteRef, discoveryApiRef, fetchApiRef, configApiRef, @@ -26,10 +25,8 @@ import { } from '@backstage/core-plugin-api'; import { createCardExtension } from '@backstage/plugin-home-react'; import { HomePagePagerDutyCardProps } from './components/HomePagePagerDutyCard/Content'; +import { rootRouteRef } from './routes'; -export const rootRouteRef = createRouteRef({ - id: 'pagerduty', -}); /** @public */ export const pagerDutyPlugin = createPlugin({ diff --git a/plugins/backstage-plugin/dev/mockEntity.ts b/plugins/backstage-plugin/src/routes.ts similarity index 55% rename from plugins/backstage-plugin/dev/mockEntity.ts rename to plugins/backstage-plugin/src/routes.ts index 251ba80..db9c667 100644 --- a/plugins/backstage-plugin/dev/mockEntity.ts +++ b/plugins/backstage-plugin/src/routes.ts @@ -13,23 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -export const mockEntity: Entity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { - name: 'backstage', - description: 'backstage.io', - annotations: { - 'github.com/project-slug': 'backstage/backstage', - 'pagerduty.com/service-id': 'foo', - 'pagerduty.com/integration-key': 'foo', - }, - }, - spec: { - lifecycle: 'production', - type: 'website', - owner: 'user:guest', - }, -}; +import { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ id: 'pagerduty' }); diff --git a/yarn.lock b/yarn.lock index 4436ee1..454d5b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,15 +2766,15 @@ __metadata: languageName: node linkType: hard -"@backstage/app-defaults@npm:^1.6.3": - version: 1.6.3 - resolution: "@backstage/app-defaults@npm:1.6.3" +"@backstage/app-defaults@npm:^1.7.0": + version: 1.7.0 + resolution: "@backstage/app-defaults@npm:1.7.0" dependencies: - "@backstage/core-app-api": "npm:^1.17.1" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/theme": "npm:^0.6.6" + "@backstage/core-app-api": "npm:^1.19.0" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/theme": "npm:^0.6.8" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" peerDependencies: @@ -2785,7 +2785,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/438afc8f8545467ada3866c2437166171a45dc2ef54bf4f73b548e088a1178c8b4991e6c2667469222143370eb6dd546a005f7c885a0fc31b0c8259a39a1342b + checksum: 10c0/f2843b120d66a0520830b95773c95412a98e1f3a54c0382846cfef69338d719932ccfa7608f274ba83920ee92d8a64363704d943a14e7578a79cc92d8c9cb1b9 languageName: node linkType: hard @@ -3651,6 +3651,18 @@ __metadata: languageName: node linkType: hard +"@backstage/catalog-client@npm:^1.12.0": + version: 1.12.0 + resolution: "@backstage/catalog-client@npm:1.12.0" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/errors": "npm:^1.2.7" + cross-fetch: "npm:^4.0.0" + uri-template: "npm:^2.0.0" + checksum: 10c0/c403212c1af786e17b31103b25b682640533c14e1af54e3a6fdbbb9b001ab2fe8dd03346062b4f444ace1f6cbd7d17b6b6d2d3be1f5cd24e9f056c025bbe94ad + languageName: node + linkType: hard + "@backstage/catalog-model@npm:^1.5.0, @backstage/catalog-model@npm:^1.7.0, @backstage/catalog-model@npm:^1.7.3, @backstage/catalog-model@npm:^1.7.4": version: 1.7.4 resolution: "@backstage/catalog-model@npm:1.7.4" @@ -3878,7 +3890,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-app-api@npm:^1.14.0, @backstage/core-app-api@npm:^1.17.1": +"@backstage/core-app-api@npm:^1.17.1": version: 1.17.1 resolution: "@backstage/core-app-api@npm:1.17.1" dependencies: @@ -3934,6 +3946,34 @@ __metadata: languageName: node linkType: hard +"@backstage/core-app-api@npm:^1.19.0": + version: 1.19.0 + resolution: "@backstage/core-app-api@npm:1.19.0" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + "@types/prop-types": "npm:^15.7.3" + history: "npm:^5.0.0" + i18next: "npm:^22.4.15" + lodash: "npm:^4.17.21" + prop-types: "npm:^15.7.2" + react-use: "npm:^17.2.4" + zen-observable: "npm:^0.10.0" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/4fa96ed0e6d18e9bbacff6cd09adfda2b305d9cd993054d283703f0b8174d45ec532eb20b296a5d350ffd18da739dcb62f7457eab5a61069976d0d7655bc713a + languageName: node + linkType: hard + "@backstage/core-compat-api@npm:^0.4.3": version: 0.4.3 resolution: "@backstage/core-compat-api@npm:0.4.3" @@ -3976,29 +4016,51 @@ __metadata: languageName: node linkType: hard -"@backstage/core-components@npm:^0.14.9": - version: 0.14.10 - resolution: "@backstage/core-components@npm:0.14.10" +"@backstage/core-compat-api@npm:^0.5.2": + version: 0.5.2 + resolution: "@backstage/core-compat-api@npm:0.5.2" dependencies: - "@backstage/config": "npm:^1.2.0" - "@backstage/core-plugin-api": "npm:^1.9.3" - "@backstage/errors": "npm:^1.2.4" - "@backstage/theme": "npm:^0.5.6" - "@backstage/version-bridge": "npm:^1.0.8" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-catalog-react": "npm:^1.21.0" + "@backstage/version-bridge": "npm:^1.0.11" + lodash: "npm:^4.17.21" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/54baa338d187764699321b801cef296e6c1520eef387bdde2490153926a6d22effc49ab420b621af8ef6503875fe73ec5f9bd655e9d7d42d783abddd6e60026d + languageName: node + linkType: hard + +"@backstage/core-components@npm:^0.17.3": + version: 0.17.3 + resolution: "@backstage/core-components@npm:0.17.3" + dependencies: + "@backstage/config": "npm:^1.3.2" + "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/errors": "npm:^1.2.7" + "@backstage/theme": "npm:^0.6.6" + "@backstage/version-bridge": "npm:^1.0.11" + "@dagrejs/dagre": "npm:^1.1.4" "@date-io/core": "npm:^1.3.13" "@material-table/core": "npm:^3.1.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" "@react-hookz/web": "npm:^24.0.0" - "@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0" + "@testing-library/react": "npm:^16.0.0" "@types/react-sparklines": "npm:^1.7.0" ansi-regex: "npm:^6.0.1" classnames: "npm:^2.2.6" d3-selection: "npm:^3.0.0" d3-shape: "npm:^3.0.0" d3-zoom: "npm:^3.0.0" - dagre: "npm:^0.8.5" + js-yaml: "npm:^4.1.0" linkify-react: "npm:4.1.3" linkifyjs: "npm:4.1.3" lodash: "npm:^4.17.21" @@ -4018,21 +4080,25 @@ __metadata: zen-observable: "npm:^0.10.0" zod: "npm:^3.22.4" peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 10c0/5afb8394e254e6ded61dd87addbf298059e3393ee2bc1532193109d469c843bb434469ba888b6b07fe5381360e2f10b6d9e4d35a7625b1e8fc3a3c7fcf8036db + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/1a8e73152d2603cd649c5c2c4076c41cdbe22fbe3d9cbb677518046311c6cc145a5d1d328b2db7fa8796011c94428ce4b6db7750338fefe6a0458267950453ce languageName: node linkType: hard -"@backstage/core-components@npm:^0.17.3": - version: 0.17.3 - resolution: "@backstage/core-components@npm:0.17.3" +"@backstage/core-components@npm:^0.17.4": + version: 0.17.4 + resolution: "@backstage/core-components@npm:0.17.4" dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/errors": "npm:^1.2.7" - "@backstage/theme": "npm:^0.6.6" + "@backstage/theme": "npm:^0.6.7" "@backstage/version-bridge": "npm:^1.0.11" "@dagrejs/dagre": "npm:^1.1.4" "@date-io/core": "npm:^1.3.13" @@ -4075,18 +4141,18 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/1a8e73152d2603cd649c5c2c4076c41cdbe22fbe3d9cbb677518046311c6cc145a5d1d328b2db7fa8796011c94428ce4b6db7750338fefe6a0458267950453ce + checksum: 10c0/5028fdc206bf0416f65c3118cfa05229559748700bbb1aa3ed9f4e5273089f91f7c76144c253dcd962b3362a8a848ee9393759504dd8886aea32096a2279877f languageName: node linkType: hard -"@backstage/core-components@npm:^0.17.4": - version: 0.17.4 - resolution: "@backstage/core-components@npm:0.17.4" +"@backstage/core-components@npm:^0.18.0": + version: 0.18.0 + resolution: "@backstage/core-components@npm:0.18.0" dependencies: "@backstage/config": "npm:^1.3.3" - "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/core-plugin-api": "npm:^1.11.0" "@backstage/errors": "npm:^1.2.7" - "@backstage/theme": "npm:^0.6.7" + "@backstage/theme": "npm:^0.6.8" "@backstage/version-bridge": "npm:^1.0.11" "@dagrejs/dagre": "npm:^1.1.4" "@date-io/core": "npm:^1.3.13" @@ -4103,12 +4169,13 @@ __metadata: d3-shape: "npm:^3.0.0" d3-zoom: "npm:^3.0.0" js-yaml: "npm:^4.1.0" - linkify-react: "npm:4.1.3" - linkifyjs: "npm:4.1.3" + linkify-react: "npm:4.3.2" + linkifyjs: "npm:4.3.2" lodash: "npm:^4.17.21" pluralize: "npm:^8.0.0" qs: "npm:^6.9.4" rc-progress: "npm:3.5.1" + react-full-screen: "npm:^1.1.1" react-helmet: "npm:6.1.0" react-hook-form: "npm:^7.12.2" react-idle-timer: "npm:5.7.2" @@ -4129,7 +4196,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/5028fdc206bf0416f65c3118cfa05229559748700bbb1aa3ed9f4e5273089f91f7c76144c253dcd962b3362a8a848ee9393759504dd8886aea32096a2279877f + checksum: 10c0/99ff6bfc13994631758dd3c1b765f49803293468c765e7ab1eeee6dffe52b114e24b2958dee4c45df8cd7061a92ed72ab624f1851f43a48d4bbc69a8e159b3ec languageName: node linkType: hard @@ -4175,18 +4242,39 @@ __metadata: languageName: node linkType: hard -"@backstage/dev-utils@npm:^1.0.35": - version: 1.1.11 - resolution: "@backstage/dev-utils@npm:1.1.11" +"@backstage/core-plugin-api@npm:^1.11.0": + version: 1.11.0 + resolution: "@backstage/core-plugin-api@npm:1.11.0" dependencies: - "@backstage/app-defaults": "npm:^1.6.3" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-app-api": "npm:^1.17.1" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/theme": "npm:^0.6.6" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + history: "npm:^5.0.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d462dd2fa1c013d120dd574ff4f879764ff371cd1c21ada99bb48652cf6e187f056c14c47ec5ea51407400e4d1939914f696b283b7cc8be898ed2a08a26d0f35 + languageName: node + linkType: hard + +"@backstage/dev-utils@npm:^1.1.14": + version: 1.1.14 + resolution: "@backstage/dev-utils@npm:1.1.14" + dependencies: + "@backstage/app-defaults": "npm:^1.7.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-app-api": "npm:^1.19.0" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/integration-react": "npm:^1.2.10" + "@backstage/plugin-catalog-react": "npm:^1.21.0" + "@backstage/theme": "npm:^0.6.8" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" react-use: "npm:^17.2.4" @@ -4198,7 +4286,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/4603beab85cda91f48ca9a41d4daad88e3a645f87f1283f598f8f68eee1f0ab4c1be5fd6b2f637453c47cba63b9b3fcd92ce9a1fa242cb1b1e1866c662b71088 + checksum: 10c0/53605b36e1e46a599af0eb3b455798eda4fea5e808e10e4dada5291f067b86b121be14ac708d664fe0c6df429161b8e76c8e4d37b0a3d674ed936ef41d8d21a9 languageName: node linkType: hard @@ -4289,6 +4377,32 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-app-api@npm:^0.13.0": + version: 0.13.0 + resolution: "@backstage/frontend-app-api@npm:0.13.0" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-app-api": "npm:^1.19.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-defaults": "npm:^0.3.1" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + lodash: "npm:^4.17.21" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/183d0672a14349bed46605245cbbddd8fd9066710a0210dd67e5178b47a89700c7236d2d9c1b959b1edd6489baa558bfbb2ade2701e40eeb8a70d49d538487ad + languageName: node + linkType: hard + "@backstage/frontend-defaults@npm:^0.2.3": version: 0.2.3 resolution: "@backstage/frontend-defaults@npm:0.2.3" @@ -4333,6 +4447,29 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-defaults@npm:^0.3.1": + version: 0.3.1 + resolution: "@backstage/frontend-defaults@npm:0.3.1" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-app-api": "npm:^0.13.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-app": "npm:^0.3.0" + "@react-hookz/web": "npm:^24.0.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/eb76eda486656de684f8f87f606c297de86a638555bc11740b9c79914f055212069fc07fedcc618997103c95a668682d4a5ebd347bb9098b4b6b9e36635f36d8 + languageName: node + linkType: hard + "@backstage/frontend-plugin-api@npm:^0.10.3": version: 0.10.3 resolution: "@backstage/frontend-plugin-api@npm:0.10.3" @@ -4381,6 +4518,30 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-plugin-api@npm:^0.12.0": + version: 0.12.0 + resolution: "@backstage/frontend-plugin-api@npm:0.12.0" + dependencies: + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.4" + lodash: "npm:^4.17.21" + zod: "npm:^3.22.4" + zod-to-json-schema: "npm:^3.21.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/816263a00c8cb8c7174f72fccef801326f046aa5213cc5bdabca31bea4f0f0144aba50960144cc53c87834747deebe8ad4ca1302bdd709e503424ca9585a033c + languageName: node + linkType: hard + "@backstage/frontend-test-utils@npm:^0.3.3": version: 0.3.3 resolution: "@backstage/frontend-test-utils@npm:0.3.3" @@ -4431,6 +4592,31 @@ __metadata: languageName: node linkType: hard +"@backstage/frontend-test-utils@npm:^0.3.6": + version: 0.3.6 + resolution: "@backstage/frontend-test-utils@npm:0.3.6" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/frontend-app-api": "npm:^0.13.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-app": "npm:^0.3.0" + "@backstage/test-utils": "npm:^1.7.11" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + zod: "npm:^3.22.4" + peerDependencies: + "@testing-library/react": ^16.0.0 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/e4a83aab38623983e3f2aa726ab00f8cb080e941f7da3731b23c1dedd3b5fa7fb5ba2399773e90812b8f4f142745fce53f8f0cc34600d759a4caa0f1b20dc44f + languageName: node + linkType: hard + "@backstage/integration-aws-node@npm:^0.1.12, @backstage/integration-aws-node@npm:^0.1.16": version: 0.1.16 resolution: "@backstage/integration-aws-node@npm:0.1.16" @@ -4446,6 +4632,27 @@ __metadata: languageName: node linkType: hard +"@backstage/integration-react@npm:^1.2.10": + version: 1.2.10 + resolution: "@backstage/integration-react@npm:1.2.10" + dependencies: + "@backstage/config": "npm:^1.3.3" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/integration": "npm:^1.18.0" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/ecd55947e807521dc3ab1360e36b53f30f7c13ad75e84dc6d93a0b8be3681e7f99012ee158ebac4d8b3bfdd338e3d81bd2b4ca01bda682a99604a17540f2a12f + languageName: node + linkType: hard + "@backstage/integration-react@npm:^1.2.8": version: 1.2.8 resolution: "@backstage/integration-react@npm:1.2.8" @@ -4524,19 +4731,37 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-api-docs@npm:^0.12.9": - version: 0.12.9 - resolution: "@backstage/plugin-api-docs@npm:0.12.9" +"@backstage/integration@npm:^1.18.0": + version: 1.18.0 + resolution: "@backstage/integration@npm:1.18.0" + dependencies: + "@azure/identity": "npm:^4.0.0" + "@azure/storage-blob": "npm:^12.5.0" + "@backstage/config": "npm:^1.3.3" + "@backstage/errors": "npm:^1.2.7" + "@octokit/auth-app": "npm:^4.0.0" + "@octokit/rest": "npm:^19.0.3" + cross-fetch: "npm:^4.0.0" + git-url-parse: "npm:^15.0.0" + lodash: "npm:^4.17.21" + luxon: "npm:^3.0.0" + checksum: 10c0/40ac8029ab82902bf294ee0df6c117f61926bc76d6818e5a81bff0ef0d6e98274b7cbc3193948efd5f8dc124559ebab6928e5358e8e645de52f270f055d2243d + languageName: node + linkType: hard + +"@backstage/plugin-api-docs@npm:^0.12.11": + version: 0.12.11 + resolution: "@backstage/plugin-api-docs@npm:0.12.11" dependencies: "@asyncapi/react-component": "npm:^2.3.3" "@backstage/catalog-model": "npm:^1.7.5" - "@backstage/core-compat-api": "npm:^0.4.4" - "@backstage/core-components": "npm:^0.17.4" - "@backstage/core-plugin-api": "npm:^1.10.9" - "@backstage/frontend-plugin-api": "npm:^0.10.4" - "@backstage/plugin-catalog": "npm:^1.31.1" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-catalog": "npm:^1.31.3" "@backstage/plugin-catalog-common": "npm:^1.1.5" - "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-catalog-react": "npm:^1.21.0" "@backstage/plugin-permission-react": "npm:^0.4.36" "@graphiql/react": "npm:^0.23.0" "@material-ui/core": "npm:^4.12.2" @@ -4556,7 +4781,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/0c1dc21db396f854739075238da64c18eb33036c234384cf9215a82fe3d6c837ffe79431835c818cfab7f68f87dd78afc059ebf8c6cd308c5ddf9c779cefe07e + checksum: 10c0/9b0a59125f214d645437d5b3bbfd31e55151e7e4d301ffce84c8e2c51feb537e5e91b29dc7558dfc353b0248bcb0ff59dc8c798b22025900a17d20e1458e73b5 languageName: node linkType: hard @@ -4651,6 +4876,36 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-app@npm:^0.3.0": + version: 0.3.0 + resolution: "@backstage/plugin-app@npm:0.3.0" + dependencies: + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/integration-react": "npm:^1.2.10" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/theme": "npm:^0.6.8" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.9.13" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:^4.0.0-alpha.61" + "@react-hookz/web": "npm:^24.0.0" + react-use: "npm:^17.2.4" + zod: "npm:^3.22.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/baac6d6a4caa13b238a3659e2900e219071c3160e574c8ed94d2b0735cc1b0c7dab3414ebd1fbbb5dd6ef0cb6fbe631c7163335c1afa3ab962f051ec381f2f19 + languageName: node + linkType: hard + "@backstage/plugin-auth-backend-module-github-provider@npm:^0.3.4": version: 0.3.4 resolution: "@backstage/plugin-auth-backend-module-github-provider@npm:0.3.4" @@ -4893,18 +5148,18 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog-graph@npm:^0.4.20": - version: 0.4.20 - resolution: "@backstage/plugin-catalog-graph@npm:0.4.20" - dependencies: - "@backstage/catalog-client": "npm:^1.10.1" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/core-compat-api": "npm:^0.4.3" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-plugin-api": "npm:^0.10.3" - "@backstage/plugin-catalog-react": "npm:^1.19.0" - "@backstage/types": "npm:^1.2.1" +"@backstage/plugin-catalog-graph@npm:^0.5.0": + version: 0.5.0 + resolution: "@backstage/plugin-catalog-graph@npm:0.5.0" + dependencies: + "@backstage/catalog-client": "npm:^1.12.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-catalog-react": "npm:^1.21.0" + "@backstage/types": "npm:^1.2.2" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -4921,26 +5176,26 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/b93df87afc74a822549433bfd3c4a08e00101c96cb3650f40a3bce1a6957a8873783beacce96428537aad0ee4bc8b12a183c29edc2ffb8d3ccd53b6f48bd5489 + checksum: 10c0/0ab555aa11a5e6ed0115c1f3a61eaee1d1664105ab2d5a944bc89a754badd3d58c405797f61aa4782e48b15068cc5aeab7eb7cc8b79d5f7d120ee3c9e1303a4a languageName: node linkType: hard -"@backstage/plugin-catalog-import@npm:^0.13.3": - version: 0.13.3 - resolution: "@backstage/plugin-catalog-import@npm:0.13.3" +"@backstage/plugin-catalog-import@npm:^0.13.5": + version: 0.13.5 + resolution: "@backstage/plugin-catalog-import@npm:0.13.5" dependencies: - "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-client": "npm:^1.12.0" "@backstage/catalog-model": "npm:^1.7.5" "@backstage/config": "npm:^1.3.3" - "@backstage/core-compat-api": "npm:^0.4.4" - "@backstage/core-components": "npm:^0.17.4" - "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.4" - "@backstage/integration": "npm:^1.17.1" - "@backstage/integration-react": "npm:^1.2.9" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/integration": "npm:^1.18.0" + "@backstage/integration-react": "npm:^1.2.10" "@backstage/plugin-catalog-common": "npm:^1.1.5" - "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-catalog-react": "npm:^1.21.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@material-ui/lab": "npm:4.0.0-alpha.61" @@ -4959,7 +5214,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/d5340bd7807a9336996ea035405e7f95ba052172be4689094bca3e21a6b9390ae06cfd07d5c90e2c3380366d7e56515e8b95bf067e9cdb8a9761d946ca606b0c + checksum: 10c0/be50be0f76d25f6f208e8aca5eceae77d1322a6e99c52ab7073ca0393eb5e02ce5e80abca7d2a05f66cf8e59984d74ac72e717a4631603afa54f326191491a18 languageName: node linkType: hard @@ -5063,27 +5318,68 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-catalog@npm:^1.31.1": - version: 1.31.1 - resolution: "@backstage/plugin-catalog@npm:1.31.1" +"@backstage/plugin-catalog-react@npm:^1.21.0": + version: 1.21.0 + resolution: "@backstage/plugin-catalog-react@npm:1.21.0" dependencies: - "@backstage/catalog-client": "npm:^1.10.2" + "@backstage/catalog-client": "npm:^1.12.0" "@backstage/catalog-model": "npm:^1.7.5" - "@backstage/core-compat-api": "npm:^0.4.4" - "@backstage/core-components": "npm:^0.17.4" - "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-plugin-api": "npm:^0.10.4" - "@backstage/integration-react": "npm:^1.2.9" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/frontend-test-utils": "npm:^0.3.6" + "@backstage/integration-react": "npm:^1.2.10" "@backstage/plugin-catalog-common": "npm:^1.1.5" - "@backstage/plugin-catalog-react": "npm:^1.19.1" + "@backstage/plugin-permission-common": "npm:^0.9.1" "@backstage/plugin-permission-react": "npm:^0.4.36" - "@backstage/plugin-scaffolder-common": "npm:^1.6.0" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:4.0.0-alpha.61" + "@react-hookz/web": "npm:^24.0.0" + classnames: "npm:^2.2.6" + lodash: "npm:^4.17.21" + material-ui-popup-state: "npm:^1.9.3" + qs: "npm:^6.9.4" + react-use: "npm:^17.2.4" + yaml: "npm:^2.0.0" + zen-observable: "npm:^0.10.0" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/026e7d22a7c8cbbb0416562600155900e4962b64a0248b998b88703e307c8464c75c69788a9ffa36b318aa3437b19eff9451e7d99b1601b799120c31ebd95c0b + languageName: node + linkType: hard + +"@backstage/plugin-catalog@npm:^1.31.3": + version: 1.31.3 + resolution: "@backstage/plugin-catalog@npm:1.31.3" + dependencies: + "@backstage/catalog-client": "npm:^1.12.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/integration-react": "npm:^1.2.10" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-react": "npm:^1.21.0" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/plugin-scaffolder-common": "npm:^1.7.1" "@backstage/plugin-search-common": "npm:^1.2.19" - "@backstage/plugin-search-react": "npm:^1.9.2" + "@backstage/plugin-search-react": "npm:^1.9.4" "@backstage/plugin-techdocs-common": "npm:^0.1.1" - "@backstage/plugin-techdocs-react": "npm:^1.3.1" - "@backstage/types": "npm:^1.2.1" + "@backstage/plugin-techdocs-react": "npm:^1.3.3" + "@backstage/types": "npm:^1.2.2" "@backstage/version-bridge": "npm:^1.0.11" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" @@ -5105,7 +5401,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/bdd40d48e7195572a70bd2c15c5ab18d187125db77e049191cee1156ec34b314fe03d66d7fd9926a73e3b175022b6cf355c25aa58329c1307143f6c66622d1b8 + checksum: 10c0/c21f1c9453ff1570808f37bcf4dfe579baaba9e7b008e3b674d6a8e5d8220a1f3e0c826271c86108161cb86351ec112fa9ebc2a1ff7657d2f066b19a56f010df languageName: node linkType: hard @@ -5135,13 +5431,13 @@ __metadata: languageName: node linkType: hard -"@backstage/plugin-home-react@npm:^0.1.15": - version: 0.1.27 - resolution: "@backstage/plugin-home-react@npm:0.1.27" +"@backstage/plugin-home-react@npm:^0.1.30": + version: 0.1.30 + resolution: "@backstage/plugin-home-react@npm:0.1.30" dependencies: - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-plugin-api": "npm:^0.10.3" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@rjsf/utils": "npm:5.23.2" @@ -5153,7 +5449,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/d1ef3f40fef7c9a73a7c0752537a50949b052b4e4725019d1a7e4280b2f2598d3f9aea436031018d36a82441eedfa68dc2a0c828704711828adb5f4a712f2dc6 + checksum: 10c0/419d8c59d130100935e8451f8974f2b248adfb81a3803cc6c38fa587da62b5b871cada21db79b0df0a1eeb7f7196a3244f230dfe54cbb197770174a842ed8f95 languageName: node linkType: hard @@ -5764,6 +6060,25 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-scaffolder-common@npm:^1.7.1": + version: 1.7.1 + resolution: "@backstage/plugin-scaffolder-common@npm:1.7.1" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/errors": "npm:^1.2.7" + "@backstage/integration": "npm:^1.18.0" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/types": "npm:^1.2.2" + "@microsoft/fetch-event-source": "npm:^2.0.1" + "@types/json-schema": "npm:^7.0.9" + cross-fetch: "npm:^4.0.0" + json-schema: "npm:^0.4.0" + uri-template: "npm:^2.0.0" + zen-observable: "npm:^0.10.0" + checksum: 10c0/aa61ddd75025f8e7374a8ead63f9f9ba96810131166eb35ac314738297cb1a63dea5b35730f209d1531372c4f406b7a624e81d366c8e5195ba716f262808b419 + languageName: node + linkType: hard + "@backstage/plugin-scaffolder-node@npm:^0.4.7, @backstage/plugin-scaffolder-node@npm:^0.4.8": version: 0.4.12 resolution: "@backstage/plugin-scaffolder-node@npm:0.4.12" @@ -6104,6 +6419,36 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-search-react@npm:^1.9.4": + version: 1.9.4 + resolution: "@backstage/plugin-search-react@npm:1.9.4" + dependencies: + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-search-common": "npm:^1.2.19" + "@backstage/theme": "npm:^0.6.8" + "@backstage/types": "npm:^1.2.2" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + "@material-ui/lab": "npm:4.0.0-alpha.61" + lodash: "npm:^4.17.21" + qs: "npm:^6.9.4" + react-use: "npm:^17.3.2" + uuid: "npm:^11.0.2" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/54f11a3bab3f429ffe51500ec0148aedba7914dc7f06eeb0a47e351f0b7aa1d42080cd308caf701996d8a3b0148800dd8b0cd4f34d4ef5942fa2b280fb50bb6f + languageName: node + linkType: hard + "@backstage/plugin-search@npm:^1.4.28": version: 1.4.28 resolution: "@backstage/plugin-search@npm:1.4.28" @@ -6310,6 +6655,35 @@ __metadata: languageName: node linkType: hard +"@backstage/plugin-techdocs-react@npm:^1.3.3": + version: 1.3.3 + resolution: "@backstage/plugin-techdocs-react@npm:1.3.3" + dependencies: + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-techdocs-common": "npm:^0.1.1" + "@backstage/version-bridge": "npm:^1.0.11" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/styles": "npm:^4.11.0" + jss: "npm:~10.10.0" + lodash: "npm:^4.17.21" + react-helmet: "npm:6.1.0" + react-use: "npm:^17.2.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/73e052415514e698abc22e7be383a39ceadcf1d0f64313d69e36c94683c1d307ab895b315a9aff6d0ef4af494b8bb8c34110510c555204bb065167fe25c6557d + languageName: node + linkType: hard + "@backstage/plugin-techdocs@npm:^1.13.2": version: 1.13.2 resolution: "@backstage/plugin-techdocs@npm:1.13.2" @@ -6401,16 +6775,16 @@ __metadata: languageName: node linkType: hard -"@backstage/test-utils@npm:^1.5.8, @backstage/test-utils@npm:^1.7.9": - version: 1.7.9 - resolution: "@backstage/test-utils@npm:1.7.9" +"@backstage/test-utils@npm:^1.7.10": + version: 1.7.10 + resolution: "@backstage/test-utils@npm:1.7.10" dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/core-app-api": "npm:^1.17.1" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/plugin-permission-common": "npm:^0.9.0" - "@backstage/plugin-permission-react": "npm:^0.4.35" - "@backstage/theme": "npm:^0.6.6" + "@backstage/config": "npm:^1.3.3" + "@backstage/core-app-api": "npm:^1.18.0" + "@backstage/core-plugin-api": "npm:^1.10.9" + "@backstage/plugin-permission-common": "npm:^0.9.1" + "@backstage/plugin-permission-react": "npm:^0.4.36" + "@backstage/theme": "npm:^0.6.7" "@backstage/types": "npm:^1.2.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" @@ -6426,20 +6800,20 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/d0bcfbbacddf9078becf453ab7a888ca2624619dc360676c3ad9c6ded0ca729dd4b157c9f5dc72690816c4f6fdca0dcce22657954a3ddf642dd9755c7831c1c7 + checksum: 10c0/5f8f8e9757961143bbf24ed118dca8d817e1151cb6185b735175b9b4976f6bf3dc31a08b78af49aa966edbd6367afa914b5566b6e046f7d883dfc40aa8523534 languageName: node linkType: hard -"@backstage/test-utils@npm:^1.7.10": - version: 1.7.10 - resolution: "@backstage/test-utils@npm:1.7.10" +"@backstage/test-utils@npm:^1.7.11": + version: 1.7.11 + resolution: "@backstage/test-utils@npm:1.7.11" dependencies: "@backstage/config": "npm:^1.3.3" "@backstage/core-app-api": "npm:^1.18.0" "@backstage/core-plugin-api": "npm:^1.10.9" "@backstage/plugin-permission-common": "npm:^0.9.1" "@backstage/plugin-permission-react": "npm:^0.4.36" - "@backstage/theme": "npm:^0.6.7" + "@backstage/theme": "npm:^0.6.8" "@backstage/types": "npm:^1.2.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" @@ -6455,7 +6829,36 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/5f8f8e9757961143bbf24ed118dca8d817e1151cb6185b735175b9b4976f6bf3dc31a08b78af49aa966edbd6367afa914b5566b6e046f7d883dfc40aa8523534 + checksum: 10c0/0e5c0336e2dd1a1c95d46e9a75cd51d6616f2cd2cec704caaa3b7c2908aa81431b9bc725392f1784d8af68b6f96574e3e847ba9742990a5d06e7a89b5c23b8be + languageName: node + linkType: hard + +"@backstage/test-utils@npm:^1.7.9": + version: 1.7.9 + resolution: "@backstage/test-utils@npm:1.7.9" + dependencies: + "@backstage/config": "npm:^1.3.2" + "@backstage/core-app-api": "npm:^1.17.1" + "@backstage/core-plugin-api": "npm:^1.10.8" + "@backstage/plugin-permission-common": "npm:^0.9.0" + "@backstage/plugin-permission-react": "npm:^0.4.35" + "@backstage/theme": "npm:^0.6.6" + "@backstage/types": "npm:^1.2.1" + "@material-ui/core": "npm:^4.12.2" + "@material-ui/icons": "npm:^4.9.1" + cross-fetch: "npm:^4.0.0" + i18next: "npm:^22.4.15" + zen-observable: "npm:^0.10.0" + peerDependencies: + "@testing-library/react": ^16.0.0 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d0bcfbbacddf9078becf453ab7a888ca2624619dc360676c3ad9c6ded0ca729dd4b157c9f5dc72690816c4f6fdca0dcce22657954a3ddf642dd9755c7831c1c7 languageName: node linkType: hard @@ -6515,6 +6918,26 @@ __metadata: languageName: node linkType: hard +"@backstage/theme@npm:^0.6.8": + version: 0.6.8 + resolution: "@backstage/theme@npm:0.6.8" + dependencies: + "@emotion/react": "npm:^11.10.5" + "@emotion/styled": "npm:^11.10.5" + "@mui/material": "npm:^5.12.2" + peerDependencies: + "@material-ui/core": ^4.12.2 + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/547cfc64fe328e422dc5968b0c0a4f589332e345b02c3993b33cb0987c5259f97040ea6e86675fee1d7964a574fdb6f96e9f915479cb1c160e23d227b12d1eeb + languageName: node + linkType: hard + "@backstage/types@npm:^1.1.1, @backstage/types@npm:^1.2.1": version: 1.2.1 resolution: "@backstage/types@npm:1.2.1" @@ -6522,6 +6945,13 @@ __metadata: languageName: node linkType: hard +"@backstage/types@npm:^1.2.2": + version: 1.2.2 + resolution: "@backstage/types@npm:1.2.2" + checksum: 10c0/3c947cf83c058a56b0cfd90d91483e9a5c1c913f7978a0d5a3c0fd9b502d08e9bdf279afba626826eee84159e698ee4cdaa70040789ac47fc8a25df9f1925612 + languageName: node + linkType: hard + "@backstage/ui@npm:^0.6.1": version: 0.6.1 resolution: "@backstage/ui@npm:0.6.1" @@ -6544,7 +6974,28 @@ __metadata: languageName: node linkType: hard -"@backstage/version-bridge@npm:^1.0.11, @backstage/version-bridge@npm:^1.0.8": +"@backstage/ui@npm:^0.7.1": + version: 0.7.1 + resolution: "@backstage/ui@npm:0.7.1" + dependencies: + "@base-ui-components/react": "npm:1.0.0-alpha.7" + "@remixicon/react": "npm:^4.6.0" + "@tanstack/react-table": "npm:^8.21.3" + clsx: "npm:^2.1.1" + react-aria-components: "npm:^1.10.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + react-router-dom: ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/db29a408c4a1dc078e38d326e6e59512327cf53ec70c96eb9aee2c7af924045f077660bfecd394a28ecf00587395a37d378f8b95e3a8179b84cabe5251a524ae + languageName: node + linkType: hard + +"@backstage/version-bridge@npm:^1.0.11": version: 1.0.11 resolution: "@backstage/version-bridge@npm:1.0.11" peerDependencies: @@ -10711,19 +11162,21 @@ __metadata: version: 0.0.0-use.local resolution: "@pagerduty/backstage-plugin@workspace:plugins/backstage-plugin" dependencies: - "@backstage/catalog-client": "npm:^1.10.2" - "@backstage/catalog-model": "npm:^1.5.0" - "@backstage/cli": "npm:^0.33.0" - "@backstage/core-app-api": "npm:^1.14.0" - "@backstage/core-compat-api": "npm:^0.4.4" - "@backstage/core-components": "npm:^0.14.9" - "@backstage/core-plugin-api": "npm:^1.9.3" - "@backstage/dev-utils": "npm:^1.0.35" - "@backstage/errors": "npm:^1.2.4" - "@backstage/frontend-plugin-api": "npm:^0.10.4" - "@backstage/plugin-catalog-react": "npm:^1.19.1" - "@backstage/plugin-home-react": "npm:^0.1.15" - "@backstage/test-utils": "npm:^1.5.8" + "@backstage/catalog-client": "npm:^1.12.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/cli": "npm:^0.34.3" + "@backstage/core-app-api": "npm:^1.19.0" + "@backstage/core-compat-api": "npm:^0.5.2" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/dev-utils": "npm:^1.1.14" + "@backstage/errors": "npm:^1.2.7" + "@backstage/frontend-defaults": "npm:^0.3.1" + "@backstage/frontend-plugin-api": "npm:^0.12.0" + "@backstage/plugin-catalog": "npm:^1.31.3" + "@backstage/plugin-catalog-react": "npm:^1.21.0" + "@backstage/plugin-home-react": "npm:^0.1.30" + "@backstage/test-utils": "npm:^1.7.11" "@backstage/theme": "npm:^0.5.6" "@backstage/ui": "npm:^0.6.1" "@emotion/react": "npm:^11.11.4" @@ -17688,21 +18141,21 @@ __metadata: version: 0.0.0-use.local resolution: "app@workspace:packages/app" dependencies: - "@backstage/app-defaults": "npm:^1.6.3" + "@backstage/app-defaults": "npm:^1.7.0" "@backstage/canon": "npm:^0.5.0" - "@backstage/catalog-model": "npm:^1.7.4" - "@backstage/cli": "npm:^0.33.0" - "@backstage/core-app-api": "npm:^1.17.1" - "@backstage/core-components": "npm:^0.17.3" - "@backstage/core-plugin-api": "npm:^1.10.8" - "@backstage/frontend-defaults": "npm:^0.2.4" - "@backstage/integration-react": "npm:^1.2.8" - "@backstage/plugin-api-docs": "npm:^0.12.9" - "@backstage/plugin-catalog": "npm:^1.31.1" - "@backstage/plugin-catalog-common": "npm:^1.1.4" - "@backstage/plugin-catalog-graph": "npm:^0.4.20" - "@backstage/plugin-catalog-import": "npm:^0.13.3" - "@backstage/plugin-catalog-react": "npm:^1.19.0" + "@backstage/catalog-model": "npm:^1.7.5" + "@backstage/cli": "npm:^0.34.3" + "@backstage/core-app-api": "npm:^1.19.0" + "@backstage/core-components": "npm:^0.18.0" + "@backstage/core-plugin-api": "npm:^1.11.0" + "@backstage/frontend-defaults": "npm:^0.3.1" + "@backstage/integration-react": "npm:^1.2.10" + "@backstage/plugin-api-docs": "npm:^0.12.11" + "@backstage/plugin-catalog": "npm:^1.31.3" + "@backstage/plugin-catalog-common": "npm:^1.1.5" + "@backstage/plugin-catalog-graph": "npm:^0.5.0" + "@backstage/plugin-catalog-import": "npm:^0.13.5" + "@backstage/plugin-catalog-react": "npm:^1.21.0" "@backstage/plugin-kubernetes": "npm:^0.12.8" "@backstage/plugin-org": "npm:^0.6.41" "@backstage/plugin-permission-react": "npm:^0.4.35" @@ -17715,7 +18168,7 @@ __metadata: "@backstage/plugin-user-settings": "npm:^0.8.23" "@backstage/test-utils": "npm:^1.7.9" "@backstage/theme": "npm:^0.6.6" - "@backstage/ui": "npm:^0.6.1" + "@backstage/ui": "npm:^0.7.1" "@material-ui/core": "npm:^4.12.2" "@material-ui/icons": "npm:^4.9.1" "@pagerduty/backstage-plugin": "workspace:^" @@ -20762,16 +21215,6 @@ __metadata: languageName: node linkType: hard -"dagre@npm:^0.8.5": - version: 0.8.5 - resolution: "dagre@npm:0.8.5" - dependencies: - graphlib: "npm:^2.1.8" - lodash: "npm:^4.17.15" - checksum: 10c0/1c021b66961aa9a700bb6ec51747bcc214720a661ad6cb1878eab7316ecb550a759664a6754081a315b37d0355e3c19ff162813b36f20cbeb2e37f7440364d62 - languageName: node - linkType: hard - "damerau-levenshtein@npm:^1.0.8": version: 1.0.8 resolution: "damerau-levenshtein@npm:1.0.8" @@ -23343,11 +23786,11 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^12.23.12": - version: 12.23.12 - resolution: "framer-motion@npm:12.23.12" +"framer-motion@npm:^12.23.22": + version: 12.23.22 + resolution: "framer-motion@npm:12.23.22" dependencies: - motion-dom: "npm:^12.23.12" + motion-dom: "npm:^12.23.21" motion-utils: "npm:^12.23.6" tslib: "npm:^2.4.0" peerDependencies: @@ -23361,7 +23804,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10c0/40dfb57bf714075c4f6dd0bbe5b84dd11310114474ebf603846ef9b888ed475fa653271c1fd98ec57a6a1d0b781cdf8b3ebcd5e2c6a3620e934b46304ae0fd39 + checksum: 10c0/66d0e8cd0b99fdbc39bb6d8c45dee9f710003c1919d306d18b21c2b3cb4233f9546e1fc4f01dcff03014d12c561fd973e1a1678958f81ca1d7eb98db2ce04b0b languageName: node linkType: hard @@ -23504,6 +23947,13 @@ __metadata: languageName: node linkType: hard +"fscreen@npm:^1.0.2": + version: 1.2.0 + resolution: "fscreen@npm:1.2.0" + checksum: 10c0/1a5cb44446c9e9f7411454408f47ebdce7320a2493a0135b4b6b34af0e1a56c23fcd01d1f33201ce9e2da3f4d07da6ef7258e9f16960d0ec98e51653e0f16d60 + languageName: node + linkType: hard + "fsevents@npm:2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" @@ -24046,15 +24496,6 @@ __metadata: languageName: node linkType: hard -"graphlib@npm:^2.1.8": - version: 2.1.8 - resolution: "graphlib@npm:2.1.8" - dependencies: - lodash: "npm:^4.17.15" - checksum: 10c0/41c525e4d91a6d8b4e8da1883bf4e85689a547e908557ccc53f64db9141bdfb351b9162a79f13cae81c5b3a410027f59e4fc1edc1ea442234ec08e629859b188 - languageName: node - linkType: hard - "graphql-config@npm:^5.0.2": version: 5.1.5 resolution: "graphql-config@npm:5.1.5" @@ -27441,6 +27882,16 @@ __metadata: languageName: node linkType: hard +"linkify-react@npm:4.3.2": + version: 4.3.2 + resolution: "linkify-react@npm:4.3.2" + peerDependencies: + linkifyjs: ^4.0.0 + react: ">= 15.0.0" + checksum: 10c0/6f1e5fa28129bfa2c9fe7568a63c4cc8453cfa7de9f401a33b9bf6826b8d7ecccbb054cfe54c0b3f7c39d36b410189a9adcf438667c3e6443afda8bd2e4b36df + languageName: node + linkType: hard + "linkifyjs@npm:4.1.3": version: 4.1.3 resolution: "linkifyjs@npm:4.1.3" @@ -27448,6 +27899,13 @@ __metadata: languageName: node linkType: hard +"linkifyjs@npm:4.3.2": + version: 4.3.2 + resolution: "linkifyjs@npm:4.3.2" + checksum: 10c0/1a85e6b368304a4417567fe5e38651681e3e82465590836942d1b4f3c834cc35532898eb1e2479f6337d9144b297d418eb708b6be8ed0b3dc3954a3588e07971 + languageName: node + linkType: hard + "loader-runner@npm:^4.2.0": version: 4.3.0 resolution: "loader-runner@npm:4.3.0" @@ -29120,12 +29578,12 @@ __metadata: languageName: node linkType: hard -"motion-dom@npm:^12.23.12": - version: 12.23.12 - resolution: "motion-dom@npm:12.23.12" +"motion-dom@npm:^12.23.21": + version: 12.23.21 + resolution: "motion-dom@npm:12.23.21" dependencies: motion-utils: "npm:^12.23.6" - checksum: 10c0/1b6a4b86c1aed5b5da7b8a5d1f8310ad169125235bdc1953b8c41cf9f4e2c460ee90bb48ffdae54daecb8db1d7006566ceb5f5c9ccdc82606d548c527cb2631e + checksum: 10c0/0eee880c955ff0235f1e95e3cb07f8ab2bd446bc56eb55c1c4a9930536c66b06da496167130c7bafeb2084fddb4d484db6358bb7144e9457d93e71c523277f33 languageName: node linkType: hard @@ -29137,10 +29595,10 @@ __metadata: linkType: hard "motion@npm:^12.20.1": - version: 12.23.12 - resolution: "motion@npm:12.23.12" + version: 12.23.22 + resolution: "motion@npm:12.23.22" dependencies: - framer-motion: "npm:^12.23.12" + framer-motion: "npm:^12.23.22" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -29153,7 +29611,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10c0/48137c82b4fc8e55e06031f17219b2eb4385f028e77717aa6b2e87238c1e42d4222fb4b59b6527ebb66f98ea5f1234edd17c15682985e690b8cf48a5f3e44e67 + checksum: 10c0/dffcae42cafa5552d983f47eb0f36cf3d6f4fedaf24dc802c7348f95f86f5c504e2a354051a0ceed1593af3a9c8715c613d318aca92bc902c8df3a57529077d8 languageName: node linkType: hard @@ -32242,6 +32700,17 @@ __metadata: languageName: node linkType: hard +"react-full-screen@npm:^1.1.1": + version: 1.1.1 + resolution: "react-full-screen@npm:1.1.1" + dependencies: + fscreen: "npm:^1.0.2" + peerDependencies: + react: ">= 16.8.0" + checksum: 10c0/02c6034c6aca5c68b4067d2cbfe0328b2461a0ef3b27735cf2711aca53308242cf0f31f888e6fc22e9ea34ae28c61a8d8acaddfd497f100c8e84f87b58530439 + languageName: node + linkType: hard + "react-helmet@npm:6.1.0": version: 6.1.0 resolution: "react-helmet@npm:6.1.0" From b17baec971f5531a384891aa95d30e8e8a4ca7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gl=C3=B3ria?= Date: Wed, 1 Oct 2025 14:31:59 +0100 Subject: [PATCH 9/9] Add CODEOWNERS file for repository ownership (#73) (#76) Co-authored-by: Chris Micacchi --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..fcf68e5 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @PagerDuty/dev-ecosystem-and-public-apis