diff --git a/.changeset/analyze-software-creation.md b/.changeset/analyze-software-creation.md deleted file mode 100644 index 312987d3d1..0000000000 --- a/.changeset/analyze-software-creation.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Basic analytics instrumentation is now in place: - -- As users make their way through template steps, a `click` event is fired, including the step number. -- After a user clicks "Create" a `create` event is fired, including the name of the software that was just created. The template used at creation is set on the `entityRef` context key. diff --git a/.changeset/analyze-software-exploration.md b/.changeset/analyze-software-exploration.md deleted file mode 100644 index f535f60127..0000000000 --- a/.changeset/analyze-software-exploration.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Both `EntityProvider` and `AsyncEntityProvider` contexts now wrap all children with an `AnalyticsContext` containing the corresponding `entityRef`; this opens up the possibility for all events underneath these contexts to be associated with and aggregated by the corresponding entity. diff --git a/.changeset/angry-dingos-lick.md b/.changeset/angry-dingos-lick.md new file mode 100644 index 0000000000..933f19a839 --- /dev/null +++ b/.changeset/angry-dingos-lick.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-splunk-on-call': patch +'@backstage/plugin-techdocs-react': patch +--- + +Internal refactor to improve tests diff --git a/.changeset/beige-gorillas-sip.md b/.changeset/beige-gorillas-sip.md deleted file mode 100644 index b0dcaadfc6..0000000000 --- a/.changeset/beige-gorillas-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix logic bug that broke techdocs-cli-embedded-app diff --git a/.changeset/big-islands-add.md b/.changeset/big-islands-add.md deleted file mode 100644 index 4a6511562b..0000000000 --- a/.changeset/big-islands-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Set the `searchTooltip` to "Filter" to follow how the `searchPlaceholder` is set making this more consistent diff --git a/.changeset/brave-eels-allow.md b/.changeset/brave-eels-allow.md deleted file mode 100644 index 8fbe7ba8d2..0000000000 --- a/.changeset/brave-eels-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': minor ---- - -Updated the React Router wiring to make use of the new `basename` property of the router components in React Router v6 stable. To implement this, a new optional `basename` property has been added to the `Router` app component, which can be forwarded to the concrete router implementation in order to support this new behavior. This is done by default in any app that does not have a `Router` component override. diff --git a/.changeset/brown-days-pretend.md b/.changeset/brown-days-pretend.md deleted file mode 100644 index 4b6a328724..0000000000 --- a/.changeset/brown-days-pretend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch ---- - -Fixed bug when sending data by Post in `runChecks` and `runBulkChecks` functions of the `TechInsightsClient` class, the default `Content-Type` used was `plain/text` diff --git a/.changeset/calm-bottles-happen.md b/.changeset/calm-bottles-happen.md deleted file mode 100644 index e76db28065..0000000000 --- a/.changeset/calm-bottles-happen.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': minor ---- - -**BREAKING CHANGE**: The `UrlReader` interface has been updated to require that `readUrl` is implemented. `readUrl` has previously been optional to implement but a warning has been logged when calling its predecessor `read`. -The `read` method is now deprecated and will be removed in a future release. diff --git a/.changeset/chatty-planets-flash.md b/.changeset/chatty-planets-flash.md deleted file mode 100644 index d6a5c6ad42..0000000000 --- a/.changeset/chatty-planets-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Add `gitlabDiscoveryEntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/chilly-ads-lay.md b/.changeset/chilly-ads-lay.md new file mode 100644 index 0000000000..844eaa8dc7 --- /dev/null +++ b/.changeset/chilly-ads-lay.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': minor +--- + +**BREAKING PRODUCERS**: Added a new `getEntitiesByRefs` endpoint to `CatalogApi`, for efficient batch fetching of entities by ref. diff --git a/.changeset/clean-feet-remain.md b/.changeset/clean-feet-remain.md deleted file mode 100644 index c712ef9e1e..0000000000 --- a/.changeset/clean-feet-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-issues': patch ---- - -Stripping specific issues URL already present to target base issues URL. diff --git a/.changeset/clean-planets-rhyme.md b/.changeset/clean-planets-rhyme.md deleted file mode 100644 index a6878b491b..0000000000 --- a/.changeset/clean-planets-rhyme.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-azure': patch ---- - -`AzureDevOpsEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://backstage.io/docs/integrations/azure/discovery diff --git a/.changeset/clever-pillows-drive.md b/.changeset/clever-pillows-drive.md new file mode 100644 index 0000000000..f4e60fb869 --- /dev/null +++ b/.changeset/clever-pillows-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Do not use deprecated `LocationSpec` from the `@backstage/plugin-catalog-node` package diff --git a/.changeset/create-app-1667233110.md b/.changeset/create-app-1667233110.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1667233110.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/dirty-birds-burn.md b/.changeset/dirty-birds-burn.md deleted file mode 100644 index 98f2c5967d..0000000000 --- a/.changeset/dirty-birds-burn.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -`MicrosoftGraphOrgEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-msgraph#readme diff --git a/.changeset/dull-oranges-tap.md b/.changeset/dull-oranges-tap.md deleted file mode 100644 index 946656f610..0000000000 --- a/.changeset/dull-oranges-tap.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@backstage/plugin-techdocs': minor ---- - -Add ability to configure filters when using EntityListDocsGrid - -The following example will render two sections of cards grid: - -- One section for documentations tagged as `recommended` -- One section for documentations tagged as `runbook` - -```js - - entity?.metadata?.tags?.includes('recommended') ?? false, - }, - { - title: "RunBooks Documentation", - filterPredicate: entity => - entity?.metadata?.tags?.includes('runbook') ?? false, - } -]}} /> -``` diff --git a/.changeset/early-hairs-switch.md b/.changeset/early-hairs-switch.md new file mode 100644 index 0000000000..16f4298db5 --- /dev/null +++ b/.changeset/early-hairs-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +changed tests created by create-plugin to follow eslint-rules best practices particularly testing-library/prefer-screen-queries and testing-library/render-result-naming-convention diff --git a/.changeset/eight-pears-attack.md b/.changeset/eight-pears-attack.md deleted file mode 100644 index ca18abb2db..0000000000 --- a/.changeset/eight-pears-attack.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': minor ---- - -BREAKING: Support authenticated backends by including a server token for catalog requests. The constructor of `GithubLocationAnalyzer` now requires an instance of `TokenManager` to be supplied: - -```diff -... - builder.addLocationAnalyzers( - new GitHubLocationAnalyzer({ - discovery: env.discovery, - config: env.config, -+ tokenManager: env.tokenManager, - }), - ); -... -``` diff --git a/.changeset/eleven-pets-sneeze.md b/.changeset/eleven-pets-sneeze.md deleted file mode 100644 index 7c0d8147cc..0000000000 --- a/.changeset/eleven-pets-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -The app `Router` component now accepts an optional `basename` property. diff --git a/.changeset/fast-lies-remain.md b/.changeset/fast-lies-remain.md new file mode 100644 index 0000000000..74be117920 --- /dev/null +++ b/.changeset/fast-lies-remain.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Added new `POST /entities/by-refs` endpoint, which allows you to efficiently +batch-fetch entities by their entity ref. This can be useful e.g. in graphql +resolvers or similar contexts where you need to fetch many entities at the same +time. diff --git a/.changeset/few-books-remember.md b/.changeset/few-books-remember.md deleted file mode 100644 index 4607202ff6..0000000000 --- a/.changeset/few-books-remember.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-techdocs-node': patch -'@backstage/plugin-techdocs-backend': patch ---- - -Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. diff --git a/.changeset/flat-items-perform.md b/.changeset/flat-items-perform.md deleted file mode 100644 index 4bc846ba7e..0000000000 --- a/.changeset/flat-items-perform.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Added a set of default Prometheus metrics around scaffolding. See below for a list of metrics and an explanation of their labels: - -- `scaffolder_task_count`: Tracks successful task runs. - - Labels: - - - `template`: The entity ref of the scaffolded template - - `user`: The entity ref of the user that invoked the template run - - `result`: A string describing whether the task ran successfully, failed, or was skipped - -- `scaffolder_task_duration`: a histogram which tracks the duration of a task run - - Labels: - - - `template`: The entity ref of the scaffolded template - - `result`: A boolean describing whether the task ran successfully - -- `scaffolder_step_count`: a count that tracks each step run - - Labels: - - - `template`: The entity ref of the scaffolded template - - `step`: The name of the step that was run - - `result`: A string describing whether the task ran successfully, failed, or was skipped - -- `scaffolder_step_duration`: a histogram which tracks the duration of each step run - - Labels: - - - `template`: The entity ref of the scaffolded template - - `step`: The name of the step that was run - - `result`: A string describing whether the task ran successfully, failed, or was skipped - -You can find a guide for running Prometheus metrics here: https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/prometheus-metrics.md diff --git a/.changeset/flat-kangaroos-kiss.md b/.changeset/flat-kangaroos-kiss.md deleted file mode 100644 index a79c8621b1..0000000000 --- a/.changeset/flat-kangaroos-kiss.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -`GitlabDiscoveryEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://backstage.io/docs/integrations/gitlab/discovery diff --git a/.changeset/forty-bags-trade.md b/.changeset/forty-bags-trade.md deleted file mode 100644 index 4908134498..0000000000 --- a/.changeset/forty-bags-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Generated development HTTPS backend certificate is now checked for expiration date instead of file age. diff --git a/.changeset/forty-jokes-lie.md b/.changeset/forty-jokes-lie.md deleted file mode 100644 index bd44898004..0000000000 --- a/.changeset/forty-jokes-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-openapi': patch ---- - -Added support to use the `UrlReaders` when `$ref` pointing to a URL. diff --git a/.changeset/fresh-cooks-sing.md b/.changeset/fresh-cooks-sing.md deleted file mode 100644 index 31f5ff0f22..0000000000 --- a/.changeset/fresh-cooks-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': minor ---- - -This patch brings Gitea as a valid integration: target, via the ScmIntegration interface. It adds gitea to the relevant static properties (get integration by name, get integration by type) for plugins to be able to reference the same Gitea server. diff --git a/.changeset/fresh-weeks-share.md b/.changeset/fresh-weeks-share.md deleted file mode 100644 index aced6e910c..0000000000 --- a/.changeset/fresh-weeks-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -This patch adds GiteaURLReader to the available classes. It currently only reads single files via gitea's public repos api diff --git a/.changeset/funny-numbers-compete.md b/.changeset/funny-numbers-compete.md new file mode 100644 index 0000000000..604ffe7294 --- /dev/null +++ b/.changeset/funny-numbers-compete.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Use Json types from @backstage/types diff --git a/.changeset/gorgeous-balloons-sit.md b/.changeset/gorgeous-balloons-sit.md deleted file mode 100644 index a83b12131b..0000000000 --- a/.changeset/gorgeous-balloons-sit.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-stack-overflow-backend': patch -'@backstage/plugin-techdocs': patch ---- - -Tweak README diff --git a/.changeset/gorgeous-hairs-applaud.md b/.changeset/gorgeous-hairs-applaud.md new file mode 100644 index 0000000000..7793c6591e --- /dev/null +++ b/.changeset/gorgeous-hairs-applaud.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': patch +--- + +Wait for indexer initialization before finalizing indexing. diff --git a/.changeset/gorgeous-onions-thank.md b/.changeset/gorgeous-onions-thank.md deleted file mode 100644 index 8b41bfa5a0..0000000000 --- a/.changeset/gorgeous-onions-thank.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -`AwsS3EntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://backstage.io/docs/integrations/aws-s3/discovery diff --git a/.changeset/gorgeous-queens-pull.md b/.changeset/gorgeous-queens-pull.md deleted file mode 100644 index bb257e85f0..0000000000 --- a/.changeset/gorgeous-queens-pull.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/integration': minor ---- - -Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. - -Deprecates: - -- `getGitHubFileFetchUrl` replaced by `getGithubFileFetchUrl` -- `GitHubIntegrationConfig` replaced by `GithubIntegrationConfig` -- `GitHubIntegration` replaced by `GithubIntegration` -- `readGitHubIntegrationConfig` replaced by `readGithubIntegrationConfig` -- `readGitHubIntegrationConfigs` replaced by `readGithubIntegrationConfigs` -- `replaceGitHubUrlType` replaced by `replaceGithubUrlType` diff --git a/.changeset/great-colts-invite.md b/.changeset/great-colts-invite.md deleted file mode 100644 index 1ca71580dc..0000000000 --- a/.changeset/great-colts-invite.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Added a new ESLint rule that restricts imports of Link from @material-ui - -The rule can be can be overridden in the following way: - -```diff -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { -+ restrictedImports: [ -+ { name: '@material-ui/core', importNames: [] }, -+ { name: '@material-ui/core/Link', importNames: [] }, -+ ], -}); -``` diff --git a/.changeset/grumpy-clouds-drum.md b/.changeset/grumpy-clouds-drum.md deleted file mode 100644 index cf2d5d2a32..0000000000 --- a/.changeset/grumpy-clouds-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -- The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project. diff --git a/.changeset/grumpy-pigs-reflect.md b/.changeset/grumpy-pigs-reflect.md deleted file mode 100644 index 797aefcba0..0000000000 --- a/.changeset/grumpy-pigs-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Get rid of `this-is-undefined-in-esm` warning diff --git a/.changeset/happy-avocados-tan.md b/.changeset/happy-avocados-tan.md deleted file mode 100644 index 9f087930d5..0000000000 --- a/.changeset/happy-avocados-tan.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Removed forced capitalization for Entity types in the catalog sidebar. diff --git a/.changeset/heavy-elephants-nail.md b/.changeset/heavy-elephants-nail.md deleted file mode 100644 index 473e3eda9e..0000000000 --- a/.changeset/heavy-elephants-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': minor ---- - -Deprecated the `homepage` config as the component that used it - `HomepageTimer` - has been removed and replaced by the `HeaderWorldClock` in the home plugin diff --git a/.changeset/itchy-paws-protect.md b/.changeset/itchy-paws-protect.md deleted file mode 100644 index a0c272e5e4..0000000000 --- a/.changeset/itchy-paws-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-azure': patch ---- - -Add `azureDevOpsEntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/itchy-walls-boil.md b/.changeset/itchy-walls-boil.md new file mode 100644 index 0000000000..2afd0287fe --- /dev/null +++ b/.changeset/itchy-walls-boil.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-user-settings': minor +--- + +Added the ability to fully customize settings page. Deprecated UserSettingsTab in favour of SettingsLayout.Route diff --git a/.changeset/kind-emus-juggle.md b/.changeset/kind-emus-juggle.md deleted file mode 100644 index 2a99deef81..0000000000 --- a/.changeset/kind-emus-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -Add `awsS3EntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/lazy-planes-repair.md b/.changeset/lazy-planes-repair.md deleted file mode 100644 index 00ecfb095e..0000000000 --- a/.changeset/lazy-planes-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-tasks': patch ---- - -Deprecated the `HumanDuration` type, which should now instead be imported from `@backstage/types`. diff --git a/.changeset/little-bikes-eat.md b/.changeset/little-bikes-eat.md deleted file mode 100644 index 0992198146..0000000000 --- a/.changeset/little-bikes-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-radar': patch ---- - -Fixed bug in Tech Radar where, on hover, the tech list quadrant would rerender and scroll top diff --git a/.changeset/lucky-cats-peel.md b/.changeset/lucky-cats-peel.md deleted file mode 100644 index dfe1047b7c..0000000000 --- a/.changeset/lucky-cats-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Small update to fix compatibility with newer versions of the `keyv` library diff --git a/.changeset/lucky-cobras-sell.md b/.changeset/lucky-cobras-sell.md deleted file mode 100644 index 16d86d52e8..0000000000 --- a/.changeset/lucky-cobras-sell.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-playlist': patch -'@backstage/plugin-playlist-backend': patch ---- - -Updated Playlist plugin docs: - -- Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features -- Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings diff --git a/.changeset/lucky-spoons-hide.md b/.changeset/lucky-spoons-hide.md deleted file mode 100644 index c481941f6a..0000000000 --- a/.changeset/lucky-spoons-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated `@swc/core` to version 1.3.9 which fixes a `.tsx` parser bug diff --git a/.changeset/mean-files-fly.md b/.changeset/mean-files-fly.md deleted file mode 100644 index a7a79bcf74..0000000000 --- a/.changeset/mean-files-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Add `microsoftGraphOrgEntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/metal-dogs-swim.md b/.changeset/metal-dogs-swim.md deleted file mode 100644 index d97c7077f2..0000000000 --- a/.changeset/metal-dogs-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gerrit': patch ---- - -Add `gerritEntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/metal-hairs-mix.md b/.changeset/metal-hairs-mix.md deleted file mode 100644 index f795c37506..0000000000 --- a/.changeset/metal-hairs-mix.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-azure-devops-backend': patch ---- - -- Adjusted the asset parser to accept case sensitive -- Fixed fetching data that was using the deprecated function diff --git a/.changeset/nasty-crabs-share.md b/.changeset/nasty-crabs-share.md deleted file mode 100644 index d09eb09044..0000000000 --- a/.changeset/nasty-crabs-share.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-github-pull-requests-board': patch ---- - -Add a new "Team" Filter Options to the Github Pull Requests Dashboard. - -When toggling this option on, the dashboard will displays all of the PRs opened -by the members of that team on any repositories of the organization. diff --git a/.changeset/orange-trees-peel.md b/.changeset/orange-trees-peel.md deleted file mode 100644 index 344dd88cb9..0000000000 --- a/.changeset/orange-trees-peel.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/catalog-model': patch -'@backstage/core-components': patch -'@backstage/integration': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-xcmetrics': patch ---- - -Internal refactor of imports to avoid circular dependencies diff --git a/.changeset/popular-bulldogs-lie.md b/.changeset/popular-bulldogs-lie.md deleted file mode 100644 index 3bc83338c1..0000000000 --- a/.changeset/popular-bulldogs-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Properly derive Github credentials when making requests in `GithubLocationAnalyzer` to support Github App authentication diff --git a/.changeset/popular-mails-wave.md b/.changeset/popular-mails-wave.md deleted file mode 100644 index 23517f0608..0000000000 --- a/.changeset/popular-mails-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-ilert': minor ---- - -Added support for multiple responders in alert list, added new tab with list to support iLert resource 'service', added new tab with list to support iLert resource 'status page' diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 9aa5bbdfdf..0000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,252 +0,0 @@ -{ - "mode": "pre", - "tag": "next", - "initialVersions": { - "example-app": "0.2.76", - "@backstage/app-defaults": "1.0.7", - "example-backend": "0.2.76", - "@backstage/backend-app-api": "0.2.2", - "@backstage/backend-common": "0.15.2", - "@backstage/backend-defaults": "0.1.2", - "example-backend-next": "0.0.4", - "@backstage/backend-plugin-api": "0.1.3", - "@backstage/backend-tasks": "0.3.6", - "@backstage/backend-test-utils": "0.1.29", - "@backstage/catalog-client": "1.1.1", - "@backstage/catalog-model": "1.1.2", - "@backstage/cli": "0.20.0", - "@backstage/cli-common": "0.1.10", - "@backstage/codemods": "0.1.40", - "@backstage/config": "1.0.3", - "@backstage/config-loader": "1.1.5", - "@backstage/core-app-api": "1.1.1", - "@backstage/core-components": "0.11.2", - "@backstage/core-plugin-api": "1.0.7", - "@backstage/create-app": "0.4.32", - "@backstage/dev-utils": "1.0.7", - "e2e-test": "0.2.0", - "@backstage/errors": "1.1.2", - "@backstage/integration": "1.3.2", - "@backstage/integration-react": "1.1.5", - "@backstage/release-manifests": "0.0.6", - "@techdocs/cli": "1.2.2", - "techdocs-cli-embedded-app": "0.2.75", - "@backstage/test-utils": "1.2.1", - "@backstage/theme": "0.2.16", - "@backstage/types": "1.0.0", - "@backstage/version-bridge": "1.0.1", - "@backstage/plugin-adr": "0.2.2", - "@backstage/plugin-adr-backend": "0.2.2", - "@backstage/plugin-adr-common": "0.2.2", - "@backstage/plugin-airbrake": "0.3.10", - "@backstage/plugin-airbrake-backend": "0.2.10", - "@backstage/plugin-allure": "0.1.26", - "@backstage/plugin-analytics-module-ga": "0.1.21", - "@backstage/plugin-apache-airflow": "0.2.3", - "@backstage/plugin-api-docs": "0.8.10", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.0", - "@backstage/plugin-apollo-explorer": "0.1.3", - "@backstage/plugin-app-backend": "0.3.37", - "@backstage/plugin-auth-backend": "0.17.0", - "@backstage/plugin-auth-node": "0.2.6", - "@backstage/plugin-azure-devops": "0.2.1", - "@backstage/plugin-azure-devops-backend": "0.3.16", - "@backstage/plugin-azure-devops-common": "0.3.0", - "@backstage/plugin-badges": "0.2.34", - "@backstage/plugin-badges-backend": "0.1.31", - "@backstage/plugin-bazaar": "0.1.25", - "@backstage/plugin-bazaar-backend": "0.2.0", - "@backstage/plugin-bitbucket-cloud-common": "0.2.0", - "@backstage/plugin-bitrise": "0.1.37", - "@backstage/plugin-catalog": "1.6.0", - "@backstage/plugin-catalog-backend": "1.5.0", - "@backstage/plugin-catalog-backend-module-aws": "0.1.10", - "@backstage/plugin-catalog-backend-module-azure": "0.1.8", - "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.4", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.4", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.2", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.5", - "@backstage/plugin-catalog-backend-module-github": "0.1.8", - "@backstage/plugin-catalog-backend-module-gitlab": "0.1.8", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.4", - "@backstage/plugin-catalog-backend-module-msgraph": "0.4.3", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.3", - "@backstage/plugin-catalog-common": "1.0.7", - "@internal/plugin-catalog-customized": "0.0.3", - "@backstage/plugin-catalog-graph": "0.2.22", - "@backstage/plugin-catalog-graphql": "0.3.14", - "@backstage/plugin-catalog-import": "0.9.0", - "@backstage/plugin-catalog-node": "1.2.0", - "@backstage/plugin-catalog-react": "1.2.0", - "@backstage/plugin-cicd-statistics": "0.1.12", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.6", - "@backstage/plugin-circleci": "0.3.10", - "@backstage/plugin-cloudbuild": "0.3.10", - "@backstage/plugin-code-climate": "0.1.10", - "@backstage/plugin-code-coverage": "0.2.3", - "@backstage/plugin-code-coverage-backend": "0.2.3", - "@backstage/plugin-codescene": "0.1.5", - "@backstage/plugin-config-schema": "0.1.33", - "@backstage/plugin-cost-insights": "0.11.32", - "@backstage/plugin-cost-insights-common": "0.1.1", - "@backstage/plugin-dynatrace": "1.0.0", - "@internal/plugin-todo-list": "1.0.6", - "@internal/plugin-todo-list-backend": "1.0.6", - "@internal/plugin-todo-list-common": "1.0.5", - "@backstage/plugin-explore": "0.3.41", - "@backstage/plugin-explore-react": "0.0.22", - "@backstage/plugin-firehydrant": "0.1.27", - "@backstage/plugin-fossa": "0.2.42", - "@backstage/plugin-gcalendar": "0.3.6", - "@backstage/plugin-gcp-projects": "0.3.29", - "@backstage/plugin-git-release-manager": "0.3.23", - "@backstage/plugin-github-actions": "0.5.10", - "@backstage/plugin-github-deployments": "0.1.41", - "@backstage/plugin-github-issues": "0.1.2", - "@backstage/plugin-github-pull-requests-board": "0.1.4", - "@backstage/plugin-gitops-profiles": "0.3.28", - "@backstage/plugin-gocd": "0.1.16", - "@backstage/plugin-graphiql": "0.2.42", - "@backstage/plugin-graphql-backend": "0.1.27", - "@backstage/plugin-home": "0.4.26", - "@backstage/plugin-ilert": "0.1.36", - "@backstage/plugin-jenkins": "0.7.9", - "@backstage/plugin-jenkins-backend": "0.1.27", - "@backstage/plugin-jenkins-common": "0.1.9", - "@backstage/plugin-kafka": "0.3.10", - "@backstage/plugin-kafka-backend": "0.2.30", - "@backstage/plugin-kubernetes": "0.7.3", - "@backstage/plugin-kubernetes-backend": "0.7.3", - "@backstage/plugin-kubernetes-common": "0.4.3", - "@backstage/plugin-lighthouse": "0.3.10", - "@backstage/plugin-newrelic": "0.3.28", - "@backstage/plugin-newrelic-dashboard": "0.2.3", - "@backstage/plugin-org": "0.5.10", - "@backstage/plugin-pagerduty": "0.5.3", - "@backstage/plugin-periskop": "0.1.8", - "@backstage/plugin-periskop-backend": "0.1.8", - "@backstage/plugin-permission-backend": "0.5.12", - "@backstage/plugin-permission-common": "0.7.0", - "@backstage/plugin-permission-node": "0.7.0", - "@backstage/plugin-permission-react": "0.4.6", - "@backstage/plugin-playlist": "0.1.1", - "@backstage/plugin-playlist-backend": "0.2.0", - "@backstage/plugin-playlist-common": "0.1.1", - "@backstage/plugin-proxy-backend": "0.2.31", - "@backstage/plugin-rollbar": "0.4.10", - "@backstage/plugin-rollbar-backend": "0.1.34", - "@backstage/plugin-scaffolder": "1.7.0", - "@backstage/plugin-scaffolder-backend": "1.7.0", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.12", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.5", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.10", - "@backstage/plugin-scaffolder-common": "1.2.1", - "@backstage/plugin-search": "1.0.3", - "@backstage/plugin-search-backend": "1.1.0", - "@backstage/plugin-search-backend-module-elasticsearch": "1.0.3", - "@backstage/plugin-search-backend-module-pg": "0.4.1", - "@backstage/plugin-search-backend-node": "1.0.3", - "@backstage/plugin-search-common": "1.1.0", - "@backstage/plugin-search-react": "1.2.0", - "@backstage/plugin-sentry": "0.4.3", - "@backstage/plugin-shortcuts": "0.3.2", - "@backstage/plugin-sonarqube": "0.4.2", - "@backstage/plugin-sonarqube-backend": "0.1.2", - "@backstage/plugin-splunk-on-call": "0.3.34", - "@backstage/plugin-stack-overflow": "0.1.6", - "@backstage/plugin-stack-overflow-backend": "0.1.6", - "@backstage/plugin-tech-insights": "0.3.1", - "@backstage/plugin-tech-insights-backend": "0.5.3", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.21", - "@backstage/plugin-tech-insights-common": "0.2.7", - "@backstage/plugin-tech-insights-node": "0.3.5", - "@backstage/plugin-tech-radar": "0.5.17", - "@backstage/plugin-techdocs": "1.3.3", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.5", - "@backstage/plugin-techdocs-backend": "1.4.0", - "@backstage/plugin-techdocs-module-addons-contrib": "1.0.5", - "@backstage/plugin-techdocs-node": "1.4.1", - "@backstage/plugin-techdocs-react": "1.0.5", - "@backstage/plugin-todo": "0.2.12", - "@backstage/plugin-todo-backend": "0.1.34", - "@backstage/plugin-user-settings": "0.5.0", - "@backstage/plugin-user-settings-backend": "0.1.1", - "@backstage/plugin-vault": "0.1.4", - "@backstage/plugin-vault-backend": "0.2.3", - "@backstage/plugin-xcmetrics": "0.2.30", - "@backstage/plugin-azure-sites": "0.0.0", - "@backstage/plugin-azure-sites-backend": "0.0.0", - "@backstage/plugin-azure-sites-common": "0.0.0" - }, - "changesets": [ - "analyze-software-creation", - "analyze-software-exploration", - "beige-gorillas-sip", - "big-islands-add", - "brave-eels-allow", - "brown-days-pretend", - "calm-bottles-happen", - "chatty-planets-flash", - "clean-feet-remain", - "clean-planets-rhyme", - "create-app-1667233110", - "dirty-birds-burn", - "dull-oranges-tap", - "eight-pears-attack", - "eleven-pets-sneeze", - "few-books-remember", - "flat-items-perform", - "flat-kangaroos-kiss", - "forty-bags-trade", - "forty-jokes-lie", - "fresh-cooks-sing", - "fresh-weeks-share", - "gorgeous-balloons-sit", - "gorgeous-onions-thank", - "gorgeous-queens-pull", - "great-colts-invite", - "grumpy-clouds-drum", - "grumpy-pigs-reflect", - "happy-avocados-tan", - "heavy-elephants-nail", - "itchy-paws-protect", - "kind-emus-juggle", - "lazy-planes-repair", - "little-bikes-eat", - "lucky-cats-peel", - "lucky-cobras-sell", - "lucky-spoons-hide", - "mean-files-fly", - "metal-dogs-swim", - "metal-hairs-mix", - "nasty-crabs-share", - "orange-trees-peel", - "popular-bulldogs-lie", - "popular-mails-wave", - "real-swans-repair", - "renovate-6fb5f1b", - "selfish-kiwis-matter", - "shaggy-birds-happen", - "shaggy-colts-watch", - "sharp-goats-itch", - "shiny-beers-relax", - "short-balloons-work", - "sixty-islands-develop", - "sixty-pigs-shave", - "sixty-singers-push", - "spicy-parents-lick", - "spotty-dryers-explain", - "stupid-pens-occur", - "sweet-readers-compare", - "tame-ads-appear", - "tasty-colts-hug", - "tasty-scissors-tickle", - "ten-pens-draw", - "three-houses-agree", - "three-poems-think", - "two-oranges-joke", - "two-yaks-wave", - "unlucky-buttons-poke", - "wet-cameras-call" - ] -} diff --git a/.changeset/real-swans-repair.md b/.changeset/real-swans-repair.md deleted file mode 100644 index 67eafc9999..0000000000 --- a/.changeset/real-swans-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-common': patch ---- - -Properly handle rules that have no parameters in `PermissionClient` diff --git a/.changeset/renovate-4bb70f3.md b/.changeset/renovate-4bb70f3.md new file mode 100644 index 0000000000..3a9054011f --- /dev/null +++ b/.changeset/renovate-4bb70f3.md @@ -0,0 +1,17 @@ +--- +'@backstage/core-app-api': patch +'@backstage/core-components': patch +'@backstage/core-plugin-api': patch +'@backstage/dev-utils': patch +'@backstage/test-utils': patch +'@backstage/types': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-config-schema': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-shortcuts': patch +'@backstage/plugin-user-settings': patch +--- + +Updated dependency `zen-observable` to `^0.9.0`. diff --git a/.changeset/renovate-6fb5f1b.md b/.changeset/renovate-6fb5f1b.md deleted file mode 100644 index f98cc64ea4..0000000000 --- a/.changeset/renovate-6fb5f1b.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@svgr/plugin-jsx` to `6.5.x`. -Updated dependency `@svgr/plugin-svgo` to `6.5.x`. -Updated dependency `@svgr/rollup` to `6.5.x`. -Updated dependency `@svgr/webpack` to `6.5.x`. diff --git a/.changeset/search-om-manniskan-ginge.md b/.changeset/search-om-manniskan-ginge.md new file mode 100644 index 0000000000..c36972f191 --- /dev/null +++ b/.changeset/search-om-manniskan-ginge.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': patch +--- + +Updated indexer and decorator base classes to take advantage of features introduced in Node.js v16; be sure you are running a [supported version of Node.js](https://backstage.io/docs/releases/v1.8.0#node-16-and-18). diff --git a/.changeset/selfish-kiwis-matter.md b/.changeset/selfish-kiwis-matter.md deleted file mode 100644 index e258af0e97..0000000000 --- a/.changeset/selfish-kiwis-matter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated `@swc/core` to `v1.3.9` which fixes a `.tsx` parser bug. You may want to run `yarn backstage-cli versions:bump` to get on latest version including the CLI itself. diff --git a/.changeset/serious-windows-occur.md b/.changeset/serious-windows-occur.md new file mode 100644 index 0000000000..37f778e846 --- /dev/null +++ b/.changeset/serious-windows-occur.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-common': patch +'@backstage/core-components': patch +--- + +Internal refactor to avoid usage of deprecated symbols. diff --git a/.changeset/shaggy-birds-happen.md b/.changeset/shaggy-birds-happen.md deleted file mode 100644 index 7f7a691c85..0000000000 --- a/.changeset/shaggy-birds-happen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-issues': minor ---- - -**BREAKING**: Changed the casing of all exported types to have a lowercase "h" in "github". E.g. "GitHubIssuesPage" was renamed to "GithubIssuesPage". Please rename your imports where necessary. diff --git a/.changeset/shaggy-colts-watch.md b/.changeset/shaggy-colts-watch.md deleted file mode 100644 index 67003bd2d3..0000000000 --- a/.changeset/shaggy-colts-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Disable base path workaround in `Link` component when React Router v6 stable is used. diff --git a/.changeset/sharp-goats-itch.md b/.changeset/sharp-goats-itch.md deleted file mode 100644 index 601d6a7e9d..0000000000 --- a/.changeset/sharp-goats-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/types': patch ---- - -Added the `HumanDuration` type, moved here from `@backstage/backend-tasks`. This type matches the `Duration.fromObject` form of `luxon`. diff --git a/.changeset/shiny-beers-relax.md b/.changeset/shiny-beers-relax.md deleted file mode 100644 index be8e9b6fb7..0000000000 --- a/.changeset/shiny-beers-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated the create-app command to no longer require Git to be installed and configured. A git repository will only be initialized if possible and if not already in an git repository. diff --git a/.changeset/short-balloons-work.md b/.changeset/short-balloons-work.md deleted file mode 100644 index 5d0f66851d..0000000000 --- a/.changeset/short-balloons-work.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-bitrise': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-cost-insights': minor -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-xcmetrics': patch ---- - -Updated recharts to v2.0.0 and fixed typing issues diff --git a/.changeset/sixty-islands-develop.md b/.changeset/sixty-islands-develop.md deleted file mode 100644 index 9eb36cc1a9..0000000000 --- a/.changeset/sixty-islands-develop.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -Added props to override default Scaffolder page title, subtitle and pageTitleOverride. -Routes like `rootRouteRef`, `selectedTemplateRouteRef`, `nextRouteRef`, `nextSelectedTemplateRouteRef` were made public and can be used in your app (e.g. in custom TemplateCard component). diff --git a/.changeset/sixty-pigs-shave.md b/.changeset/sixty-pigs-shave.md deleted file mode 100644 index e1f4443ad4..0000000000 --- a/.changeset/sixty-pigs-shave.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch ---- - -Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. diff --git a/.changeset/sixty-singers-push.md b/.changeset/sixty-singers-push.md deleted file mode 100644 index b5b50ae077..0000000000 --- a/.changeset/sixty-singers-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-bazaar': minor ---- - -The limit prop of BazaarOverviewCard has been removed entirely, and instead replaced with a new optional boolean prop `fullWidth`. The BazaarOverviewCard now always use full height without fixed width. Also fixed problem with link to Bazaar. diff --git a/.changeset/slow-dragons-promise.md b/.changeset/slow-dragons-promise.md new file mode 100644 index 0000000000..045b4f34e3 --- /dev/null +++ b/.changeset/slow-dragons-promise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Fix incorrectly exported GithubOrgEntityProvider as a type diff --git a/.changeset/soft-nails-arrive.md b/.changeset/soft-nails-arrive.md new file mode 100644 index 0000000000..e9c0a40a05 --- /dev/null +++ b/.changeset/soft-nails-arrive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Implement Custom Field Explorer to view and play around with available installed custom field extensions diff --git a/.changeset/sour-flowers-care.md b/.changeset/sour-flowers-care.md new file mode 100644 index 0000000000..8524c4981c --- /dev/null +++ b/.changeset/sour-flowers-care.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Adds the ability to supply a `transformErrors` function to the `Stepper` for `/next` diff --git a/.changeset/sour-plums-grow.md b/.changeset/sour-plums-grow.md new file mode 100644 index 0000000000..4070dc5e50 --- /dev/null +++ b/.changeset/sour-plums-grow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +fixed `headerOptions` not passed to `TemplatePage` component diff --git a/.changeset/spicy-parents-lick.md b/.changeset/spicy-parents-lick.md deleted file mode 100644 index 692745ed12..0000000000 --- a/.changeset/spicy-parents-lick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Include query parameters when navigating to relative links in documents diff --git a/.changeset/spotty-dryers-explain.md b/.changeset/spotty-dryers-explain.md deleted file mode 100644 index 41bef3fbf7..0000000000 --- a/.changeset/spotty-dryers-explain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-xcmetrics': patch ---- - -Removed an unused and hidden build details route. diff --git a/.changeset/stupid-pens-occur.md b/.changeset/stupid-pens-occur.md deleted file mode 100644 index d8af9a447a..0000000000 --- a/.changeset/stupid-pens-occur.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': minor ---- - -**BREAKING**: Removed the `HomepageTimer` as it has been replaced by the `HeaderWorldClock` in the Home plugin and was deprecated over a year ago. diff --git a/.changeset/sweet-readers-compare.md b/.changeset/sweet-readers-compare.md deleted file mode 100644 index dd61b0afdc..0000000000 --- a/.changeset/sweet-readers-compare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-circleci': patch ---- - -Update screenshots in documentation to match latest CircleCI plugin diff --git a/.changeset/tame-ads-appear.md b/.changeset/tame-ads-appear.md deleted file mode 100644 index 887cc73252..0000000000 --- a/.changeset/tame-ads-appear.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch -'@backstage/plugin-tech-insights-node': patch ---- - -Add a default delay to the fact retrievers to prevent cold-start errors diff --git a/.changeset/tasty-colts-hug.md b/.changeset/tasty-colts-hug.md deleted file mode 100644 index e56d48a441..0000000000 --- a/.changeset/tasty-colts-hug.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-azure-sites': minor -'@backstage/plugin-azure-sites-backend': minor -'@backstage/plugin-azure-sites-common': minor ---- - -Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. diff --git a/.changeset/tasty-scissors-tickle.md b/.changeset/tasty-scissors-tickle.md deleted file mode 100644 index 745172df36..0000000000 --- a/.changeset/tasty-scissors-tickle.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch ---- - -`BitbucketServerEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://backstage.io/docs/integrations/bitbucketServer/discovery diff --git a/.changeset/ten-pens-draw.md b/.changeset/ten-pens-draw.md deleted file mode 100644 index be35a6f3b0..0000000000 --- a/.changeset/ten-pens-draw.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gerrit': patch ---- - -`GerritEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. - -Please find how to configure the schedule at the config at -https://backstage.io/docs/integrations/gerrit/discovery diff --git a/.changeset/three-houses-agree.md b/.changeset/three-houses-agree.md deleted file mode 100644 index 041cd471d3..0000000000 --- a/.changeset/three-houses-agree.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch -'@backstage/plugin-tech-insights-node': patch ---- - -Use `HumanDuration` from `@backstage/types` diff --git a/.changeset/three-poems-think.md b/.changeset/three-poems-think.md deleted file mode 100644 index aad3cae117..0000000000 --- a/.changeset/three-poems-think.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': minor ---- - -Added the ability for the GitHub discovery provider to validate that catalog files exist before emitting them. - -Users can now set the `validateLocationsExist` property to `true` in their GitHub discovery configuration to opt in to this feature. -This feature only works with `catalogPath`s that do not contain wildcards. - -When `validateLocationsExist` is set to `true`, the GitHub discovery provider will retrieve the object from the -repository at the provided `catalogPath`. -If this file exists and is non-empty, then it will be emitted as a location for further processing. -If this file does not exist or is empty, then it will not be emitted. -Not emitting locations that do not exist allows for far fewer calls to the GitHub API to validate locations that do not exist. diff --git a/.changeset/two-oranges-joke.md b/.changeset/two-oranges-joke.md deleted file mode 100644 index 7f116e8ab0..0000000000 --- a/.changeset/two-oranges-joke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch ---- - -Add `bitbucketServerEntityProviderCatalogModule` (new backend-plugin-api, alpha). diff --git a/.changeset/two-yaks-wave.md b/.changeset/two-yaks-wave.md deleted file mode 100644 index 97c2908928..0000000000 --- a/.changeset/two-yaks-wave.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/core-components': patch -'@backstage/create-app': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder': patch ---- - -Prefer using `Link` from `@backstage/core-components` rather than material-UI. diff --git a/.changeset/unlucky-buttons-poke.md b/.changeset/unlucky-buttons-poke.md deleted file mode 100644 index b0ccd2039a..0000000000 --- a/.changeset/unlucky-buttons-poke.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@backstage/integration': patch -'@backstage/plugin-catalog-backend-module-aws': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-stack-overflow-backend': patch -'@backstage/plugin-techdocs-backend': patch ---- - -Remove explicit default visibility at `config.d.ts` files. - -```ts -/** - * @visibility backend - */ -``` diff --git a/.changeset/weak-ears-jam.md b/.changeset/weak-ears-jam.md new file mode 100644 index 0000000000..8f20937998 --- /dev/null +++ b/.changeset/weak-ears-jam.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Added `integrations.github.apps.allowedInstallationOwners` to the configuration schema. diff --git a/.changeset/wet-cameras-call.md b/.changeset/wet-cameras-call.md deleted file mode 100644 index 3d58719269..0000000000 --- a/.changeset/wet-cameras-call.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': minor -'@backstage/plugin-kubernetes-common': patch ---- - -The Kubernetes errors when fetching pod metrics are now captured and returned to the frontend. - -- **BREAKING** The method `fetchPodMetricsByNamespace` in the interface `KubernetesFetcher` is changed to `fetchPodMetricsByNamespaces`. It now accepts a set of namespace strings and returns `Promise`. -- Add the `PodStatusFetchResponse` to the `FetchResponse` union type. -- Add `NOT_FOUND` to the `KubernetesErrorTypes` union type, the HTTP error with status code 404 will be mapped to this error. diff --git a/.eslintrc.js b/.eslintrc.js index 47a47daee6..6d07fab291 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,7 +18,7 @@ var path = require('path'); module.exports = { root: true, - plugins: ['notice'], + plugins: ['notice', 'testing-library'], rules: { 'notice/notice': [ 'error', @@ -45,5 +45,10 @@ module.exports = { "CallExpression[arguments.length=0] > MemberExpression[property.name='toUpperCase']", }, ], + 'testing-library/await-async-query': 'error', + 'testing-library/await-async-utils': 'error', + 'testing-library/no-await-sync-query': 'error', + 'testing-library/prefer-wait-for': 'error', + 'testing-library/no-dom-import': 'error', }, }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2dd8f4b55b..3f17c9591f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,6 +36,15 @@ yarn.lock @backstage/reviewers @backst /plugins/code-coverage-backend @backstage/reviewers @alde @nissayeva /plugins/cost-insights @backstage/reviewers @backstage/silver-lining /plugins/cost-insights-* @backstage/reviewers @backstage/silver-lining +/plugins/events-backend @backstage/reviewers @pjungermann +/plugins/events-backend-module-aws-sqs @backstage/reviewers @pjungermann +/plugins/events-backend-module-azure @backstage/reviewers @pjungermann +/plugins/events-backend-module-bitbucket-cloud @backstage/reviewers @pjungermann +/plugins/events-backend-module-gerrit @backstage/reviewers @pjungermann +/plugins/events-backend-module-github @backstage/reviewers @pjungermann +/plugins/events-backend-module-gitlab @backstage/reviewers @pjungermann +/plugins/events-backend-test-utils @backstage/reviewers @pjungermann +/plugins/events-node @backstage/reviewers @pjungermann /plugins/explore @backstage/reviewers @backstage/sda-se-reviewers /plugins/explore-react @backstage/reviewers @backstage/sda-se-reviewers /plugins/fossa @backstage/reviewers @backstage/sda-se-reviewers diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 5c4745c70c..93e0471fd3 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,6 +1,7 @@ { labels: ['dependencies'], extends: ['config:base', ':disableDependencyDashboard', ':gitSignOff'], + postUpdateOptions: ['yarnDedupeHighest'], rangeStrategy: 'update-lockfile', // @elastic/elasticsearch is ignored due to licensing issues. See #10992 ignoreDeps: ['@elastic/elasticsearch', 'event-source-polyfill'], diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index 839afaa256..f2b3ac0b09 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -234,11 +234,14 @@ onboarding Onboarding OpenShift orgs +padding +paddings pagerduty pageview parallelization parseable Patrik +pattison Peloton performant Performant @@ -314,6 +317,7 @@ Spotifiers spotify Spotify sqlite +sqs squidfunk src statefulsets @@ -352,6 +356,7 @@ theia thumbsup todo todos +togglable tolerations Tolerations toolchain @@ -403,3 +408,4 @@ zod Zolotusky zoomable zsh +Lainfiesta diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index 51bf41d61a..12fccdc7ed 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -17,7 +17,7 @@ jobs: for your contributions. days-before-issue-stale: 60 days-before-issue-close: 7 - exempt-issue-labels: pinned,security,plugin,after-vacations,rfc,will-fix + exempt-issue-labels: plugin,after-vacations,will-fix stale-issue-label: stale stale-pr-message: > This PR has been automatically marked as stale because it has not had diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64067188bb..eef5058690 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true @@ -33,7 +33,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -47,7 +47,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true @@ -63,10 +63,13 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} + - name: verify yarn dependency duplicates + run: node scripts/verify-lockfile-duplicates.js + - name: verify changesets run: node scripts/verify-changesets.js @@ -121,7 +124,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] services: postgres13: @@ -178,7 +181,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -208,7 +211,7 @@ jobs: - name: test all packages (and upload coverage) if: ${{ steps.yarn-lock.outcome == 'failure' }} run: | - yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --coverage + yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=800M --coverage bash <(curl -s https://codecov.io/bash) -N $(git rev-parse FETCH_HEAD) env: BACKSTAGE_NEXT_TESTS: 1 diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 467c817baf..4629d656ce 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -8,7 +8,7 @@ jobs: cron: runs-on: ubuntu-latest steps: - - uses: backstage/actions/cron@v0.5.6 + - uses: backstage/actions/cron@v0.5.7 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index af6f222377..1f87c30af2 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] env: CI: true diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index 476e5dd10b..360a74e012 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] env: CI: true @@ -26,7 +26,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index f3736d93a2..1d03c210cd 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] services: postgres13: @@ -67,7 +67,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -130,7 +130,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] env: CI: 'true' @@ -145,7 +145,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 95e91dda30..a42b9b6f7b 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -10,4 +10,4 @@ jobs: if: github.repository == 'backstage/backstage' steps: - name: Issue sync - uses: backstage/actions/issue-sync@v0.5.6 + uses: backstage/actions/issue-sync@v0.5.7 diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index e822209e03..6104a802d9 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -35,7 +35,7 @@ jobs: const prNumber = artifact.name.slice('pr_number-'.length) console.log(`::set-output name=pr-number::${prNumber}`); - - uses: backstage/actions/re-review@v0.5.6 + - uses: backstage/actions/re-review@v0.5.7 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index e13928ccee..4ab7da8e07 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -18,7 +18,7 @@ jobs: if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: - name: PR sync - uses: backstage/actions/pr-sync@v0.5.6 + uses: backstage/actions/pr-sync@v0.5.7 with: github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 779284818f..2113efe924 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -20,7 +20,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index dd35ba26f3..c1fb727c33 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - uses: actions/checkout@v3 @@ -23,7 +23,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 3353a84f3b..a84b315e33 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -31,7 +31,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true @@ -52,7 +52,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index e1bb2246dc..8d59d15899 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true diff --git a/.github/workflows/verify_e2e-tugboat.yml b/.github/workflows/verify_e2e-tugboat.yml index 04d9e686e2..cb3a463a0d 100644 --- a/.github/workflows/verify_e2e-tugboat.yml +++ b/.github/workflows/verify_e2e-tugboat.yml @@ -52,7 +52,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: '14' + node-version: '16.x' - name: yarn install run: yarn --cwd cypress install diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index 4e8025f7d5..fc29c1f03b 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: os: [windows-2019] - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true diff --git a/.github/workflows/verify_kubernetes.yml b/.github/workflows/verify_kubernetes.yml index e64ddec586..b92deb96ac 100644 --- a/.github/workflows/verify_kubernetes.yml +++ b/.github/workflows/verify_kubernetes.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true @@ -28,7 +28,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index 50c2116090..4085f334f3 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.x] env: CI: true @@ -32,6 +32,9 @@ jobs: run: yarn install --immutable working-directory: microsite + - name: verify yarn dependency duplicates + run: node scripts/verify-lockfile-duplicates.js + - name: prettier run: yarn prettier:check working-directory: microsite diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index cac94ff682..4fe39fe244 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -35,7 +35,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.6 + uses: backstage/actions/yarn-install@v0.5.7 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: storybook yarn install diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 8bbaa645bf..75a0633cbe 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] env: CI: true diff --git a/ADOPTERS.md b/ADOPTERS.md index 2dffec64dc..90aaa5c69b 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -141,7 +141,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Kambi AB](https://www.kambi.com) | [Martin Norum](mailto:martin.norum@kambi.com) | We want to kick ass at speed, so we're currently building up a catalog of our existing software, and looking into how Backstage can support us in our journey towards autonomous product teams. Both to improve speed to market and operational awareness. | | [ANZ](https://www.anz.com.au/personal/) | [Elliot Jackson](mailto:elliot.jackson@anz.com) | Catalog, tech docs and automation | | [Genie Solutions](https://www.geniesolutionssoftware.com.au) | [Zainab Bagasrawala](mailto:zainabbagasrawala@geniesolutions.com.au) | Developer Portal to track our projects, documentation, observability tools and more | -| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [Paulo Eduardo Peixoto](mailto:paulo.peixoto@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. | +| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [DX Team](mailto:dxteam@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. | | [Sonatype](https://www.sonatype.com) | [Srikar Ananthula](mailto:sananthula@sonatype.com) | Centralize services used internally with many plugins | | [CVS Health](https://www.cvshealth.com) | [Ari Ben-Elazar](mailto:abenelazar@gmail.com) | Cataloging and documenting our service offerings to offer our internal developers a better operational journey | | [Yatra.com](https://www.yatra.com) | [Matiur Rahman Maitur](mailto:arifrahman4u@gmail.com) | Easy to find out Project details, ownership, dependent services, Documentation, it is very useful for developer. | @@ -216,4 +216,9 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Inter&Co](https://bancointer.com.br) | [Arnaud Lanna](https://github.com/arnaudlanna), [Adriano Silva](https://github.com/adrianovss), [Bruno Grossi](https://github.com/begrossi) | We're using Backstage as our internal Developer Portal to catalog and collect repositories and microservices pieces of information like ownership, deployment time, and documentation. | | [StatusNeo](https://statusneo.com/) | [Karan Nangru](mailto:nangru@statusneo.com), [@NishkarshRaj](https://github.com/NishkarshRaj), and [Gaurav Sarien](mailto:gaurav.sarien@statusneo.com) | Harnessing the power of central catalog inventory and self-serving software templates | | [Alaska Airlines](https://alaskaair.com) | [@swerdick](https://github.com/swerdick) | Backstage is the developer portal for our 'software delivery platform'. Consolidating developer tools to one place, and providing automation to make it easy for developers to create and deploy applications to Kubernetes -| [Loft](https://loft.com.br) | [Augusto Hoffmann](mailto:augusto.hoffmann@loft.com.br) | We're using Backstage to give visibility and promote ownership of all our applications, resources and tools. Now moving to use it as a Developer Portal to create applications, AWS resources etc. | +| [Loft](https://loft.com.br) | [Squad DevTools](mailto:squad_devtools@loft.com.br) | We're using Backstage to give visibility and promote ownership of all our applications, resources and tools. Now moving to use it as a Developer Portal to create applications, AWS resources etc. | +| [Raízen](https://www.raizen.com) | [Melquisedque Bernardes Pereira](https://github.com/rayleshh) and [Paulo Eduardo Peixoto](https://github.com/padupe) | Backstage helps us to organize and make available, in a simple and direct way, all the infrastructure for new projects. In addition, it has become a great support tool for our developers. | +| [Trifork](https://trifork.com) | [Casper Thygesen](https://github.com/cthtrifork) | We're using Backstage as part of our dataplatform product. It integrates with the infrastructure components and is the developer portal for all the platform users. | +| [MSCI](http://msci.com) | [Stephen Burrows](mailto:stephen.burrows@msci.com) | Developer portal, service catalog, documentation and tooling +| [ESW](https://esw.com) | [Alisson Fabiano](https://github.com/afabianoo), [Bruno Quintella](https://github.com/quintelab) and [Guilherme Oenning](https://github.com/goenning) | Backstage is our one stop shop to find everything related to all our services, such as ownership, dependencies, production status, tech health and much more. +| [FanDuel](https://fanduel.com) | [Diego Herrera](https://github.com/diegoh), [Christy Campbell](https://github.com/FD-ChristopherCampbell) | We use backstage as our developer portal to provide visibility of our software, ownership, strategy, and the state of maturity across disciplines. diff --git a/REVIEWING.md b/REVIEWING.md index 469ac249f7..500e15701d 100644 --- a/REVIEWING.md +++ b/REVIEWING.md @@ -171,6 +171,37 @@ Exported types can be marked with either `@public`, `@alpha` or `@beta` release If a package does not have this configuration, then all exported types are considered stable, even if they are marked as `@alpha` or `@beta`. +#### Changes that are Not Considered Breaking + +There are a few exceptions that are not considered breaking in the [versioning policy](https://backstage.io/docs/overview/versioning-policy#changes-that-are-not-considered-breaking), +primarily regarding Utility APIs and Backend Service interfaces (referred to "contracts" below) that are supplied by the +Backstage core packages. + +Example of a non-breaking change to a contract which has a default +implementation, since consumers typically only interact with that contract as +callers of existing methods: + +```diff + export interface MyService { + oldMethod(): void; ++ newMethod(): void; + } +``` + +Changes such as these must still be marked with `**BREAKING PRODUCERS**:` in the +changelog, to highlight them for those who might be implementing custom +implementations of those contracts or putting mocks of the contract in tests. + +Example of a breaking change to a contract, which affects existing consumers and +therefore makes it NOT fall under these exceptions: + +```diff + export interface MyService { +- oldMethod(): void; ++ oldMethod(): Promise; + } +``` + #### Type Contract Direction An important distinction to make when looking at changes to an API Report is the direction of the contract of a changed type, that is, whether it's used as input or output from the user's point of view. In the next two sections we'll dive into the different directions of a type contract, and how it affects whether a change is breaking or not. diff --git a/app-config.yaml b/app-config.yaml index 69a1207365..ef133491af 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -1,7 +1,6 @@ app: title: Backstage Example App baseUrl: http://localhost:3000 - googleAnalyticsTrackingId: # UA-000000-0 #datadogRum: # clientToken: '123456789' # applicationId: qwerty diff --git a/contrib/chart/backstage/templates/backstage-app-config.yaml b/contrib/chart/backstage/templates/backstage-app-config.yaml index f06e47feab..061fc3285b 100644 --- a/contrib/chart/backstage/templates/backstage-app-config.yaml +++ b/contrib/chart/backstage/templates/backstage-app-config.yaml @@ -13,7 +13,6 @@ metadata: data: APP_CONFIG_app_baseUrl: {{ .Values.appConfig.app.baseUrl | quote | quote }} APP_CONFIG_app_title: {{ .Values.appConfig.app.title | quote | quote }} - APP_CONFIG_app_googleAnalyticsTrackingId: {{ .Values.appConfig.app.googleAnalyticsTrackingId | quote | quote }} APP_CONFIG_backend_baseUrl: {{ .Values.appConfig.backend.baseUrl | quote | quote }} APP_CONFIG_backend_cors_origin: {{ .Values.appConfig.backend.cors.origin | quote | quote }} APP_CONFIG_techdocs_storageUrl: {{ .Values.appConfig.techdocs.storageUrl | quote | quote }} diff --git a/contrib/chart/backstage/values.yaml b/contrib/chart/backstage/values.yaml index 6ffe076e57..cd80fd954b 100644 --- a/contrib/chart/backstage/values.yaml +++ b/contrib/chart/backstage/values.yaml @@ -92,7 +92,6 @@ appConfig: app: baseUrl: https://demo.example.com title: Backstage - googleAnalyticsTrackingId: backend: baseUrl: https://demo.example.com listen: diff --git a/contrib/docker/devops/Dockerfile b/contrib/docker/devops/Dockerfile index a7c194618a..8703b2ab48 100644 --- a/contrib/docker/devops/Dockerfile +++ b/contrib/docker/devops/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE_TAG=14-alpine +ARG IMAGE_TAG=16-alpine FROM node:${IMAGE_TAG} diff --git a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild index 41f931544f..053b4fb492 100644 --- a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild +++ b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild @@ -35,7 +35,7 @@ -FROM node:14-buster AS build +FROM node:16-buster AS build RUN mkdir /app COPY . /app diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 6c5fabd709..49b6ae0a4d 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -4,19 +4,15 @@ The Backstage backend APIs are by default available without authentication. To a API requests from frontend plugins include an authorization header with a Backstage identity token acquired when the user logs in. By adding a middleware that verifies said token to be valid and signed by Backstage, non-authenticated requests can be blocked with a 401 Unauthorized response. -**NOTE**: Enabling this means that Backstage will stop working for guests, as no token is issued for them. +**NOTE**: Enabling this means that Backstage will stop working for guests, as no token is issued for them. If you have not done so already, you will also need to implement [service-to-service auth](https://backstage.io/docs/auth/service-to-service-auth). As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire). Create `packages/backend/src/authMiddleware.ts`: ```typescript -import { SingleHostDiscovery } from '@backstage/backend-common'; import type { Config } from '@backstage/config'; -import { - getBearerTokenFromAuthorizationHeader, - IdentityClient, -} from '@backstage/plugin-auth-node'; +import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; import { NextFunction, Request, Response, RequestHandler } from 'express'; import { decodeJwt } from 'jose'; import { URL } from 'url'; @@ -45,11 +41,6 @@ export const createAuthMiddleware = async ( config: Config, appEnv: PluginEnvironment, ) => { - const discovery = SingleHostDiscovery.fromConfig(config); - const identity = IdentityClient.create({ - discovery, - issuer: await discovery.getExternalBaseUrl('auth'), - }); const baseUrl = config.getString('backend.baseUrl'); const secure = baseUrl.startsWith('https://'); const cookieDomain = new URL(baseUrl).hostname; @@ -61,13 +52,13 @@ export const createAuthMiddleware = async ( try { const token = getBearerTokenFromAuthorizationHeader(req.headers.authorization) || - (req.cookies.token as string | undefined); + (req.cookies?.token as string | undefined); if (!token) { res.status(401).send('Unauthorized'); return; } try { - req.user = await identity.authenticate(token); + req.user = await appEnv.identity.getIdentity({ request: req }); } catch { await appEnv.tokenManager.authenticate(token); } @@ -180,7 +171,12 @@ export async function setTokenCookie(url: string, identityApi: IdentityApi) { ``` ```typescript -// packages/app/src/App.tsx from a create-app deployment +// required types and packages for example below + +import type { IdentityApi } from '@backstage/core-plugin-api'; +import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; + +// additional packages/app/src/App.tsx from a create-app deployment import { setTokenCookie } from './cookieAuth'; diff --git a/contrib/docs/tutorials/aws-deployment.md b/contrib/docs/tutorials/aws-deployment.md index 3a76da2ed3..a767d292bf 100644 --- a/contrib/docs/tutorials/aws-deployment.md +++ b/contrib/docs/tutorials/aws-deployment.md @@ -40,7 +40,7 @@ image](https://backstage.io/docs/getting-started/deployment-docker) documentation to build a new Backstage Docker image: ```shell -$ yarn build +$ yarn build:backend $ yarn build-image --tag backstage ``` diff --git a/contrib/scaffolder/README.md b/contrib/scaffolder/README.md new file mode 100644 index 0000000000..e22c4b391f --- /dev/null +++ b/contrib/scaffolder/README.md @@ -0,0 +1,15 @@ +# Scaffolder contrib tools + +## Testing Templates with Dry-run + +Scaffolder templates support anything that backstage.io and custom actions can do, so testing them is hard without actually running the instance of Backstage that they're designed for. + +Please leave [feedback on the RFC](https://github.com/backstage/backstage/issues/14280) on your experience with this approach. + +The [command line script](template-testing-dry-run.md) might offer a way for you to do so using the dry-run API used for the Template Editor. Run it against a running instance, either locally or remote, and use it like + +```sh +scaffolder-dry http://localhost:7007/ template-directory values.yml output-directory +``` + +If you're using backend permissions, pass a front-end auth token from a current browser session via `--token $FRONTEND_TOKEN`. diff --git a/contrib/scaffolder/template-testing-dry-run.md b/contrib/scaffolder/template-testing-dry-run.md new file mode 100644 index 0000000000..70e0c572ab --- /dev/null +++ b/contrib/scaffolder/template-testing-dry-run.md @@ -0,0 +1,150 @@ +```js +/* + * Copyright 2022 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. + */ + +/** + * A CLI that helps you test Backstage software templates + * + * @packageDocumentation + */ + +import { dirname, join, relative } from 'node:path'; +import { readFile, writeFile } from 'node:fs/promises'; +import { gzipSync } from 'node:zlib'; +import { ensureDir } from 'fs-extra'; +import { program } from 'commander'; +import fetch from 'node-fetch'; +import ora from 'ora'; +import readdir from 'recursive-readdir'; +import { parse } from 'yaml'; +import { version } from '../../../package.json'; +import type { ScaffolderDryRunResponse } from '@backstage/plugin-scaffolder'; + +const loadDirectoryContents = async (template_path: string) => { + const spinner = ora('Loading template').start(); + const files = await await readdir(template_path, ['.git']); + const contents = await Promise.all( + files.map(async p => { + return { + path: relative(template_path, p), + base64Content: (await readFile(p)).toString('base64'), + }; + }), + ); + spinner.succeed(); + return contents; +}; + +const writeResultContents = async ( + root: string, + directoryContents: ScaffolderDryRunResponse['directoryContents'], +) => { + const directories = new Set( + directoryContents.map(({ path }) => dirname(join(root, path))), + ); + await Promise.all(Array.from(directories).map(d => ensureDir(d))); + await Promise.all( + directoryContents.map(async ({ path, base64Content, executable }) => + writeFile(join(root, path), Buffer.from(base64Content, 'base64'), { + mode: executable ? 0o755 : 0o644, + }), + ), + ); +}; + +const api = async ( + bodyObj: Record, + { baseURL, token }: { baseURL: string; token: string | false }, +) => { + const body = gzipSync(JSON.stringify(bodyObj)); + return fetch(new URL('/api/scaffolder/v2/dry-run', baseURL), { + method: 'POST', + headers: { + Authorization: `Bearer ${token || ''}`, + 'Content-Type': 'application/json', + 'Content-Encoding': 'gzip', + }, + body, + }); +}; + +const handle = async ( + baseURL: string, + template_path: string, + data: string, + target: string, + { token }: { token: string | false }, +) => { + const directoryContents = await loadDirectoryContents(template_path); + const values = parse(await readFile(data, 'utf-8')); + const secrets = {}; + const template = parse( + await readFile(`${template_path}/template.yaml`, 'utf-8'), + ); + const response = await api( + { + directoryContents, + values, + secrets, + template, + }, + { baseURL, token }, + ); + if (!response.ok) { + const contentType = response.headers.get('content-type'); + if (contentType?.startsWith('application/json')) { + const responseData = await response.json(); + if (responseData.error) { + throw responseData.error; + } + if (responseData.errors) { + throw responseData.errors; + } + throw responseData; + } + throw await response.text(); + } + const { log, directoryContents: resultContents } = + (await response.json()) as ScaffolderDryRunResponse; + for (const logEntry of log) { + console.log(logEntry.body.message); + } + await writeResultContents(target, resultContents); +}; + +const main = async (argv: string[]) => { + program + .name('backstage-scaffolder') + .version(version) + .description('Creates a dry-run output of a given template') + .option('-t, --token ', 'JWT to use for auth') + .argument('url', 'URL of your Backstage instance') + .argument('template-path', 'Source directory of template') + .argument('data-path', 'YAML file with input to render') + .argument('target', 'Output directory') + .action(handle); + + await program.parseAsync(argv); + process.exit(); +}; + +process.on('unhandledRejection', rejection => { + console.error(rejection); + process.exit(1); +}); + +main(process.argv); +``` diff --git a/cypress/README.md b/cypress/README.md index 15338fe371..4212af398c 100644 --- a/cypress/README.md +++ b/cypress/README.md @@ -24,7 +24,7 @@ necessary environment variables: ```sh yarn tsc -yarn build +yarn build:backend yarn workspace example-backend build-image docker run -p 7007:7007 example-backend ``` diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index d9b4869ecd..9c4a63b76c 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -10,7 +10,7 @@ "incremental": true, "isolatedModules": true, "jsx": "react", - "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2020", "ESNext.Promise"], + "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2021", "ESNext.Promise"], "module": "ESNext", "moduleResolution": "node", "noEmit": true, @@ -31,7 +31,7 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "stripInternal": true, - "target": "ES2019", + "target": "ES2021", "types": ["node", "cypress"] } } diff --git a/cypress/yarn.lock b/cypress/yarn.lock index 3b1358156e..07249a29fc 100644 --- a/cypress/yarn.lock +++ b/cypress/yarn.lock @@ -414,8 +414,8 @@ __metadata: linkType: hard "cypress@npm:^10.0.0": - version: 10.10.0 - resolution: "cypress@npm:10.10.0" + version: 10.11.0 + resolution: "cypress@npm:10.11.0" dependencies: "@cypress/request": ^2.88.10 "@cypress/xvfb": ^1.2.4 @@ -461,7 +461,7 @@ __metadata: yauzl: ^2.10.0 bin: cypress: bin/cypress - checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2 + checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2 languageName: node linkType: hard diff --git a/docs/assets/software-templates/custom-field-explorer.png b/docs/assets/software-templates/custom-field-explorer.png new file mode 100644 index 0000000000..1af897ac8c Binary files /dev/null and b/docs/assets/software-templates/custom-field-explorer.png differ diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index 01c18f04cd..a43e2307e6 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -49,7 +49,7 @@ the user to initiate a login. This login request is done to the `/start` endpoint which is handled by the `start` method. The `start` method re-directs to the external auth provider who authenticates -the request and re-directs the request to the `/frame/handler` endpoint, which +the request and re-directs the request to the `/handler/frame` endpoint, which is handled by the `frameHandler` method. The `frameHandler` returns an HTML response, containing a script that does a diff --git a/docs/auth/github/provider.md b/docs/auth/github/provider.md index a8c6020cae..353b8ebe08 100644 --- a/docs/auth/github/provider.md +++ b/docs/auth/github/provider.md @@ -24,7 +24,7 @@ Settings for local development: - Application name: Backstage (or your custom app name) - Homepage URL: `http://localhost:3000` -- Authorization callback URL: `http://localhost:7007/api/auth/github` +- Authorization callback URL: `http://localhost:7007/api/auth/github/handler/frame` ## Configuration diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 1ebfcaf15b..90d267b327 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -26,6 +26,7 @@ auth: providers: gcp-iap: audience: '/projects//global/backendServices/' + jwtHeader: x-custom-header # Optional: Only if you are using a custom header for the IAP JWT ``` You can find the project number and service ID in the Google Cloud Console. diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index d96c9fc45a..a65f3d7899 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -49,7 +49,7 @@ A user identity within Backstage is built up from two pieces of information, a user [entity reference](../features/software-catalog/references.md), and a set of ownership entity references. When a user signs in, a Backstage token is generated with these two pieces of information, -which is then used to identity the user within the Backstage ecosystem. +which is then used to identify the user within the Backstage ecosystem. The user entity reference should uniquely identify the logged in user in Backstage. It is encouraged that a matching user entity also exists within the Software Catalog, diff --git a/docs/auth/index.md b/docs/auth/index.md index ab04d3ed87..5702e96cee 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -258,9 +258,58 @@ Passport-supported authentication method. ## Custom ScmAuthApi Implementation -If you are using any custom authentication providers, like for example one for GitHub Enterprise, then you are likely to need a custom implementation of the [`ScmAuthApi`](https://backstage.io/docs/reference/integration-react.scmauthapi). It is an API used to authenticate towards different SCM systems in a generic way, based on what resource is being accessed, and is used for example by the Scaffolder (Software Templates) and Catalog Import plugins. +The default `ScmAuthAPi` provides integrations for `github`, `gitlab`, `azure` and `bitbucket` and is created by the following code in `packages/app/src/apis.ts`: -To set up a custom `ScmAuthApi` implementation, you'll need to add an API factory entry to `packages/app/src/apis.ts`. The following example shows an implementation that supports both public GitHub via `githubAuthApi` as well as a GitHub Enterprise installation hosted at `ghe.example.com` via `gheAuthApi`: +```ts +ScmAuth.createDefaultApiFactory(); +``` + +If you require only a subset of these integrations, then you will need a custom implementation of the [`ScmAuthApi`](https://backstage.io/docs/reference/integration-react.scmauthapi). It is an API used to authenticate different SCM systems generically, based on what resource is being accessed, and is used for example, by the Scaffolder (Software Templates) and Catalog Import plugins. + +The first step is to remove the code that creates the default providers. + +```diff + import { + ScmIntegrationsApi, + scmIntegrationsApiRef, ++ ScmAuth, + } from '@backstage/integration-react'; + + export const apis: AnyApiFactory[] = [ +... ++ ScmAuth.createDefaultApiFactory(), +... + ]; +``` + +Then replace it with something like this, which will create an `ApiFactory` with only a github provider. + +```ts +export const apis: AnyApiFactory[] = [ + createApiFactory({ + api: scmAuthApiRef, + deps: { + githubAuthApi: githubAuthApiRef, + }, + factory: ({ githubAuthApi }) => + ScmAuth.merge( + ScmAuth.forGithub(githubAuthApi), + ), + }); +``` + +If you use any custom authentication integrations, a new provider can be added to the `ApiFactory`. + +The first step is to create a new authentication ref, which follows the naming convention of `xxxAuthApiRef`. The example below is for a new GitHub enterprise integration which can be defined either inside the app itself if it's only used for this purpose or inside a common internal package for APIs, such as `@internal/apis`: + +```ts +const gheAuthApiRef: ApiRef = + createApiRef({ + id: 'internal.auth.ghe', + }); +``` + +The new ref is then used to add a new provider to the ApiFactory: ```ts createApiFactory({ @@ -278,3 +327,14 @@ createApiFactory({ ), }); ``` + +Finally, you also need to add and configure another provider to the `auth-backend` using the provider ID, which in this example is `ghe`: + +```ts +import { providers } from '@backstage/plugin-auth-backend'; + +// Add the following options to `createRouter` in packages/backend/src/plugins/auth.ts +providerFactories: { + ghe: providers.github.create(), +}, +``` diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index cbd24867b7..583139cff1 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -46,11 +46,18 @@ The Microsoft provider is a structure with three configuration keys: - `clientSecret`: Secret, found on App Registration > Certificates & secrets - `tenantId`: Directory (tenant) ID, found on App Registration > Overview -In order to finish signing a user in from Azure, the Backstage backend must -fetch their information from graph.microsoft.com (as seen in [this source -code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)), -so ensure that your Backstage backend has connectivity to this host. -Otherwise users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. +## Outbound Network Access + +If your environment has restrictions on outgoing access (e.g. through +firewall rules), make sure your Backstage backend has access to the following +hosts: + +- `login.microsoftonline.com`, to get and exchange authorization codes and access + tokens +- `graph.microsoft.com`, to fetch user profile information (as seen + in [this source + code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). + If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. ## Adding the provider to the Backstage frontend diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 04a509d316..30276a97ab 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -34,8 +34,8 @@ more efficient caching of dependencies on the host, where a single change won't bust the entire cache. The required steps in the host build are to install dependencies with -`yarn install`, generate type definitions using `yarn tsc`, and build all -packages with `yarn build`. +`yarn install`, generate type definitions using `yarn tsc`, and build the backend +package with `yarn build:backend`. > NOTE: If you created your app prior to 2021-02-18, follow the > [migration step](https://github.com/backstage/backstage/releases/tag/release-2021-02-18) @@ -49,8 +49,8 @@ yarn install --frozen-lockfile # tsc outputs type definitions to dist-types/ in the repo root, which are then consumed by the build yarn tsc -# Build all packages and in the end bundle them all up into the packages/backend/dist folder. -yarn build +# Build the backend, which bundles it all up into the packages/backend/dist folder. +yarn build:backend ``` Once the host build is complete, we are ready to build our image. The following @@ -108,10 +108,13 @@ root of the repo to speed up the build by reducing build context size: ```text .git +.yarn/cache +.yarn/install-state.gz node_modules packages/*/src packages/*/node_modules plugins +*.local.yaml ``` With the project built and the `.dockerignore` and `Dockerfile` in place, we are diff --git a/docs/dls/component-design-guidelines.md b/docs/dls/component-design-guidelines.md new file mode 100644 index 0000000000..65eef4c057 --- /dev/null +++ b/docs/dls/component-design-guidelines.md @@ -0,0 +1,108 @@ +--- +id: component-design-guidelines +title: Component Design Guidelines +description: Documentation on Design +--- + +Be it a new component contribution, or plugin specific components, you'll want +to follow these guidelines. We'll cover the three main subjects that define the +general look and feel of your components, all of which build on top of the +Material-UI theme features: + +- Layout +- Color palette +- Typography + +## 🏗️ Layout + +Layout refers to how you organize or stack content. Whenever possible, we want +to use Backstage's components (check the [Storybook][1] for a list and demo) +first, and otherwise fall back to Material-UI components (check the [MUI docs][2]). + +If none of these fit your layout needs, then you can build your own components. +However, using HTML+CSS directly is not recommended; it's better to use MUI +layout components to make your layout theme aware, meaning if someone changes +the theme, your layout would react to those changes without requiring updates +to your code. + +Specifically you want to look at these components that make use of the +`theme.spacing()` function for margins, paddings and positions, as well as +color palette and typography: + +- [Container][3] mostly at page level +- [Box][4] like a div that can be customized a lot +- [Grid][5] for flexible grid layouts +- [Paper][6] The base of a card, like it's background & padding on the borders +- [Card][7] Card with support for title, description, buttons, images... + +## Color palette + +If you're using an existing component and want to tweak the colors it uses in +general in the whole application, you can use a [Custom Theme][10] to override +specific styles for that component, that includes paddings, margins and colors. + +However when making a component from scratch you'll need to reference the theme +as much as possible, make sure to use the theme's color palette. Most Backstage +components and all MUI components should use the theme's color palette by default, +so unless you need explicit control on the color of a component (say when the +component was designed to use the primary color but you want to use the +secondary color instead), then the easiest way to access the color palette is +to [Override the Component Styles][11] as suggested by Backstage. + +It's not a very common use case to override a theme color in a MUI component +but let's say you have a custom Sidebar component with a Paper component that +highlights its content with a different color for a side menu or something +(usually you use the elevation, but maybe the designer wanted a colorful app). +You can use the theme like this: + +```tsx +import { makeStyles, Paper } from '@material-ui/core'; + +const useStyles = makeStyles((theme: Theme) => ({ + sidebarPaper: { + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + }, +})); + +export function Sidebar({ children }) { + const { sidebarPaper } = useStyles(); + return {children}; +} +``` + +Here is a link to the [Default Palette values][8] you can use, the tokens will +be the same, what changes are the colors associated with those depending on your +app theme color palette, there's also a [Default Theme Explorer][12] to look +which tokens you can use as reference from the compiled theme. + +## Typography + +Most of the time the components from MUI will use the `` component +which will use the theme's typography properties like font family, size, weight +and appropriate color from the palette for the context of that component. This applies for example to +buttons that use white font color for contained buttons, or the respective color +passed on via props when not outlined for proper contrast (buttons in dark +theme adapt properly by using a dark font instead of white). + +However for those cases where the parent component of the content doesn't handle +the text, like when the parent component is a layout one, you use typography +component instead of the HTML counterparts, usually used for titles and +paragraphs but it is valid for any type of text. + +Check the [Typography docs][9] for information on how to install, use, +customize semantic elements and specially the recommendations about +accessibility. + +[1]: http://backstage.io/storybook +[2]: https://v4.mui.com/getting-started/supported-components/ +[3]: https://v4.mui.com/components/container/ +[4]: https://v4.mui.com/components/box/ +[5]: https://v4.mui.com/components/grid/ +[6]: https://v4.mui.com/components/paper/ +[7]: https://v4.mui.com/components/cards/ +[8]: https://v4.mui.com/customization/palette/#default-values +[9]: https://v4.mui.com/customization/typography/ +[10]: https://backstage.io/docs/getting-started/app-custom-theme +[11]: https://backstage.io/docs/getting-started/app-custom-theme#overriding-backstage-and-material-ui-components-styles +[12]: https://v4.mui.com/customization/default-theme/#explore diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index 5b4e2fa716..616991123d 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -102,7 +102,7 @@ If either existing don't work for your use-case, it is possible to implement a custom [KubernetesClustersSupplier](https://backstage.io/docs/reference/plugin-kubernetes-backend.kubernetesclusterssupplier). -Change the following in `packages/backend/src/plugin/kubernetes.ts`: +Change the following in `packages/backend/src/plugins/kubernetes.ts`: ```diff -import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend'; diff --git a/docs/features/search/getting-started.md b/docs/features/search/getting-started.md index 71b9c276d9..726d1557d0 100644 --- a/docs/features/search/getting-started.md +++ b/docs/features/search/getting-started.md @@ -68,7 +68,7 @@ export const searchPage = ( switch (result.type) { case 'software-catalog': return ( - { It's good practice for search results to highlight information that was used to return it in the first place! The code below highlights how you might specify a -custom result item component, using the `` component as +custom result item component, using the `` component as an example: ```tsx {7-13} @@ -265,7 +265,7 @@ an example: switch (result.type) { case 'software-catalog': return ( - { + await return axios.get(this.getStaffUrl) + } + + public async connect(connection: EntityProviderConnection): Promise { + this.connection = connection + } + + async run(): Promise { + if (!this.connection) { + throw new Error('User Connection Not initialized') + } + + const userResources: UserEntity[] = [] + const staff = await this.getAllStaff() + + for (const user of staff) { + // we can add any links here in this case it would be adding a slack link to the users so you can directly slack them. + const links = + user.slackUserId != null && user.slackUserId.length > 0 + ? [ + { + url: `slack://user?team=${this.slackTeam}&id=${user.slackUserId}`, + title: 'Slack', + icon: 'message', + }, + ] + : undefined + const userEntity: UserEntity = { + kind: 'User', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { + [ANNOTATION_LOCATION]: 'hr-user-https://www.hrurl.com/', + [ANNOTATION_ORIGIN_LOCATION]: 'hr-user-https://www.hrurl.com/', + }, + links, + // name of the entity + name: kebabCase(user.displayName), + // name for display purposes could be anything including email + title: user.displayName, + }, + spec: { + profile: { + displayName: user.displayName, + email: user.email, + picture: user.photoUrl, + }, + memberOf: [], + }, + } + + userResources.push(userEntity) + } + + await this.connection.applyMutation({ + type: 'full', + entities: userResources.map((entity) => ({ + entity, + locationKey: 'hr-user-https://www.hrurl.com/', + })), + }) +} + +``` + ## Custom Processors The other possible way of ingesting data into the catalog is through the use of diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md new file mode 100644 index 0000000000..c44ee39269 --- /dev/null +++ b/docs/features/software-templates/input-examples.md @@ -0,0 +1,195 @@ +--- +id: input-examples +title: Input Examples +description: Some examples to use in your template +--- + +All the examples on this page you can test using _create/edit_ from your Backstage installation. + +It is important to remember that all examples are based on [react-jsonschema-form](https://rjsf-team.github.io/react-jsonschema-form/). + +## Simple text input + +### Simple input with basic validations + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Simple text input + type: string + description: Description about input + maxLength: 8 + pattern: '^([a-zA-Z][a-zA-Z0-9]*)(-[a-zA-Z0-9]+)*$' + ui:autofocus: true + ui:help: 'Hint: additional description...' +``` + +### Multi line text input + +```yaml +parameters: + - title: Fill in some steps + properties: + multiline: + title: Text area input + type: string + description: Insert your multi line string + ui:widget: textarea + ui:options: + rows: 10 + ui:help: 'Hint: Make it strong!' + ui:placeholder: | + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: backstage + spec: + type: library + owner: CNCF + lifecycle: experimental +``` + +## Arrays options + +### Array with custom titles + +```yaml +parameters: + - title: Fill in some steps + properties: + volume_type: + title: Volume Type + type: string + description: The volume type to be used + default: gp2 + enum: + - gp2 + - gp3 + - io1 + - io2 + - sc1 + - st1 + - standard + enumNames: + - 'General Purpose SSD (gp2)' + - 'General Purpose SSD (gp3)' + - 'Provisioned IOPS (io1)' + - 'Provisioned IOPS (io2)' + - 'Cold HDD (sc1)' + - 'Throughput Optimized HDD (st1)' + - 'Magnetic (standard)' +``` + +### A multiple choices list + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Select environments + type: array + items: + type: string + enum: + - production + - staging + - development + uniqueItems: true + ui:widget: checkboxes +``` + +### Array with another types + +```yaml +parameters: + - title: Fill in some steps + properties: + arrayObjects: + title: Array with custom objects + type: array + ui:options: + addable: false + orderable: false + removable: false + items: + type: object + properties: + array: + title: Array string with default value + type: string + default: value3 + enum: + - value1 + - value2 + - value3 + flag: + title: Boolean flag + type: boolean + ui:widget: radio + someInput: + title: Simple text input + type: string +``` + +## Boolean options + +### Boolean + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Checkbox boolean + type: boolean +``` + +### Boolean Yes or No options + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Yes or No options + type: boolean + ui:widget: radio +``` + +### Boolean multiple options + +```yaml +parameters: + - title: Fill in some steps + properties: + name: + title: Select features + type: array + items: + type: boolean + enum: + - 'Enable scraping' + - 'Enable HPA' + - 'Enable cache' + uniqueItems: true + ui:widget: checkboxes +``` + +## Use parameters as condition in steps + +```yaml +- name: Only development environments + if: ${{ parameters.environment === "staging" and parameters.environment === "development" }} + action: debug:log + input: + message: 'development step' + +- name: Only production environments + if: ${{ parameters.environment === "prod" or parameters.environment === "production" }} + action: debug:log + input: + message: 'production step' +``` diff --git a/docs/features/software-templates/writing-custom-field-extensions.md b/docs/features/software-templates/writing-custom-field-extensions.md index b4c4d2d4ce..1d28bd5db9 100644 --- a/docs/features/software-templates/writing-custom-field-extensions.md +++ b/docs/features/software-templates/writing-custom-field-extensions.md @@ -181,3 +181,102 @@ const CustomFieldExtension = scaffolderPlugin.provide( }) ); ``` + +## Previewing Custom Field Extensions + +You can preview custom field extensions you write in the Backstage UI using the Custom Field Explorer +(accessible via the `/create/edit` route by default): + +![Custom Field Explorer](../../assets/software-templates/custom-field-explorer.png) + +In order to make your new custom field extension available in the explorer you will have to define a +JSON schema that describes the input/output types on your field like in the following example: + +```tsx +//packages/app/src/scaffolder/MyCustomExtensionWithOptions/MyCustomExtensionWithOptions.tsx +export const MyCustomExtensionWithOptionsSchema = { + uiOptions: { + type: 'object', + properties: { + focused: { + description: 'Whether to focus this field', + type: 'boolean', + }, + }, + }, + returnValue: { type: 'string' }, +}; + +export const MyCustomExtensionWithOptions = ({ + onChange, + rawErrors, + required, + formData, +}: FieldExtensionComponentProps) => { + return ( + 0 && !formData} + onChange={onChange} + focused={focused} + /> + ); +}; +``` + +```tsx +// packages/app/src/scaffolder/MyCustomExtensionWithOptions/extensions.ts +... +import { MyCustomExtensionWithOptions, MyCustomExtensionWithOptionsSchema } from './MyCustomExtensionWithOptions'; + +export const MyCustomFieldWithOptionsExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + name: 'MyCustomExtensionWithOptions', + component: MyCustomExtensionWithOptions, + schema: MyCustomExtensionWithOptionsSchema, + }), +); +``` + +We recommend using a library like [zod](https://github.com/colinhacks/zod) to define your schema +and the provided `makeFieldSchemaFromZod` helper utility function to generate both the JSON schema +and type for your field props to preventing having to duplicate the definitions: + +```tsx +//packages/app/src/scaffolder/MyCustomExtensionWithOptions/MyCustomExtensionWithOptions.tsx +... +import { z } from 'zod'; +import { makeFieldSchemaFromZod } from '@backstage/plugin-scaffolder'; + +const MyCustomExtensionWithOptionsFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + focused: z + .boolean() + .optional() + .describe('Whether to focus this field'), + }), +); + +export const MyCustomExtensionWithOptionsSchema = MyCustomExtensionWithOptionsFieldSchema.schema; + +type MyCustomExtensionWithOptionsProps = typeof MyCustomExtensionWithOptionsFieldSchema.type; + +export const MyCustomExtensionWithOptions = ({ + onChange, + rawErrors, + required, + formData, +}: MyCustomExtensionWithOptionsProps) => { + return ( + 0 && !formData} + onChange={onChange} + focused={focused} + /> + ); +}; +``` diff --git a/docs/getting-started/contributors.md b/docs/getting-started/contributors.md index 9154eae4d1..1bf3d6bc7d 100644 --- a/docs/getting-started/contributors.md +++ b/docs/getting-started/contributors.md @@ -101,7 +101,8 @@ yarn workspace @backstage/plugin-api-docs start # Serve api-docs plugin only, al yarn tsc # Run typecheck, use --watch for watch mode yarn tsc:full # Run full type checking, for example without skipLibCheck, use in CI -yarn build # Build published versions of packages, depends on tsc +yarn build:backend # Build the backend package, depends on tsc +yarn build:all # Build published versions of packages, depends on tsc yarn lint # lint packages that have changed since later commit on origin/master yarn lint:all # lint all packages diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 477467bb88..16e361a19f 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -34,6 +34,7 @@ guide to do a repository-based installation. - [Package manager](https://nodejs.org/en/download/package-manager/) - [Using NodeSource packages](https://github.com/nodesource/distributions/blob/master/README.md) - `yarn` [Installation](https://classic.yarnpkg.com/en/docs/install) + - You will need to use Yarn classic to create a new project, but it can then be [migrated to Yarn 3](../tutorials/yarn-migration.md) - `docker` [installation](https://docs.docker.com/engine/install/) - `git` [installation](https://github.com/git-guides/install-git) - If the system is not directly accessible over your network the following ports diff --git a/docs/getting-started/running-backstage-locally.md b/docs/getting-started/running-backstage-locally.md index 7cc6f6be6a..e7e96316f4 100644 --- a/docs/getting-started/running-backstage-locally.md +++ b/docs/getting-started/running-backstage-locally.md @@ -21,12 +21,12 @@ This is made easy with a version manager such as # Installing current LTS release nvm install --lts > Installing latest LTS version. -> Downloading and installing node v14.15.1... -> Now using node v14.15.1 (npm v6.14.8) +> Downloading and installing node v16.16.0... +> Now using node v16.16.0 (npm v8.11.0) # Checking your version node --version -> v14.15.1 +> v16.16.0 ``` - Yarn @@ -41,47 +41,38 @@ locally to use features like Software Templates and TechDocs. Please refer to the [installation instructions for Docker](https://docs.docker.com/engine/install/). -## Clone and Build +## Clone and Install To get up and running with a local Backstage to evaluate it, let's clone it off -of GitHub and run an initial build. +of GitHub and run an initial install. ```bash # Start from your local development folder -git clone --depth 1 git@github.com:backstage/backstage.git +git clone --depth 1 https://github.com/backstage/backstage.git cd backstage -# Fetch our dependencies and run an initial build +# Install our dependencies yarn install -yarn tsc -yarn build ``` Phew! Now you have a local repository that's ready to run and to add any open source contributions into. We are now going to launch two things: an example Backstage frontend app, and an -example Backstage backend that the frontend talks to. You are going to need two -terminal windows, both starting from the Backstage project root. - -In the first window, run +example Backstage backend that the frontend talks to. These can both be launched +through the following command: ```bash -# From your Backstage root directory -yarn --cwd packages/backend start +# From your Backstage root directory, launches both the frontend and backend +yarn dev ``` -That starts up a backend instance on port 7007. +If you prefer to run the frontend and backend separately, you can instead use `yarn start` +and `yarn start-backend` in two separate terminal windows. -In the other window, we will then launch the frontend. This command is run from -the project root, not inside the backend directory. - -```bash -yarn start -``` - -That starts up the frontend on port 3000, and should automatically open a -browser window showing it. +Which ever way you choose, you will now have a backend instance running on port 7007, +and the frontend running on port 3000. A browser window should also automatically open, +showing the frontend. ## Authentication diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 99c517b568..acb43db182 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -101,7 +101,7 @@ To grant the managed identity the same permissions as mentioned in _App Registra ## Filtering imported Users and Groups By default, the plugin will import all users and groups from your directory. -This can be customized through filters and search queries. +This can be customized through [filters](https://learn.microsoft.com/en-us/graph/filter-query-parameter) and [search](https://learn.microsoft.com/en-us/graph/search-query-parameter) queries. ### Groups @@ -228,6 +228,17 @@ export async function myOrganizationTransformer( ## Troubleshooting +### No data + +First check your logs for the message `Reading msgraph users and groups`. +If you don't see this, check you've registered the provider, and that the schedule is valid + +If you see a log entry `Read 0 msgraph users and 0 msgraph groups`, check your search and filter arguments. + +If you see the start message (`Reading msgraph users and groups`) but no end message (`Read X msgraph users and Y msgraph groups`), then it is likely the job is taking a long time due to a large volume of data. +The default behavior is to import all users and groups, which is often more data than needed. +Try importing a smaller set of data (e.g. `filter: displayName eq 'John Smith'`). + ### Authentication / Token Errors See [Troubleshooting Azure Identity Authentication Issues](https://aka.ms/azsdk/js/identity/troubleshoot) diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 9b9bc4ecde..f6ceab9ff7 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -24,10 +24,12 @@ package. yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-bitbucket-cloud ``` +### Installation without Events Support + And then add the entity provider to your catalog builder: ```diff - // In packages/backend/src/plugins/catalog.ts +// packages/backend/src/plugins/catalog.ts + import { BitbucketCloudEntityProvider } from '@backstage/plugin-catalog-backend-module-bitbucket-cloud'; export default async function createPlugin( @@ -37,11 +39,7 @@ And then add the entity provider to your catalog builder: + builder.addEntityProvider( + BitbucketCloudEntityProvider.fromConfig(env.config, { + logger: env.logger, -+ // optional: alternatively, configure via app-config.yaml -+ schedule: env.scheduler.createScheduledTaskRunner({ -+ frequency: { minutes: 30 }, -+ timeout: { minutes: 3 }, -+ }), ++ scheduler: env.scheduler, + }), + ); @@ -49,6 +47,62 @@ And then add the entity provider to your catalog builder: } ``` +Alternatively to the config-based schedule, you can use + +```diff +- scheduler: env.scheduler, ++ schedule: env.scheduler.createScheduledTaskRunner({ ++ frequency: { minutes: 30 }, ++ timeout: { minutes: 3 }, ++ }), +``` + +### Installation with Events Support + +Please follow the installation instructions at + +- https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md +- https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-bitbucket-cloud/README.md + +Additionally, you need to decide how you want to receive events from external sources like + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +Set up your provider + +```diff +// packages/backend/src/plugins/catalogEventBasedProviders.ts ++import { CatalogClient } from '@backstage/catalog-client'; ++import { BitbucketCloudEntityProvider } from '@backstage/plugin-catalog-backend-module-bitbucket-cloud'; + import { EntityProvider } from '@backstage/plugin-catalog-node'; + import { EventSubscriber } from '@backstage/plugin-events-node'; + import { PluginEnvironment } from '../types'; + + export default async function createCatalogEventBasedProviders( +- _: PluginEnvironment, ++ env: PluginEnvironment, + ): Promise> { + const providers: Array< + (EntityProvider & EventSubscriber) | Array + > = []; +- // add your event-based entity providers here ++ providers.push( ++ BitbucketCloudEntityProvider.fromConfig(env.config, { ++ catalogApi: new CatalogClient({ discoveryApi: env.discovery }), ++ logger: env.logger, ++ scheduler: env.scheduler, ++ tokenManager: env.tokenManager, ++ }), ++ ); + return providers.flat(); + } +``` + +**Attention:** +`catalogApi` and `tokenManager` are required at this variant +compared to the one without events support. + ## Configuration To use the entity provider, you'll need a [Bitbucket Cloud integration set up](locations.md). diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 5482733a58..9e3c450adc 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -38,7 +38,7 @@ schedule it: ```diff // packages/backend/src/plugins/catalog.ts -+import { GitHubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; ++import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; export default async function createPlugin( env: PluginEnvironment, @@ -48,7 +48,7 @@ schedule it: + // The org URL below needs to match a configured integrations.github entry + // specified in your app-config. + builder.addEntityProvider( -+ GitHubOrgEntityProvider.fromConfig(env.config, { ++ GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, @@ -97,6 +97,66 @@ that must be approved first before the changes are applied.** ![email](../../assets/integrations/github/email.png) +### Custom Transformers + +You can inject your own transformation logic to help map from GH API responses +into backstage entities. You can do this on the user and team requests to +enable you to do further processing or updates to the entities. + +To enable this you pass a function into the `GitHubOrgEntityProvider`. You can +pass a `UserTransformer`, `TeamTransformer` or both. The function is invoked +for each item (user or team) that is returned from the API. You can either +return an Entity (User or Group) or `undefined` if you do not want to import +that item. + +There is also a `defaultUserTransformer` and `defaultOrganizationTeamTransformer`. +You could use these and simply decorate the response from the default +transformation if you only need to change a few properties. + +### Resolving GitHub users via organization email + +When you authenticate users you should resolve them to an entity within the +catalog. Often the authentication you use could be a corporate SSO system that +provides you with email as a key. To enable you to find and resolve GitHub users +it's useful to also import the private domain verified emails into the User +entity in backstage. + +The integration attempts to return `organizationVerifiedDomainEmails` from the +GitHub API and makes this available as part of the object passed to +`UserTransformer`. The GitHub API will only return emails that use a domain +that's a verified domain for your GitHub Org. It also relies on the user having +configured such an email in their own account. The API will only return these +values when using GitHub App authentication and with the correct app permission +allowing access to emails. + +You can decorate the `defaultUserTransformer` to replace the org email in the +returned identity. + +```typescript +async (user, ctx): Promise => { + const entity = await defaultUserTransformer(user, ctx); + + if (entity && user.organizationVerifiedDomainEmails) { + entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0] || ''; + } + + return entity; +}, +``` + +Once you have imported the emails you can resolve users in your sign-in in +resolver using the catalog entity search via email + +```typescript +// packages/backend/src/plugins/auth.ts +ctx.signInWithCatalogUser({ + filter: { + kind: ['User'], + 'spec.profile.email': email as string, + }, +}); +``` + ## Using a Processor instead of a Provider An alternative to using the Provider for ingesting organizational entities is to diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index 3c9417268b..384ab6cf32 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -205,7 +205,7 @@ A typical plugin consists of up to five packages, two frontend ones, two backend, and one isomorphic package. All packages within the plugin must share a common prefix, typically of the form `@/plugin-`, but alternatives like `backstage-plugin-` or -`@scope/backstage-plugin-` are also valid. Along with this prefix, +`@/backstage-plugin-` are also valid. Along with this prefix, each of the packages have their own unique suffix that denotes their role. In addition to these five plugin packages it's also possible for a plugin to have additional frontend and backend modules that can be installed to enable optional @@ -249,7 +249,7 @@ however likely to change in the future. The common packages are the packages effectively depended on by all other pages. This is a much smaller set of packages but they are also very pervasive. Because the common packages are isomorphic and must execute both in the frontend and -backend, they are never allowed to depend on any of the frontend of backend +backend, they are never allowed to depend on any of the frontend or backend packages. The Backstage CLI is in a category of its own and is depended on by virtually diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md index 885a599ed8..10ffc82188 100644 --- a/docs/overview/versioning-policy.md +++ b/docs/overview/versioning-policy.md @@ -99,7 +99,7 @@ This versioning is completely decoupled from the Backstage release versioning, meaning you might for example have `@backstage/core-plugin-api` version `3.1.4` be part of the `1.12` Backstage release. -Following versioning policy applies to all packages: +The following versioning policy applies to all packages: - Breaking changes are noted in the changelog, and documentation is updated. - Breaking changes are prefixed with `**BREAKING**: ` in the changelog. @@ -120,6 +120,25 @@ For packages at version `1.0.0` or above, the following policy also applies: changes without a deprecation period, but the changes must still adhere to semver. +### Changes that are Not Considered Breaking + +There are a few changes that would typically be considered breaking changes, but +that we make exceptions for. This is both to be able to evolve the project more +rapidly, also because the alternative ends up having a bigger impact on users. + +For all Utility APIs and Backend Services that _have_ a built-in implementation, +we only consider the API stability for consumers of those interfaces. This means +that it is not considered a breaking change to break the contract for producers +of the interface. + +Changes that fall under the above rule, must be marked with +`**BREAKING PRODUCERS**:` in the changelog. + +For any case of dependency injection, it is not considered a breaking change to +add a dependency on a Utility API or Backend Service that is provided by the +framework. This includes any dependency that is provided by the +`@backstage/app-defaults` and `@backstage/backend-defaults` packages. + ### Release Stages The release stages(`@alpha`, `@beta` `@public`) refers to the @@ -144,9 +163,10 @@ following schedule for determining the [Node.js releases](https://nodejs.org/en/ - At any given point in time we support exactly two adjacent even-numbered releases of Node.js, for example v12 and v14. -- Three months before a Node.js release becomes _Active LTS_ we switch support - to that release and the previous one. This is halfway through the _Current LTS_ - cycle for that release and occurs at the end of July every year. +- Once a new Node.js release becomes _Active LTS_ we switch to support that + release and the previous one. The switch is not immediate but done as soon + as possible. You can find the Node.js version supported by each release + in the `engines` field in the root `package.json` of a new app. When we say _Supporting_ a Node.js release, that means the following: diff --git a/docs/releases/v1.8.0-changelog.md b/docs/releases/v1.8.0-changelog.md new file mode 100644 index 0000000000..4b36b01abf --- /dev/null +++ b/docs/releases/v1.8.0-changelog.md @@ -0,0 +1,2837 @@ +# Release v1.8.0 + +## @backstage/backend-common@0.16.0 + +### Minor Changes + +- a7607b5413: **BREAKING CHANGE**: The `UrlReader` interface has been updated to require that `readUrl` is implemented. `readUrl` has previously been optional to implement but a warning has been logged when calling its predecessor `read`. + The `read` method is now deprecated and will be removed in a future release. + +### Patch Changes + +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- 55227712dd: Generated development HTTPS backend certificate is now checked for expiration date instead of file age. +- d05e1841ce: This patch adds GiteaURLReader to the available classes. It currently only reads single files via gitea's public repos api +- e6ced2446a: Change to using `@keyv/memcache` now that `keyv-memcache` is deprecated +- 210a3b5668: Small update to fix compatibility with newer versions of the `keyv` library +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/integration@1.4.0 + - @backstage/types@1.0.1 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4 + - @backstage/config-loader@1.1.6 + - @backstage/errors@1.1.3 + +## @backstage/cli@0.21.0 + +### Minor Changes + +- 7539b36748: Added a new ESLint rule that restricts imports of Link from @material-ui + + The rule can be can be overridden in the following way: + + ```diff + module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + + restrictedImports: [ + + { name: '@material-ui/core', importNames: [] }, + + { name: '@material-ui/core/Link', importNames: [] }, + + ], + }); + ``` + +- 384eaa2307: Switched `tsconfig.json` to target and support `ES2021`, in line with the bump to Node.js 16 & 18. + +### Patch Changes + +- e52d6ad861: Updated the `backstage-cli` so that the `list-deprecations` command is visible and also removed the "[EXPERIMENTAL]" tag. +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- df21bbd4ad: Removed googleAnalyticsTrackingId configSchema. +- 286d474675: Minor update to the `index.html` template that updates the comment at the end to be more accurate. +- 4c16213e7d: The built-in Jest configuration now always uses the Jest environments that are bundled with the CLI by default. This avoids a situation where Jest potentially picks up an incompatible version of the environment package from a different dependency in the project. +- 4091c73e68: Updated `@swc/core` to version 1.3.9 which fixes a `.tsx` parser bug +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9c767e8f45: Updated dependency `@svgr/plugin-jsx` to `6.5.x`. + Updated dependency `@svgr/plugin-svgo` to `6.5.x`. + Updated dependency `@svgr/rollup` to `6.5.x`. + Updated dependency `@svgr/webpack` to `6.5.x`. +- Updated dependencies + - @backstage/release-manifests@0.0.7 + - @backstage/types@1.0.1 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4 + - @backstage/config-loader@1.1.6 + - @backstage/errors@1.1.3 + +## @backstage/core-app-api@1.2.0 + +### Minor Changes + +- 9b737e5f2e: Updated the React Router wiring to make use of the new `basename` property of the router components in React Router v6 stable. To implement this, a new optional `basename` property has been added to the `Router` app component, which can be forwarded to the concrete router implementation in order to support this new behavior. This is done by default in any app that does not have a `Router` component override. +- 127fcad26d: Deprecated the `homepage` config as the component that used it - `HomepageTimer` - has been removed and replaced by the `HeaderWorldClock` in the home plugin + +### Patch Changes + +- Updated dependencies + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + +## @backstage/core-components@0.12.0 + +### Minor Changes + +- fb3733e446: **BREAKING**: Removed the `HomepageTimer` as it has been replaced by the `HeaderWorldClock` in the Home plugin and was deprecated over a year ago. + +### Patch Changes + +- 5f695c219a: Set the `searchTooltip` to "Filter" to follow how the `searchPlaceholder` is set making this more consistent +- f36127f5fe: Add optional step to SimpleStepper +- b4fb5c8ecc: MissingAnnotationEmptyState now accepts either a string or an array of strings to support multiple missing annotations. +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 858986f6b6: Disable base path workaround in `Link` component when React Router v6 stable is used. +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/core-plugin-api@1.1.0 + +### Minor Changes + +- a228f113d0: The app `Router` component now accepts an optional `basename` property. + +### Patch Changes + +- Updated dependencies + - @backstage/version-bridge@1.0.2 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + +## @backstage/integration@1.4.0 + +### Minor Changes + +- d05e1841ce: This patch brings Gitea as a valid integration: target, via the ScmIntegration interface. It adds gitea to the relevant static properties (get integration by name, get integration by type) for plugins to be able to reference the same Gitea server. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. + + Deprecates: + + - `getGitHubFileFetchUrl` replaced by `getGithubFileFetchUrl` + - `GitHubIntegrationConfig` replaced by `GithubIntegrationConfig` + - `GitHubIntegration` replaced by `GithubIntegration` + - `readGitHubIntegrationConfig` replaced by `readGithubIntegrationConfig` + - `readGitHubIntegrationConfigs` replaced by `readGithubIntegrationConfigs` + - `replaceGitHubUrlType` replaced by `replaceGithubUrlType` + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-azure-sites@0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-azure-sites-common@0.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-azure-sites-backend@0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-azure-sites-common@0.1.0 + - @backstage/config@1.0.4 + +## @backstage/plugin-azure-sites-common@0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + +## @backstage/plugin-bazaar@0.2.0 + +### Minor Changes + +- 28b39e0e0e: The limit prop of BazaarOverviewCard has been removed entirely, and instead replaced with a new optional boolean prop `fullWidth`. The BazaarOverviewCard now always use full height without fixed width. Also fixed problem with link to Bazaar. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-catalog@1.6.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-github@0.2.0 + +### Minor Changes + +- 67fe5bc9a9: BREAKING: Support authenticated backends by including a server token for catalog requests. The constructor of `GithubLocationAnalyzer` now requires an instance of `TokenManager` to be supplied: + + ```diff + ... + builder.addLocationAnalyzers( + new GitHubLocationAnalyzer({ + discovery: env.discovery, + config: env.config, + + tokenManager: env.tokenManager, + }), + ); + ... + ``` + +- f64d66a45c: Added the ability for the GitHub discovery provider to validate that catalog files exist before emitting them. + + Users can now set the `validateLocationsExist` property to `true` in their GitHub discovery configuration to opt in to this feature. + This feature only works with `catalogPath`s that do not contain wildcards. + + When `validateLocationsExist` is set to `true`, the GitHub discovery provider will retrieve the object from the + repository at the provided `catalogPath`. + If this file exists and is non-empty, then it will be emitted as a location for further processing. + If this file does not exist or is empty, then it will not be emitted. + Not emitting locations that do not exist allows for far fewer calls to the GitHub API to validate locations that do not exist. + +### Patch Changes + +- 67fe5bc9a9: Properly derive Github credentials when making requests in `GithubLocationAnalyzer` to support Github App authentication +- bef063dc8d: - Make it possible to inject custom user and team transformers when configuring the `GithubOrgEntityProvider` +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-cost-insights@0.12.0 + +### Minor Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- cbe11d1e23: Tweak README +- 745e0e2228: Added support for displaying entity cost insights by implementing the new `getCatalogEntityDailyCost` that's part of the `CostInsightsApi`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + +## @backstage/plugin-events-backend@0.1.0 + +### Minor Changes + +- dc9da28abd: Support events received via HTTP endpoints at plugin-events-backend. + + The plugin provides an event publisher `HttpPostIngressEventPublisher` + which will allow you to receive events via + HTTP endpoints `POST /api/events/http/{topic}` + and will publish these to the used event broker. + + Using a provided custom validator, you can participate in the decision + which events are accepted, e.g. by verifying the source of the request. + + Please find more information at + . + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 + +## @backstage/plugin-events-backend-module-aws-sqs@0.1.0 + +### Minor Changes + +- d3ecb2382d: Adds a new module `aws-sqs` for plugin-events-backend. + + The module provides an event publisher `AwsSqsConsumingEventPublisher` + which will allow you to receive events from + an AWS SQS queue and will publish these to the used event broker. + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-events-node@0.1.0 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 + +## @backstage/plugin-events-backend-module-azure@0.1.0 + +### Minor Changes + +- 12cd94b7e9: Adds a new module `azure` to plugin-events-backend. + + The module adds a new event router `AzureDevOpsEventRouter`. + + The event router will re-publish events received at topic `azureDevOps` + under a more specific topic depending on their `$.eventType` value + (e.g., `azureDevOps.git.push`). + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.0 + +### Minor Changes + +- 6bc121bf0d: Adds a new module `bitbucket-cloud` to plugin-events-backend. + + The module adds a new event router `BitbucketCloudEventRouter`. + + The event router will re-publish events received at topic `bitbucketCloud` + under a more specific topic depending on their `x-event-key` value + (e.g., `bitbucketCloud.repo:push`). + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-events-backend-module-gerrit@0.1.0 + +### Minor Changes + +- 25f6d7bddb: Adds a new module `gerrit` to plugin-events-backend. + + The module adds a new event router `GerritEventRouter`. + + The event router will re-publish events received at topic `gerrit` + under a more specific topic depending on their `$.type` value + (e.g., `gerrit.change-merged`). + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-events-backend-module-github@0.1.0 + +### Minor Changes + +- b3a4edb885: Adds a new module `github` to plugin-events-backend. + + The module adds a new event router `GithubEventRouter`. + + The event router will re-publish events received at topic `github` + under a more specific topic depending on their `x-github-event` value + (e.g., `github.push`). + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-events-backend-module-gitlab@0.1.0 + +### Minor Changes + +- 63f7983398: Adds a new module `gitlab` to plugin-events-backend. + + The module adds a new event router `GitlabEventRouter`. + + The event router will re-publish events received at topic `gitlab` + under a more specific topic depending on their `$.event_name` value + (e.g., `gitlab.push`). + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-events-backend-test-utils@0.1.0 + +### Minor Changes + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + +## @backstage/plugin-events-node@0.1.0 + +### Minor Changes + +- dc9da28abd: Support events received via HTTP endpoints at plugin-events-backend. + + The plugin provides an event publisher `HttpPostIngressEventPublisher` + which will allow you to receive events via + HTTP endpoints `POST /api/events/http/{topic}` + and will publish these to the used event broker. + + Using a provided custom validator, you can participate in the decision + which events are accepted, e.g. by verifying the source of the request. + + Please find more information at + . + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + . + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/plugin-github-issues@0.2.0 + +### Minor Changes + +- ead285b9e4: **BREAKING**: Changed the casing of all exported types to have a lowercase "h" in "github". E.g. "GitHubIssuesPage" was renamed to "GithubIssuesPage". Please rename your imports where necessary. + +### Patch Changes + +- c8dd2a8c87: Stripping specific issues URL already present to target base issues URL. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-ilert@0.2.0 + +### Minor Changes + +- 0697af30da: Added support for multiple responders in alert list, added new tab with list to support iLert resource 'service', added new tab with list to support iLert resource 'status page' + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-kubernetes-backend@0.8.0 + +### Minor Changes + +- cbf5d11fdf: The Kubernetes errors when fetching pod metrics are now captured and returned to the frontend. + + - **BREAKING** The method `fetchPodMetricsByNamespace` in the interface `KubernetesFetcher` is changed to `fetchPodMetricsByNamespaces`. It now accepts a set of namespace strings and returns `Promise`. + - Add the `PodStatusFetchResponse` to the `FetchResponse` union type. + - Add `NOT_FOUND` to the `KubernetesErrorTypes` union type, the HTTP error with status code 404 will be mapped to this error. + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-kubernetes-common@0.4.4 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-org@0.6.0 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- 38dd29ea95: Add entity kind to the Ownership Cards. Fix the query parameters for the links of the Ownership Cards so that the catalog page actually selects the right entity kind. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-org-react@0.1.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/theme@0.2.16 + +## @backstage/plugin-scaffolder@1.8.0 + +### Minor Changes + +- edae17309e: Added props to override default Scaffolder page title, subtitle and pageTitleOverride. + Routes like `rootRouteRef`, `selectedTemplateRouteRef`, `nextRouteRef`, `nextSelectedTemplateRouteRef` were made public and can be used in your app (e.g. in custom TemplateCard component). + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. + +- 4830a3569f: Basic analytics instrumentation is now in place: + + - As users make their way through template steps, a `click` event is fired, including the step number. + - After a user clicks "Create" a `create` event is fired, including the name of the software that was just created. The template used at creation is set on the `entityRef` context key. + +- 94b7ca9c6d: Updated to use `@rjsf` packages of version `^5.0.0-beta.12` + +- 87840c8c6c: Fixed tiny grammar error in EntityNamePicker. The first letter of the description is now capitalized. + +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version + +- b2bb48a6f4: Fix the return type for the `createNextScaffodlerFieldExtension` type as before it wasn't a component type for the extension + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/integration-react@1.1.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-scaffolder-common@1.2.2 + +## @backstage/plugin-scaffolder-backend@1.8.0 + +### Minor Changes + +- ea14eb62a2: Added a set of default Prometheus metrics around scaffolding. See below for a list of metrics and an explanation of their labels: + + - `scaffolder_task_count`: Tracks successful task runs. + + Labels: + + - `template`: The entity ref of the scaffolded template + - `user`: The entity ref of the user that invoked the template run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + - `scaffolder_task_duration`: a histogram which tracks the duration of a task run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `result`: A boolean describing whether the task ran successfully + + - `scaffolder_step_count`: a count that tracks each step run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `step`: The name of the step that was run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + - `scaffolder_step_duration`: a histogram which tracks the duration of each step run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `step`: The name of the step that was run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + You can find a guide for running Prometheus metrics here: + +- 5921b5ce49: - The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project. + +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-scaffolder-common@1.2.2 + +## @backstage/plugin-sonarqube@0.5.0 + +### Minor Changes + +- 786117e98a: Fix sonarqube annotation parsing. Add content page for Sonarqube. + Removed the deprecated `plugin` export; please use `sonarQubePlugin` instead. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-splunk-on-call@0.4.0 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs@1.4.0 + +### Minor Changes + +- 5691baea69: Add ability to configure filters when using EntityListDocsGrid + + The following example will render two sections of cards grid: + + - One section for documentations tagged as `recommended` + - One section for documentations tagged as `runbook` + + ```js + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + { + title: "RunBooks Documentation", + filterPredicate: entity => + entity?.metadata?.tags?.includes('runbook') ?? false, + } + ]}} /> + ``` + +- 63705e73d9: Hide document description if not provided + +- 847fc588a6: Updated TechDocs header to include label for source code icon and updated label to reflect Kind name + +### Patch Changes + +- 9e4d8e6198: Fix logic bug that broke techdocs-cli-embedded-app +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- cbe11d1e23: Tweak README +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- 3a1a999b7b: Include query parameters when navigating to relative links in documents +- bd2aab4726: An analytics event matching the semantics of the `click` action is now captured when users click links within a TechDocs document. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/app-defaults@1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7 + +## @backstage/backend-app-api@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/errors@1.1.3 + +## @backstage/backend-defaults@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.2.3 + - @backstage/backend-plugin-api@0.1.4 + +## @backstage/backend-plugin-api@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + +## @backstage/backend-tasks@0.3.7 + +### Patch Changes + +- 30e43717c7: Deprecated the `HumanDuration` type, which should now instead be imported from `@backstage/types`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/backend-test-utils@0.1.30 + +### Patch Changes + +- e13cd3feaf: Updated dependency `msw` to `^0.48.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/cli@0.21.0 + - @backstage/backend-app-api@0.2.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 + +## @backstage/catalog-client@1.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + +## @backstage/catalog-model@1.1.3 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- Updated dependencies + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/codemods@0.1.41 + +### Patch Changes + +- 58502ec285: Updated dependency `jscodeshift` to `^0.14.0`. +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/config@1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + +## @backstage/config-loader@1.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/create-app@0.4.34 + +### Patch Changes + +- f1c3cdfb2d: Bumped create-app version. + +- df21bbd4ad: The [Analytics API](https://backstage.io/docs/plugins/analytics) is the recommended way to track usage in Backstage; an optionally installable [Google Analytics module](https://github.com/backstage/backstage/tree/master/plugins/analytics-module-ga#installation) has superseded the old app.googleAnalyticsTrackingId config and its corresponding script tags in packages/app/public/index.html. + + For an existing installation where you want to remove the redundant app.googleAnalyticsTrackingId, you should make the following adjustment to `packages/app/public/index.html`: + + ```diff + <%= config.getString('app.title') %> + - <% if (config.has('app.googleAnalyticsTrackingId')) { %> + - + - + - <% } %> + + ``` + + Additionally, you should make the following adjustment to `app-config.yaml`: + + ```diff + app: + title: Backstage Example App + baseUrl: http://localhost:3000 + - googleAnalyticsTrackingId: # UA-000000-0 + ``` + +- 4091c73e68: Updated `@swc/core` to `v1.3.9` which fixes a `.tsx` parser bug. You may want to run `yarn backstage-cli versions:bump` to get on latest version including the CLI itself. + +- 80bfac5266: Updated the create-app command to no longer require Git to be installed and configured. A git repository will only be initialized if possible and if not already in an git repository. + +- 286d474675: The `build` script in the root `package.json` has been split into two separate scripts, `build:backend` and `build:all`. This is to more accurately reflect what is being built, to avoid confusion. + + If you want to build the project for a production deployment, you will want to use `build:backend`, as this builds both the frontend and backend package. If you are not using the `app-backend` plugin you will want to add your own `build:frontend` script, to which you can pass additional configuration parameters if needed. + + The `build:all` script is useful if you simply want to check that it is possible to build all packages in the project. This might be useful as a CI check, but is generally unnecessary. + + If you want to publish the packages in your repository you can add a `build:packages` script that calls `backstage-cli repo build`. This will skip the frontend and backend packages builds, as those are quite time consuming. + + To apply these changes to an existing project, make the following change to the root `package.json` file: + + ```diff + - "build": "backstage-cli repo build --all", + + "build:backend": "yarn workspace backend build", + + "build:all": "backstage-cli repo build --all", + ``` + + There are also a couple of places where documentation has been updated, see the [upgrade helper](https://backstage.github.io/upgrade-helper/?to=1.8.0) for a full list of changes. + +- 384eaa2307: Switched Node.js version to support version 16 & 18, rather than 14 & 16. To switch the Node.js version in your own project, apply the following change to the root `package.json`: + + ```diff + "engines": { + - "node": "14 || 16" + + "node": "16 || 18" + }, + ``` + + As well as the following change to `packages/app/package.json`: + + ```diff + - "@types/node": "^14.14.32", + + "@types/node": "^16.11.26", + ``` + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. + +- 864c876e57: Fixed incorrect comments in the templated `app-config.yaml` and `app-config.production.yaml`. The `backend.listen` directive is not in fact needed to override the `backend.baseUrl`, the backend listens to all interfaces by default. The configuration has also been updated to listen to all interfaces, rather than just IPv4 ones, as this is required for Node.js v18. The production configuration now also shows the option to specify `backend.listen` as a single string. + + To apply this changes to an existing app, make the following change to `app-config.yaml`: + + ```diff + - # Uncomment the following host directive to bind to all IPv4 interfaces and + - # not just the baseUrl hostname. + - # host: 0.0.0.0 + + # Uncomment the following host directive to bind to specific interfaces + + # host: 127.0.0.1 + ``` + + And the following change to `app-config.production.yaml`: + + ```diff + - listen: + - port: 7007 + - # The following host directive binds to all IPv4 interfaces when its value + - # is "0.0.0.0". This is the most permissive setting. The right value depends + - # on your specific deployment. If you remove the host line entirely, the + - # backend will bind on the interface that corresponds to the backend.baseUrl + - # hostname. + - host: 0.0.0.0 + + # The listener can also be expressed as a single : string. In this case we bind to + + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + + listen: ':7007' + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/dev-utils@1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## @backstage/errors@1.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + +## @backstage/integration-react@1.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/release-manifests@0.0.7 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + +## @techdocs/cli@1.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-techdocs-node@1.4.2 + - @backstage/catalog-model@1.1.3 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4 + +## @backstage/test-utils@1.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7 + +## @backstage/types@1.0.1 + +### Patch Changes + +- 30e43717c7: Added the `HumanDuration` type, moved here from `@backstage/backend-tasks`. This type matches the `Duration.fromObject` form of `luxon`. + +## @backstage/version-bridge@1.0.2 + +### Patch Changes + +- e70984325d: Updated the value created by `createVersionedValueMap` to give it an extra hidden property that makes it easier to inspect during debugging. + +## @backstage/plugin-adr@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-adr-backend@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-adr-common@0.2.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-adr-common@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-airbrake@0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/dev-utils@1.0.8 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## @backstage/plugin-airbrake-backend@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## @backstage/plugin-allure@0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-analytics-module-ga@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/plugin-apache-airflow@0.2.4 + +### Patch Changes + +- 989731cabf: 1. Added a new column in the table to quickly view the latest DAG runs, plus a link to it if you want to have a deeper look. 2. Table columns are togglable 3. Set hidden columns 4. Fixed bug with turning on/off the DAGs +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + +## @backstage/plugin-api-docs@0.8.11 + +### Patch Changes + +- 4db78c2296: Updated dependency `@asyncapi/react-component` to `1.0.0-next.44`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-catalog@1.6.1 + - @backstage/theme@0.2.16 + +## @backstage/plugin-apollo-explorer@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-app-backend@0.3.38 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 + - @backstage/config-loader@1.1.6 + +## @backstage/plugin-auth-backend@0.17.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- cbe11d1e23: Tweak README +- 89d705e806: Add support for custom JWT header name in GCP IAP auth. +- abaed9770e: Improve logging +- d80833fe0c: Inject optional `CatalogApi` into auth-backend `createRouter` function. This will enable developers to use customized `CatalogApi` when creating the router. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-auth-node@0.2.7 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-azure-devops@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-azure-devops-backend@0.3.17 + +### Patch Changes + +- 62f284e394: - Adjusted the asset parser to accept case sensitive + - Fixed fetching data that was using the deprecated function +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-badges@0.2.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-badges-backend@0.1.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-bazaar-backend@0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/backend-test-utils@0.1.30 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-bitbucket-cloud-common@0.2.1 + +### Patch Changes + +- d089fbe7dc: Add interfaces for Bitbucket Cloud (webhook) events. +- Updated dependencies + - @backstage/integration@1.4.0 + +## @backstage/plugin-bitrise@0.1.38 + +### Patch Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-catalog@1.6.1 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-catalog-backend@1.5.1 + +### Patch Changes + +- c1a4addda3: Improve processing error logging. + + Adds `location` and `owner` to the logging meta if they are available. + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-scaffolder-common@1.2.2 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-aws@0.1.11 + +### Patch Changes + +- bae3617be5: `AwsS3EntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- defb389ecd: Add `awsS3EntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-azure@0.1.9 + +### Patch Changes + +- 87ff05892d: `AzureDevOpsEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- 0ca399b31b: Add `azureDevOpsEntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.5 + +### Patch Changes + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.5 + +### Patch Changes + +- d089fbe7dc: Handle Bitbucket Cloud `repo:push` events at the `BitbucketCloudEntityProvider` + by subscribing to the topic `bitbucketCloud.repo:push.` + + Implements `EventSubscriber` to receive events for the topic `bitbucketCloud.repo:push`. + + On `repo:push`, the affected repository will be refreshed. + This includes adding new Location entities, refreshing existing ones, + and removing obsolete ones. + + To support this, a new annotation `bitbucket.org/repo-url` was added + to Location entities. + + A full refresh will require 1 API call to Bitbucket Cloud to discover all catalog files. + When we handle one `repo:push` event, we also need 1 API call in order to know + which catalog files exist. + This may lead to more discovery-related API calls (code search). + The main cause for hitting the rate limits are Locations refresh-related operations. + + A reduction of total API calls to reduce the rate limit issues can only be achieved in + combination with + + 1. reducing the full refresh frequency (e.g., to monthly) + 2. reducing the frequency of general Location refresh operations by the processing loop + + For (2.), it is not possible to reduce the frequency only for Bitbucket Cloud-related + Locations though. + + Further optimizations might be required to resolve the rate limit issue. + + **Installation and Migration** + + Please find more information at + , + in particular the section about "_Installation with Events Support_". + + In case of the new backend-plugin-api _(alpha)_ the module will take care of + registering itself at both. + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-events-node@0.1.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/plugin-catalog-common@1.0.8 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.3 + +### Patch Changes + +- 68f7f5a857: `BitbucketServerEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- cd48ed8370: Add `bitbucketServerEntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.6 + +### Patch Changes + +- 4fba50f5d4: Add `gerritEntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. + +- 134b69f478: `GerritEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.9 + +### Patch Changes + +- 6bb046bcbe: Add `gitlabDiscoveryEntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- 81cedb5033: `GitlabDiscoveryEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-catalog-backend-module-msgraph@0.4.4 + +### Patch Changes + +- 0e37858f22: Added cause information to logged warnings + +- 8d1a5e08ca: `MicrosoftGraphOrgEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + + +- 384f99c276: Add `microsoftGraphOrgEntityProviderCatalogModule` (new backend-plugin-api, alpha). + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.4 + +### Patch Changes + +- 4ce887400d: Added support to use the `UrlReaders` when `$ref` pointing to a URL. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + +## @backstage/plugin-catalog-common@1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-catalog-graph@0.2.23 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- 21d84ef332: feat: Enable theme overrides for components in catalog-graph plugin + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/theme@0.2.16 + +## @backstage/plugin-catalog-graphql@0.3.15 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + +## @backstage/plugin-catalog-import@0.9.1 + +### Patch Changes + +- 1e7b640518: Get rid of `this-is-undefined-in-esm` warning +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/integration-react@1.1.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + +## @backstage/plugin-catalog-node@1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + +## @backstage/plugin-catalog-react@1.2.1 + +### Patch Changes + +- a889314692: Both `EntityProvider` and `AsyncEntityProvider` contexts now wrap all children with an `AnalyticsContext` containing the corresponding `entityRef`; this opens up the possibility for all events underneath these contexts to be associated with and aggregated by the corresponding entity. +- e47f466f80: Removed forced capitalization for Entity types in the catalog sidebar. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + +## @backstage/plugin-cicd-statistics@0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-cicd-statistics@0.1.13 + +## @backstage/plugin-circleci@0.3.11 + +### Patch Changes + +- 383574c49b: Update screenshots in documentation to match latest CircleCI plugin +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-cloudbuild@0.3.11 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-code-climate@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-code-coverage@0.2.4 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-code-coverage-backend@0.2.4 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-codescene@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-config-schema@0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-dynatrace@1.0.1 + +### Patch Changes + +- cbe11d1e23: Tweak README +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-explore@0.3.42 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-explore-react@0.0.23 + +## @backstage/plugin-explore-react@0.0.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + +## @backstage/plugin-firehydrant@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-fossa@0.2.43 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gcalendar@0.3.7 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gcp-projects@0.3.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-git-release-manager@0.3.24 + +### Patch Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-github-actions@0.5.11 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-github-deployments@0.1.42 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/integration-react@1.1.6 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-github-pull-requests-board@0.1.5 + +### Patch Changes + +- cc8bfc56c3: Add a new "Team" Filter Options to the Github Pull Requests Dashboard. + + When toggling this option on, the dashboard will displays all of the PRs opened + by the members of that team on any repositories of the organization. + +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gitops-profiles@0.3.29 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gocd@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-graphiql@0.2.43 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-graphql-backend@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/plugin-catalog-graphql@0.3.15 + +## @backstage/plugin-home@0.4.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-stack-overflow@0.1.7 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/plugin-jenkins@0.7.10 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-jenkins-common@0.1.10 + +## @backstage/plugin-jenkins-backend@0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-jenkins-common@0.1.10 + +## @backstage/plugin-jenkins-common@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-catalog-common@1.0.8 + +## @backstage/plugin-kafka@0.3.11 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/plugin-kafka-backend@0.2.31 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-kubernetes@0.7.4 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-kubernetes-common@0.4.4 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/plugin-kubernetes-common@0.4.4 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. + +- cbf5d11fdf: The Kubernetes errors when fetching pod metrics are now captured and returned to the frontend. + + - **BREAKING** The method `fetchPodMetricsByNamespace` in the interface `KubernetesFetcher` is changed to `fetchPodMetricsByNamespaces`. It now accepts a set of namespace strings and returns `Promise`. + - Add the `PodStatusFetchResponse` to the `FetchResponse` union type. + - Add `NOT_FOUND` to the `KubernetesErrorTypes` union type, the HTTP error with status code 404 will be mapped to this error. + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + +## @backstage/plugin-lighthouse@0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @backstage/plugin-newrelic@0.3.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-newrelic-dashboard@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + +## @backstage/plugin-pagerduty@0.5.4 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-periskop@0.1.9 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-periskop-backend@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## @backstage/plugin-permission-backend@0.5.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-permission-common@0.7.1 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 64848c963c: Properly handle rules that have no parameters in `PermissionClient` +- Updated dependencies + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-permission-node@0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-permission-react@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + +## @backstage/plugin-playlist@0.1.2 + +### Patch Changes + +- 605f269f0d: Updated Playlist plugin docs: + + - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features + - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-search-react@1.2.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-playlist-common@0.1.2 + +## @backstage/plugin-playlist-backend@0.2.1 + +### Patch Changes + +- 605f269f0d: Updated Playlist plugin docs: + + - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features + - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/backend-test-utils@0.1.30 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-playlist-common@0.1.2 + +## @backstage/plugin-playlist-common@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + +## @backstage/plugin-proxy-backend@0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## @backstage/plugin-rollbar@0.4.11 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-rollbar-backend@0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + +## @backstage/plugin-scaffolder-common@1.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + +## @backstage/plugin-search@1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-search-react@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-search-backend@1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-search-backend-module-elasticsearch@1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-search-backend-module-pg@0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-search-backend-node@1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-search-common@1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + +## @backstage/plugin-search-react@1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-sentry@0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-shortcuts@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/theme@0.2.16 + +## @backstage/plugin-sonarqube-backend@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-stack-overflow@0.1.7 + +### Patch Changes + +- e32d5643e3: `StackOverflowSearchResultListItem` now accept optional rank property to be able to capture rank analytics data. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-home@0.4.27 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-stack-overflow-backend@0.1.7 + +### Patch Changes + +- cbe11d1e23: Tweak README + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/cli@0.21.0 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-tech-insights@0.3.3 + +### Patch Changes + +- 7095e8bc03: Fixed bug when sending data by Post in `runChecks` and `runBulkChecks` functions of the `TechInsightsClient` class, the default `Content-Type` used was `plain/text` +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-tech-insights-common@0.2.8 + +## @backstage/plugin-tech-insights-backend@0.5.4 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- 06cf8f1cf2: Add a default delay to the fact retrievers to prevent cold-start errors +- 30e43717c7: Use `HumanDuration` from `@backstage/types` +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-tech-insights-common@0.2.8 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-tech-insights-common@0.2.8 + +## @backstage/plugin-tech-insights-common@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + +## @backstage/plugin-tech-insights-node@0.3.6 + +### Patch Changes + +- 06cf8f1cf2: Add a default delay to the fact retrievers to prevent cold-start errors +- 30e43717c7: Use `HumanDuration` from `@backstage/types` +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/plugin-tech-insights-common@0.2.8 + +## @backstage/plugin-tech-radar@0.5.18 + +### Patch Changes + +- 1f888af5f6: Fixed bug in Tech Radar where, on hover, the tech list quadrant would rerender and scroll top +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-catalog@1.6.1 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs-backend@1.4.1 + +### Patch Changes + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-techdocs-node@1.4.2 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.6 + +### Patch Changes + +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/integration-react@1.1.6 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs-node@1.4.2 + +### Patch Changes + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## @backstage/plugin-techdocs-react@1.0.6 + +### Patch Changes + +- 7d1352d459: Analytics events captured within the `` now include the conventional `entityRef` context value, associating those events with their corresponding entity. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + +## @backstage/plugin-todo@0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-todo-backend@0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-user-settings@0.5.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-user-settings-backend@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + +## @backstage/plugin-vault@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## @backstage/plugin-vault-backend@0.2.4 + +### Patch Changes + +- 687237da4c: Added `errorHandler()` middleware to `router` to prevent crashes caused by fatal errors in plugin backend +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/backend-test-utils@0.1.30 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @backstage/plugin-xcmetrics@0.2.31 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- dcf9e728de: Removed an unused and hidden build details route. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## example-app@0.2.77 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0 + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/plugin-cost-insights@0.12.0 + - @backstage/plugin-apache-airflow@0.2.4 + - @backstage/core-app-api@1.2.0 + - @backstage/plugin-explore@0.3.42 + - @backstage/plugin-tech-insights@0.3.3 + - @backstage/plugin-github-actions@0.5.11 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-dynatrace@1.0.1 + - @backstage/plugin-catalog-import@0.9.1 + - @backstage/plugin-catalog-graph@0.2.23 + - @backstage/plugin-tech-radar@0.5.18 + - @backstage/plugin-playlist@0.1.2 + - @backstage/plugin-stack-overflow@0.1.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-gcalendar@0.3.7 + - @backstage/plugin-code-coverage@0.2.4 + - @backstage/plugin-org@0.6.0 + - @backstage/plugin-api-docs@0.8.11 + - @backstage/plugin-kubernetes@0.7.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6 + - @backstage/plugin-circleci@0.3.11 + - @backstage/plugin-azure-sites@0.1.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-cloudbuild@0.3.11 + - @backstage/plugin-jenkins@0.7.10 + - @backstage/plugin-kafka@0.3.11 + - @backstage/plugin-pagerduty@0.5.4 + - @backstage/plugin-rollbar@0.4.11 + - @backstage/plugin-airbrake@0.3.11 + - @backstage/plugin-azure-devops@0.2.2 + - @backstage/plugin-badges@0.2.35 + - @internal/plugin-catalog-customized@0.0.4 + - @backstage/plugin-gocd@0.1.17 + - @backstage/plugin-home@0.4.27 + - @backstage/plugin-lighthouse@0.3.11 + - @backstage/plugin-newrelic-dashboard@0.2.4 + - @backstage/plugin-search@1.0.4 + - @backstage/plugin-sentry@0.4.4 + - @backstage/plugin-todo@0.2.13 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-gcp-projects@0.3.30 + - @backstage/plugin-graphiql@0.2.43 + - @backstage/plugin-newrelic@0.3.29 + - @backstage/plugin-search-react@1.2.1 + - @backstage/plugin-shortcuts@0.3.3 + - @backstage/plugin-user-settings@0.5.1 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-search-common@1.1.1 + +## example-backend@0.2.77 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-backend@0.17.1 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/plugin-techdocs-backend@1.4.1 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-playlist-backend@0.2.1 + - @backstage/plugin-azure-devops-backend@0.3.17 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-code-coverage-backend@0.2.4 + - @backstage/plugin-events-backend@0.1.0 + - @backstage/plugin-events-node@0.1.0 + - @backstage/plugin-kubernetes-backend@0.8.0 + - @backstage/plugin-tech-insights-backend@0.5.4 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/plugin-azure-sites-backend@0.1.0 + - example-app@0.2.77 + - @backstage/plugin-app-backend@0.3.38 + - @backstage/plugin-badges-backend@0.1.32 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/plugin-graphql-backend@0.1.28 + - @backstage/plugin-jenkins-backend@0.1.28 + - @backstage/plugin-kafka-backend@0.2.31 + - @backstage/plugin-permission-backend@0.5.13 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/plugin-proxy-backend@0.2.32 + - @backstage/plugin-rollbar-backend@0.1.35 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6 + - @backstage/plugin-search-backend@1.1.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4 + - @backstage/plugin-search-backend-module-pg@0.4.2 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22 + - @backstage/plugin-todo-backend@0.1.35 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## example-backend-next@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/plugin-app-backend@0.3.38 + - @backstage/backend-defaults@0.1.3 + +## techdocs-cli-embedded-app@0.2.76 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-catalog@1.6.1 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/test-utils@1.2.2 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## @internal/plugin-catalog-customized@0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/plugin-catalog@1.6.1 + +## @internal/plugin-todo-list@1.0.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## @internal/plugin-todo-list-backend@1.0.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## @internal/plugin-todo-list-common@1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 diff --git a/docs/releases/v1.8.0-next.2-changelog.md b/docs/releases/v1.8.0-next.2-changelog.md new file mode 100644 index 0000000000..d6c55998f6 --- /dev/null +++ b/docs/releases/v1.8.0-next.2-changelog.md @@ -0,0 +1,1903 @@ +# Release v1.8.0-next.2 + +## @backstage/cli@0.21.0-next.1 + +### Minor Changes + +- 384eaa2307: Switched `tsconfig.json` to target and support `ES2021`, in line with the bump to Node.js 16 & 18. + +### Patch Changes + +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- Updated dependencies + - @backstage/release-manifests@0.0.7-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-org@0.6.0-next.1 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-org-react@0.1.0-next.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-scaffolder-backend@1.8.0-next.2 + +### Minor Changes + +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + +## @backstage/plugin-splunk-on-call@0.4.0-next.1 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/app-defaults@1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7-next.0 + +## @backstage/backend-app-api@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/errors@1.1.3-next.0 + +## @backstage/backend-common@0.16.0-next.1 + +### Patch Changes + +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/backend-defaults@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.2.3-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + +## @backstage/backend-plugin-api@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/backend-tasks@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/backend-test-utils@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/backend-app-api@0.2.3-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/codemods@0.1.41-next.0 + +### Patch Changes + +- 58502ec285: Updated dependency `jscodeshift` to `^0.14.0`. +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/core-components@0.12.0-next.1 + +### Patch Changes + +- b4fb5c8ecc: MissingAnnotationEmptyState now accepts either a string or an array of strings to support multiple missing annotations. +- Updated dependencies + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/version-bridge@1.0.1 + +## @backstage/create-app@0.4.34-next.2 + +### Patch Changes + +- 384eaa2307: Switched Node.js version to support version 16 & 18, rather than 14 & 16. To switch the Node.js version in your own project, apply the following change to the root `package.json`: + + ```diff + "engines": { + - "node": "14 || 16" + + "node": "16 || 18" + }, + ``` + + As well as the following change to `packages/app/package.json`: + + ```diff + - "@types/node": "^14.14.32", + + "@types/node": "^16.11.26", + ``` + +- 864c876e57: Fixed incorrect comments in the templated `app-config.yaml` and `app-config.production.yaml`. The `backend.listen` directive is not in fact needed to override the `backend.baseUrl`, the backend listens to all interfaces by default. The configuration has also been updated to listen to all interfaces, rather than just IPv4 ones, as this is required for Node.js v18. The production configuration now also shows the option to specify `backend.listen` as a single string. + + To apply this changes to an existing app, make the following change to `app-config.yaml`: + + ```diff + - # Uncomment the following host directive to bind to all IPv4 interfaces and + - # not just the baseUrl hostname. + - # host: 0.0.0.0 + + # Uncomment the following host directive to bind to specific interfaces + + # host: 127.0.0.1 + ``` + + And the following change to `app-config.production.yaml`: + + ```diff + - listen: + - port: 7007 + - # The following host directive binds to all IPv4 interfaces when its value + - # is "0.0.0.0". This is the most permissive setting. The right value depends + - # on your specific deployment. If you remove the host line entirely, the + - # backend will bind on the interface that corresponds to the backend.baseUrl + - # hostname. + - host: 0.0.0.0 + + # The listener can also be expressed as a single : string. In this case we bind to + + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + + listen: ':7007' + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/dev-utils@1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/integration-react@1.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/release-manifests@0.0.7-next.0 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + +## @techdocs/cli@1.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-adr@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-adr-backend@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-airbrake@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/dev-utils@1.0.8-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-airbrake-backend@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-allure@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-analytics-module-ga@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-apache-airflow@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + +## @backstage/plugin-api-docs@0.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-apollo-explorer@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-app-backend@0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-auth-backend@0.17.1-next.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- abaed9770e: Improve logging +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-auth-node@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-azure-devops@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-azure-devops-backend@0.3.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-azure-sites@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-azure-sites-backend@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + +## @backstage/plugin-badges@0.2.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-badges-backend@0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-bazaar@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-bazaar-backend@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-bitrise@0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog@1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-catalog-backend@1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-graph@0.2.23-next.1 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog-import@0.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog-node@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + +## @backstage/plugin-catalog-react@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + +## @backstage/plugin-cicd-statistics@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.13-next.1 + +## @backstage/plugin-circleci@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-cloudbuild@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-climate@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-coverage@0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-coverage-backend@0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-codescene@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-config-schema@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-cost-insights@0.12.0-next.1 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + +## @backstage/plugin-dynatrace@1.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-explore@0.3.42-next.1 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-explore-react@0.0.23-next.0 + +## @backstage/plugin-firehydrant@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-fossa@0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-gcalendar@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gcp-projects@0.3.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-git-release-manager@0.3.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-github-actions@0.5.11-next.1 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-deployments@0.1.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-issues@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-pull-requests-board@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-gitops-profiles@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gocd@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-graphiql@0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-graphql-backend@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-catalog-graphql@0.3.15-next.0 + +## @backstage/plugin-home@0.4.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + +## @backstage/plugin-ilert@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-jenkins@0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + +## @backstage/plugin-jenkins-backend@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-kafka@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-kafka-backend@0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-kubernetes@0.7.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-kubernetes-backend@0.8.0-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-kubernetes-common@0.4.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + +## @backstage/plugin-lighthouse@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-newrelic@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-pagerduty@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-periskop@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-periskop-backend@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-permission-backend@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-permission-node@0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-playlist@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-playlist-backend@0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + +## @backstage/plugin-proxy-backend@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-rollbar@0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-rollbar-backend@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-scaffolder@1.8.0-next.1 + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-search@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-search-backend@1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-module-pg@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-node@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-react@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-sentry@0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-shortcuts@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-sonarqube@0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-sonarqube-backend@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-stack-overflow@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-stack-overflow-backend@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-tech-insights@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-backend@0.5.4-next.1 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-node@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-radar@0.5.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs@1.4.0-next.2 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-backend@1.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-node@1.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-techdocs-react@1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/version-bridge@1.0.1 + +## @backstage/plugin-todo@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-todo-backend@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-user-settings@0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-user-settings-backend@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-vault@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-vault-backend@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-xcmetrics@0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## example-app@0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0-next.1 + - @backstage/plugin-cost-insights@0.12.0-next.1 + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/plugin-explore@0.3.42-next.1 + - @backstage/plugin-github-actions@0.5.11-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/plugin-catalog-graph@0.2.23-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-code-coverage@0.2.4-next.1 + - @backstage/plugin-org@0.6.0-next.1 + - @backstage/plugin-kubernetes@0.7.4-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-airbrake@0.3.11-next.1 + - @backstage/plugin-apache-airflow@0.2.4-next.1 + - @backstage/plugin-api-docs@0.8.11-next.1 + - @backstage/plugin-azure-devops@0.2.2-next.1 + - @backstage/plugin-azure-sites@0.1.0-next.1 + - @backstage/plugin-badges@0.2.35-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-import@0.9.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-circleci@0.3.11-next.1 + - @backstage/plugin-cloudbuild@0.3.11-next.1 + - @backstage/plugin-dynatrace@1.0.1-next.1 + - @backstage/plugin-gcalendar@0.3.7-next.1 + - @backstage/plugin-gcp-projects@0.3.30-next.1 + - @backstage/plugin-gocd@0.1.17-next.1 + - @backstage/plugin-graphiql@0.2.43-next.1 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-jenkins@0.7.10-next.1 + - @backstage/plugin-kafka@0.3.11-next.1 + - @backstage/plugin-lighthouse@0.3.11-next.1 + - @backstage/plugin-newrelic@0.3.29-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + - @backstage/plugin-pagerduty@0.5.4-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist@0.1.2-next.2 + - @backstage/plugin-rollbar@0.4.11-next.1 + - @backstage/plugin-search@1.0.4-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-sentry@0.4.4-next.1 + - @backstage/plugin-shortcuts@0.3.3-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.3-next.1 + - @backstage/plugin-tech-radar@0.5.18-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + - @backstage/plugin-todo@0.2.13-next.1 + - @backstage/plugin-user-settings@0.5.1-next.1 + - @internal/plugin-catalog-customized@0.0.4-next.1 + +## example-backend@0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.17.1-next.1 + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/plugin-code-coverage-backend@0.2.4-next.1 + - @backstage/plugin-kubernetes-backend@0.8.0-next.1 + - @backstage/plugin-tech-insights-backend@0.5.4-next.1 + - example-app@0.2.77-next.2 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-app-backend@0.3.38-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-azure-devops-backend@0.3.17-next.2 + - @backstage/plugin-azure-sites-backend@0.1.0-next.1 + - @backstage/plugin-badges-backend@0.1.32-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-graphql-backend@0.1.28-next.1 + - @backstage/plugin-jenkins-backend@0.1.28-next.1 + - @backstage/plugin-kafka-backend@0.2.31-next.1 + - @backstage/plugin-permission-backend@0.5.13-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-playlist-backend@0.2.1-next.2 + - @backstage/plugin-proxy-backend@0.2.32-next.1 + - @backstage/plugin-rollbar-backend@0.1.35-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 + - @backstage/plugin-search-backend@1.1.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.2-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/plugin-techdocs-backend@1.4.1-next.1 + - @backstage/plugin-todo-backend@0.1.35-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## example-backend-next@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/plugin-app-backend@0.3.38-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/backend-defaults@0.1.3-next.1 + +## techdocs-cli-embedded-app@0.2.76-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @internal/plugin-catalog-customized@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @internal/plugin-todo-list@1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @internal/plugin-todo-list-backend@1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 diff --git a/docs/releases/v1.8.0.md b/docs/releases/v1.8.0.md new file mode 100644 index 0000000000..cbe16a0cba --- /dev/null +++ b/docs/releases/v1.8.0.md @@ -0,0 +1,78 @@ +--- +id: v1.8.0 +title: v1.8.0 +description: Backstage Release v1.8.0 +--- + +These are the release notes for the v1.8.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### Node 16 and 18 + +The project was updated to support and build against Node versions 16 and 18, after 18 had been elevated to [active LTS](https://github.com/nodejs/release#release-schedule). This means that support for Node 14 has been dropped in accordance with [our versioning policy](https://backstage.io/docs/overview/versioning-policy#nodejs-releases). + +We would like to call out one particular change in Node 18 that may affect adopters. The way that it binds interfaces internally when listening for incoming connections has changed such that it may prefer e.g. an IPv6 interface that you did not intend to use. This might make it seem like the backend is unreachable from the outside in some circumstances. Because of this, you may want to change your configuration to say something along the lines of `listen: ':7007'` under the `backend` section to ensure that it listens on all interfaces. + +### Events + +An early version of the `events` plugin ecosystem has been added. This allows events such as webhooks and similar to be received and propagated by a Backstage backend, and plugins can then react to those events. One early use case for this plugin is to start powering catalog updates. + +This is early days, so bear in mind that interfaces and implementations may still be subject to change. But do check it out, and let us know what you think! + +Contributed by [@pjungermann](https://github.com/pjungermann) in [#13931](https://github.com/backstage/backstage/pull/13931) + +### Gitea + +There is now support for [Gitea](https://gitea.io) as a general SCM integration. Please check out [the docs](https://backstage.io/docs/integrations/gitea/locations) for how to get started. + +Contributed by [@atoko](https://github.com/atoko) in [#14056](https://github.com/backstage/backstage/pull/14056) + +### Azure Sites + +There's a new Azure Sites (Apps & Functions) plugin. It lets you view the current status of the site, and quickly jump to the site's Overview or Log Stream pages. Please check out [the plugin README](https://github.com/backstage/backstage/tree/master/plugins/azure-sites) for more information. + +Contributed by [@wesley-pattison](https://github.com/wesley-pattison) in [#13634](https://github.com/backstage/backstage/pull/13634) + +### Scaffolder Metrics + +The scaffolder backend now emits default Prometheus metrics that track job execution. + +Contributed by [@spencerrichardhenry](https://github.com/spencerrichardhenry) in [#13815](https://github.com/backstage/backstage/pull/13815) + +### `@backstage/backend-common` + +The `UrlReader` interface has been updated to require that `readUrl` is implemented. The `readUrl` method has previously been optional to implement, but a warning used to be logged when calling its predecessor `read`. + +The `read` method is now deprecated and will be removed in a future release, and if you made custom URL readers you will have to implement a `readUrl` method on them. + +### Recharts + +The `recharts` library that powers the graphing functionality in some plugins was upgraded across the repository to version 2. Please let us know if you run into any new issues with graphing in plugins such as Bitrise, CICD statistics, code coverage, cost insights, GIT release manager, or XCmetrics. + +### `GitHub` to `Github` + +We are pursuing an effort to standardize the naming of exported GitHub related symbols. After an upgrade of Backstage, you may therefore see errors related to not finding components and types whose names start with “GitHub”. As an example, if you are using `GitHubIssuesPage` from the GitHub Issues plugin, you now need to import and use it as `GithubIssuesPage` instead. + +## Security Fixes + +This release does not contain any security fixes. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/bFESRKVt) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.8.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/tutorials/package-role-migration.md b/docs/tutorials/package-role-migration.md index 0af5fdb615..db84defd91 100644 --- a/docs/tutorials/package-role-migration.md +++ b/docs/tutorials/package-role-migration.md @@ -116,7 +116,7 @@ The way to execute this step of the migration is not as well defined as the prev - In places where the entire repo is being built, use `yarn backstage-cli repo build`, which also supports the `--since` flag. The migration here is a bit more nuanced as it depends on why you are building all packages. - If you are building all packages to **verify** that you are able to build them, you most likely want `backstage-cli repo build --all`. The `--all` flag signals that bundled packages like `packages/app` and `packages/backend` should be built as well. Pair this up with a `--since` flag in CI to avoid needing to build all packages. - If you are building all packages to **publish** them, then `backstage-cli repo build` is enough, as it builds all published packages. - - If you are building all packages to **deploy** them, you likely don't want to use the `repo` command at all, simply call `yarn build` in the packages you want to deploy instead. For example, if you are deploying the backend with a docker host build, it's enough to call `yarn build` inside `packages/backend`. + - If you are building all packages to **deploy** them, you likely don't want to use the `repo` command at all, simply call `yarn build` in the packages you want to deploy instead. For example, if you are deploying the backend with a docker host build, it's enough to call `yarn build` inside `packages/backend`. In a standard `@backstage/create-app` there is also a shorthand for building the backend from the root, `yarn build:backend`. ## FAQ diff --git a/docs/tutorials/quickstart-app-plugin.md b/docs/tutorials/quickstart-app-plugin.md index d1ca61a11f..ea0a511c93 100644 --- a/docs/tutorials/quickstart-app-plugin.md +++ b/docs/tutorials/quickstart-app-plugin.md @@ -20,7 +20,7 @@ title: Adding Custom Plugin to Existing Monorepo App > functionality, extend the Sidebar to make our life easy. Finally, we add > custom code to display GitHub repository information. > -> This document assumes you have Node.js 14 active along with Yarn and Python. +> This document assumes you have Node.js 16 active along with Yarn and Python. > Please note, that at the time of this writing, the current version is > 0.1.1-alpha.21. This guide can still be used with future versions, just, > verify as you go. If you run into issues, you can compare your setup with mine diff --git a/microsite/blog/2022-11-15-linux-foundation-introduction-to-backstage-course.md b/microsite/blog/2022-11-15-linux-foundation-introduction-to-backstage-course.md new file mode 100644 index 0000000000..b762bd7e97 --- /dev/null +++ b/microsite/blog/2022-11-15-linux-foundation-introduction-to-backstage-course.md @@ -0,0 +1,16 @@ +--- +title: The Linux Foundation launches its Introduction to Backstage course +description: The new Linux Foundation course is available for free on edX and is designed to help individuals understand how to map Backstage to their organization needs +author: Jorge Lainfiesta, Roadie +authorURL: https://www.linkedin.com/in/jrlainfiesta/ +--- + +Backstage continues to grow in [popularity and maturity](https://roadie.io/blog/backstage-consolidating-its-role-in-the-cloud-native-ecosystem/), with industry leaders not only adopting the framework but actively participating in the community through contributions and commercial offerings. One of the most recent contributions comes from the Linux Foundation, [launching an introductory course](https://training.linuxfoundation.org/blog/23107/) aimed at DevOps engineers or professionals working on Developer Productivity or Developer Experience. The course is available for free on edX, with a paid option for the certified track. + +[![Introduction to Backstage: Developer Portals Made Easy (LFS142x): Enroll!](assets/22-11-15/Introduction-to-Backstage-Developer-Portals-Made-Easy-2-768x432.png)](https://www.edx.org/course/introduction-to-backstage-developer-portals-made-easy) + + + +The course, [Introduction to Backstage: Developer Portals Made Easy (LFS142x)](https://www.edx.org/course/introduction-to-backstage-developer-portals-made-easy), starts discussing the benefits of adopting a Developer Portal. Then, it dives into what is Backstage, its main features (Catalog, Scaffolder, TechDocs), and how to map its capabilities to your organization. At last, it provides tips on how to connect with the community to ease up your adoption journey. + +The course author, [Jorge Lainfiesta](https://www.linkedin.com/in/jrlainfiesta/), is a Technical Marketing Manager at [Roadie](https://roadie.io). Jorge has a background in software engineering (PayPal) and digital communication (UCLA). He’s been working around Backstage since it was open sourced by Spotify and co-hosts community initiatives like the Backstage Users Unconference. diff --git a/microsite/blog/assets/22-11-15/Introduction-to-Backstage-Developer-Portals-Made-Easy-2-768x432.png b/microsite/blog/assets/22-11-15/Introduction-to-Backstage-Developer-Portals-Made-Easy-2-768x432.png new file mode 100644 index 0000000000..a789762cc1 Binary files /dev/null and b/microsite/blog/assets/22-11-15/Introduction-to-Backstage-Developer-Portals-Made-Easy-2-768x432.png differ diff --git a/microsite/data/plugins/announcements.yaml b/microsite/data/plugins/announcements.yaml new file mode 100644 index 0000000000..de80dcf6fe --- /dev/null +++ b/microsite/data/plugins/announcements.yaml @@ -0,0 +1,10 @@ +--- +title: Announcements +author: K-Phoen +authorUrl: https://github.com/K-Phoen +category: Discovery +description: Write and share announcements within Backstage. +documentation: https://github.com/K-Phoen/backstage-plugin-announcements/ +iconUrl: img/plugin-announcements-logo.png +npmPackageName: '@k-phoen/backstage-plugin-announcements' +addedDate: '2022-11-09' diff --git a/microsite/data/plugins/cloudsmith.yaml b/microsite/data/plugins/cloudsmith.yaml new file mode 100644 index 0000000000..5fc417eec1 --- /dev/null +++ b/microsite/data/plugins/cloudsmith.yaml @@ -0,0 +1,13 @@ +--- +title: Cloudsmith +author: Roadie +authorUrl: https://roadie.io +category: CI/CD +description: Show Cloudsmith Repository stats on your backstage homepage. +documentation: https://github.com/RoadieHQ/roadie-backstage-plugins/tree/main/plugins/frontend/backstage-plugin-cloudsmith +iconUrl: https://cloudsmith.com/img/cloudsmith-mini-dark.svg +npmPackageName: '@roadiehq/backstage-plugin-cloudsmith' +tags: + - dashboards + - monitoring +addedDate: '2022-11-18' diff --git a/microsite/data/plugins/humanitec.yaml b/microsite/data/plugins/humanitec.yaml index 5b3c459116..1b79270582 100644 --- a/microsite/data/plugins/humanitec.yaml +++ b/microsite/data/plugins/humanitec.yaml @@ -6,7 +6,7 @@ category: Deployment # A single category e.g. CI, Machine Learning, Services, Mo description: | Show workloads, environments and resources deployed by Humanitec Platform Orchestrator. Plugin includes an Entity ComponentCard, Backend API route and scaffolder actions. -documentation: https://github.com/thefrontside/backstage/tree/main/plugins/humanitec +documentation: https://github.com/thefrontside/playhouse/tree/main/plugins/humanitec iconUrl: img/humanitec-logo.png npmPackageName: '@frontside/backstage-plugin-humanitec' addedDate: '2022-06-22' diff --git a/microsite/pages/en/community.js b/microsite/pages/en/community.js index 0580ec045a..a5fd5353e0 100644 --- a/microsite/pages/en/community.js +++ b/microsite/pages/en/community.js @@ -149,7 +149,7 @@ const Background = props => { - + Community initiatives @@ -183,6 +183,29 @@ const Background = props => { + + + + Trainings and Certifications + + + + + Introduction to Backstage: Developer Portals Made Easy (LFS142x) + + + This is a course produced and curated by the Linux Foundation. + This course introduces you to Backstage and how to get started + with the project. + + + + Learn more + + + + + diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index 8e963c2453..ab3dabe14e 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -31,15 +31,6 @@ class Index extends React.Component { ! - -
- 🤩 Join us for the first{' '} - - BackstageCon - {' '} - on October 24, 2022! -
-
diff --git a/microsite/pages/en/live.js b/microsite/pages/en/live.js index 2accd6d11c..11945fcd3b 100644 --- a/microsite/pages/en/live.js +++ b/microsite/pages/en/live.js @@ -34,7 +34,7 @@ const Background = props => { diff --git a/microsite/sidebars.json b/microsite/sidebars.json index e758fe9100..581f8b592d 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.8.0", "releases/v1.7.0", "releases/v1.6.0", "releases/v1.5.0", @@ -95,6 +96,7 @@ "features/software-templates/configuration", "features/software-templates/adding-templates", "features/software-templates/writing-templates", + "features/software-templates/input-examples", "features/software-templates/builtin-actions", "features/software-templates/writing-custom-actions", "features/software-templates/writing-custom-field-extensions", @@ -315,6 +317,7 @@ ], "Designing for Backstage": [ "dls/design", + "dls/component-design-guidelines", "dls/contributing-to-storybook", "dls/figma" ], diff --git a/microsite/static/img/plugin-announcements-logo.png b/microsite/static/img/plugin-announcements-logo.png new file mode 100644 index 0000000000..edb0caf8d9 Binary files /dev/null and b/microsite/static/img/plugin-announcements-logo.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 0a943bbe83..1fa6e492cb 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -281,14 +281,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.10.4, @babel/helper-validator-identifier@npm:^7.12.11": - version: 7.12.11 - resolution: "@babel/helper-validator-identifier@npm:7.12.11" - checksum: e604c6bf890704fc46c1ae13bf23afb242b810224ec3403bba67cdbf0d8dabfec4b82123d6dfb18135a0ee3f7f79218583c819363ebb5e04a0a49d8418db7fce - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.18.6": +"@babel/helper-validator-identifier@npm:^7.10.4, @babel/helper-validator-identifier@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-validator-identifier@npm:7.18.6" checksum: e295254d616bbe26e48c196a198476ab4d42a73b90478c9842536cf910ead887f5af6b5c4df544d3052a25ccb3614866fa808dc1e3a5a4291acd444e243c0648 @@ -1241,18 +1234,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.10.4, @babel/types@npm:^7.10.5, @babel/types@npm:^7.12.1, @babel/types@npm:^7.12.10, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.12, @babel/types@npm:^7.12.5, @babel/types@npm:^7.12.6, @babel/types@npm:^7.12.7, @babel/types@npm:^7.4.4": - version: 7.12.12 - resolution: "@babel/types@npm:7.12.12" - dependencies: - "@babel/helper-validator-identifier": ^7.12.11 - lodash: ^4.17.19 - to-fast-properties: ^2.0.0 - checksum: 1eefe9468573a32491030f2986f820eb4289ff0b93e437b97f665e73cc8dae0ec0bdd95f37995bb3b70b5ce2a9a45a302affbbad497150021cf874c5ef10e361 - languageName: node - linkType: hard - -"@babel/types@npm:^7.8.3": +"@babel/types@npm:^7.10.4, @babel/types@npm:^7.10.5, @babel/types@npm:^7.12.1, @babel/types@npm:^7.12.10, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.12, @babel/types@npm:^7.12.5, @babel/types@npm:^7.12.6, @babel/types@npm:^7.12.7, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.18.10 resolution: "@babel/types@npm:7.18.10" dependencies: @@ -2917,7 +2899,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.3": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.3": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -2929,7 +2911,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4.3.1, debug@npm:^4.1.0": +"debug@npm:4.3.1": version: 4.3.1 resolution: "debug@npm:4.3.1" dependencies: @@ -4275,21 +4257,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.0.5, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.6": - version: 7.2.0 - resolution: "glob@npm:7.2.0" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.0.4 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 78a8ea942331f08ed2e055cb5b9e40fe6f46f579d7fd3d694f3412fe5db23223d29b7fee1575440202e9a7ff9a72ab106a39fee39934c7bedafe5e5f8ae20134 - languageName: node - linkType: hard - -"glob@npm:^7.1.4": +"glob@npm:^7.0.0, glob@npm:^7.0.5, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -4430,14 +4398,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0": - version: 4.2.4 - resolution: "graceful-fs@npm:4.2.4" - checksum: 9d58c444eb4f391ce30b451aae8a8af2bd675d9f6f624719e97306f571ab89b2bd2b5f9025199bc63a2edfe2e53e7701554012f32a708148d53aa689163728cc - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da @@ -5056,15 +5017,6 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0": - version: 2.2.0 - resolution: "is-core-module@npm:2.2.0" - dependencies: - has: ^1.0.3 - checksum: 61e2aff4a7db4f8f7d5a97b484808af17290f4197b34a797cd3d3d27b6b448951064f8d3d6ceae4394fa9b7e6cf08aacd2ba7a17ef6352e922fe803580fbde56 - languageName: node - linkType: hard - "is-core-module@npm:^2.8.0": version: 2.8.1 resolution: "is-core-module@npm:2.8.1" @@ -6196,7 +6148,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.0.4, minimatch@npm:^3.0.4, minimatch@npm:~3.0.2": +"minimatch@npm:3.0.4, minimatch@npm:~3.0.2": version: 3.0.4 resolution: "minimatch@npm:3.0.4" dependencies: @@ -6205,7 +6157,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.1.1": +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -6941,7 +6893,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.6, path-parse@npm:^1.0.7": +"path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a @@ -7967,7 +7919,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6": +"resolve@npm:^1.1.6, resolve@npm:^1.10.0": version: 1.21.0 resolution: "resolve@npm:1.21.0" dependencies: @@ -7980,17 +7932,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0": - version: 1.19.0 - resolution: "resolve@npm:1.19.0" - dependencies: - is-core-module: ^2.1.0 - path-parse: ^1.0.6 - checksum: a05b356e47b85ad3613d9e2a39a824f3c27f4fcad9c9ff6c7cc71a2e314c5904a90ab37481ad0069d03cab9eaaac6eb68aca1bc3355fdb05f1045cd50e2aacea - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.1.6#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin": version: 1.21.0 resolution: "resolve@patch:resolve@npm%3A1.21.0#~builtin::version=1.21.0&hash=07638b" dependencies: @@ -8003,16 +7945,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.10.0#~builtin": - version: 1.19.0 - resolution: "resolve@patch:resolve@npm%3A1.19.0#~builtin::version=1.19.0&hash=07638b" - dependencies: - is-core-module: ^2.1.0 - path-parse: ^1.0.6 - checksum: 2443b94d347e6946c87c85faf13071f605e609e0b54784829b0ed2b917d050bfc1cbaf4ecc6453f224cfa7d0c5dcd97cbb273454cd210bee68e4af15c1a5abc9 - languageName: node - linkType: hard - "responselike@npm:1.0.2": version: 1.0.2 resolution: "responselike@npm:1.0.2" @@ -8313,14 +8245,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2": - version: 3.0.3 - resolution: "signal-exit@npm:3.0.3" - checksum: f0169d3f1263d06df32ca072b0bf33b34c6f8f0341a7a1621558a2444dfbe8f5fec76b35537fcc6f0bc4944bdb5336fe0bdcf41a5422c4e45a1dba3f45475e6c - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 diff --git a/mkdocs.yml b/mkdocs.yml index 43efc32f8e..f3194f0d61 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,6 +62,7 @@ nav: - Configuration: 'features/software-templates/configuration.md' - Adding your own Templates: 'features/software-templates/adding-templates.md' - Writing Templates: 'features/software-templates/writing-templates.md' + - Input Examples: 'features/software-templates/input-examples.md' - Builtin Actions: 'features/software-templates/builtin-actions.md' - Writing Custom Actions: 'features/software-templates/writing-custom-actions.md' - Writing Custom Step Layouts: 'features/software-templates/writing-custom-step-layouts.md' @@ -177,6 +178,7 @@ nav: - Heroku: 'deployment/heroku.md' - Designing for Backstage: - Design: 'dls/design.md' + - Component Design Guidelines: 'dls/component-design-guidelines.md' - Contributing to Storybook: 'dls/contributing-to-storybook.md' - Figma: 'dls/figma.md' - API Reference: diff --git a/package.json b/package.json index 9f17e5ee36..2f20eeeee3 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,14 @@ "name": "root", "private": true, "engines": { - "node": "14 || 16" + "node": "16 || 18" }, "scripts": { "dev": "concurrently \"yarn start\" \"yarn start-backend\"", "start": "yarn workspace example-app start", "start-backend": "yarn workspace example-backend start", - "build": "backstage-cli repo build --all", + "build:backend": "yarn workspace backend build", + "build:all": "backstage-cli repo build --all", "build:api-reports": "yarn build:api-reports:only --tsc", "build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts", "build:api-docs": "LANG=en_EN yarn build:api-reports --docs", @@ -32,7 +33,8 @@ "build-storybook": "yarn ./storybook run build-storybook", "techdocs-cli": "node scripts/techdocs-cli.js", "techdocs-cli:dev": "cross-env TECHDOCS_CLI_DEV_MODE=true node scripts/techdocs-cli.js", - "prepare": "husky install" + "prepare": "husky install", + "postinstall": "husky install" }, "workspaces": { "packages": [ @@ -44,7 +46,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.8.0-next.1", + "version": "1.8.0", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3", @@ -69,10 +71,12 @@ "e2e-test": "workspace:*", "eslint": "^8.6.0", "eslint-plugin-notice": "^0.9.10", + "eslint-plugin-testing-library": "^5.9.1", "fs-extra": "10.1.0", "husky": "^8.0.0", "lint-staged": "^13.0.0", "minimist": "^1.2.5", + "node-gyp": "^9.1.0", "prettier": "^2.2.1", "semver": "^7.3.2", "shx": "^0.3.2", @@ -90,6 +94,12 @@ ], "*.md": [ "node ./scripts/check-docs-quality" + ], + "./yarn.lock": [ + "node ./scripts/verify-lockfile-duplicates --fix" + ], + "*/yarn.lock": [ + "node ./scripts/verify-lockfile-duplicates --fix" ] }, "packageManager": "yarn@3.2.3" diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 12b6a0894f..ebe8519740 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/app-defaults +## 1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7 + +## 1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7-next.0 + ## 1.0.8-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 6658f0a8bd..e89757d925 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.0.8-next.0", + "version": "1.0.8", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index b713987116..69860075a1 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,131 @@ # example-app +## 0.2.77 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0 + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/plugin-cost-insights@0.12.0 + - @backstage/plugin-apache-airflow@0.2.4 + - @backstage/core-app-api@1.2.0 + - @backstage/plugin-explore@0.3.42 + - @backstage/plugin-tech-insights@0.3.3 + - @backstage/plugin-github-actions@0.5.11 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-dynatrace@1.0.1 + - @backstage/plugin-catalog-import@0.9.1 + - @backstage/plugin-catalog-graph@0.2.23 + - @backstage/plugin-tech-radar@0.5.18 + - @backstage/plugin-playlist@0.1.2 + - @backstage/plugin-stack-overflow@0.1.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-gcalendar@0.3.7 + - @backstage/plugin-code-coverage@0.2.4 + - @backstage/plugin-org@0.6.0 + - @backstage/plugin-api-docs@0.8.11 + - @backstage/plugin-kubernetes@0.7.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6 + - @backstage/plugin-circleci@0.3.11 + - @backstage/plugin-azure-sites@0.1.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-cloudbuild@0.3.11 + - @backstage/plugin-jenkins@0.7.10 + - @backstage/plugin-kafka@0.3.11 + - @backstage/plugin-pagerduty@0.5.4 + - @backstage/plugin-rollbar@0.4.11 + - @backstage/plugin-airbrake@0.3.11 + - @backstage/plugin-azure-devops@0.2.2 + - @backstage/plugin-badges@0.2.35 + - @internal/plugin-catalog-customized@0.0.4 + - @backstage/plugin-gocd@0.1.17 + - @backstage/plugin-home@0.4.27 + - @backstage/plugin-lighthouse@0.3.11 + - @backstage/plugin-newrelic-dashboard@0.2.4 + - @backstage/plugin-search@1.0.4 + - @backstage/plugin-sentry@0.4.4 + - @backstage/plugin-todo@0.2.13 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-gcp-projects@0.3.30 + - @backstage/plugin-graphiql@0.2.43 + - @backstage/plugin-newrelic@0.3.29 + - @backstage/plugin-search-react@1.2.1 + - @backstage/plugin-shortcuts@0.3.3 + - @backstage/plugin-user-settings@0.5.1 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-search-common@1.1.1 + +## 0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0-next.1 + - @backstage/plugin-cost-insights@0.12.0-next.1 + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/plugin-explore@0.3.42-next.1 + - @backstage/plugin-github-actions@0.5.11-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/plugin-catalog-graph@0.2.23-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-code-coverage@0.2.4-next.1 + - @backstage/plugin-org@0.6.0-next.1 + - @backstage/plugin-kubernetes@0.7.4-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-airbrake@0.3.11-next.1 + - @backstage/plugin-apache-airflow@0.2.4-next.1 + - @backstage/plugin-api-docs@0.8.11-next.1 + - @backstage/plugin-azure-devops@0.2.2-next.1 + - @backstage/plugin-azure-sites@0.1.0-next.1 + - @backstage/plugin-badges@0.2.35-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-import@0.9.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-circleci@0.3.11-next.1 + - @backstage/plugin-cloudbuild@0.3.11-next.1 + - @backstage/plugin-dynatrace@1.0.1-next.1 + - @backstage/plugin-gcalendar@0.3.7-next.1 + - @backstage/plugin-gcp-projects@0.3.30-next.1 + - @backstage/plugin-gocd@0.1.17-next.1 + - @backstage/plugin-graphiql@0.2.43-next.1 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-jenkins@0.7.10-next.1 + - @backstage/plugin-kafka@0.3.11-next.1 + - @backstage/plugin-lighthouse@0.3.11-next.1 + - @backstage/plugin-newrelic@0.3.29-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + - @backstage/plugin-pagerduty@0.5.4-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist@0.1.2-next.2 + - @backstage/plugin-rollbar@0.4.11-next.1 + - @backstage/plugin-search@1.0.4-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-sentry@0.4.4-next.1 + - @backstage/plugin-shortcuts@0.3.3-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.3-next.1 + - @backstage/plugin-tech-radar@0.5.18-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + - @backstage/plugin-todo@0.2.13-next.1 + - @backstage/plugin-user-settings@0.5.1-next.1 + - @internal/plugin-catalog-customized@0.0.4-next.1 + ## 0.2.77-next.1 ### Patch Changes diff --git a/packages/app/cypress/integration/app.js b/packages/app/cypress/integration/app.js index 7b874907be..6371bcc4f8 100644 --- a/packages/app/cypress/integration/app.js +++ b/packages/app/cypress/integration/app.js @@ -25,14 +25,17 @@ describe('App', () => { it('should display support info when clicking the button', () => { cy.visit('/'); + // eslint-disable-next-line testing-library/await-async-query cy.findByTestId('support-button').click({ force: true }); cy.contains('#backstage'); }); it('should display error message when triggering it', () => { cy.visit('/'); + // eslint-disable-next-line testing-library/await-async-query cy.findByTestId('error-button').click({ force: true }); cy.contains('Error: Oh no!'); + // eslint-disable-next-line testing-library/await-async-query cy.findByTestId('error-button-close').click({ force: true }); }); @@ -55,6 +58,7 @@ describe('App', () => { cy.contains('Token') .get('input[name=github-auth-tf]') .type('password', { force: true }); + // eslint-disable-next-line testing-library/await-async-query cy.findByTestId('github-auth-button').click({ force: true }); cy.contains(`Welcome, ${name}!`); cy.contains('Logout').click({ force: true }); diff --git a/packages/app/package.json b/packages/app/package.json index 3f93c523a3..9978a0d515 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.77-next.1", + "version": "0.2.77", "private": true, "backstage": { "role": "frontend" @@ -80,7 +80,7 @@ "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-use": "^17.2.4", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "devDependencies": { "@backstage/test-utils": "workspace:^", diff --git a/packages/app/public/index.html b/packages/app/public/index.html index 885fb6c228..0710a0d69d 100644 --- a/packages/app/public/index.html +++ b/packages/app/public/index.html @@ -44,24 +44,7 @@ /> <%= config.getString('app.title') %> - <% if (config.has('app.googleAnalyticsTrackingId')) { %> - - - <% } %> <% if (config.has('app.datadogRum')) { %> + <% if (config.has('app.datadogRum')) { %> + - + - <% } %> + + ``` + + Additionally, you should make the following adjustment to `app-config.yaml`: + + ```diff + app: + title: Backstage Example App + baseUrl: http://localhost:3000 + - googleAnalyticsTrackingId: # UA-000000-0 + ``` + +- 4091c73e68: Updated `@swc/core` to `v1.3.9` which fixes a `.tsx` parser bug. You may want to run `yarn backstage-cli versions:bump` to get on latest version including the CLI itself. +- 80bfac5266: Updated the create-app command to no longer require Git to be installed and configured. A git repository will only be initialized if possible and if not already in an git repository. +- 286d474675: The `build` script in the root `package.json` has been split into two separate scripts, `build:backend` and `build:all`. This is to more accurately reflect what is being built, to avoid confusion. + + If you want to build the project for a production deployment, you will want to use `build:backend`, as this builds both the frontend and backend package. If you are not using the `app-backend` plugin you will want to add your own `build:frontend` script, to which you can pass additional configuration parameters if needed. + + The `build:all` script is useful if you simply want to check that it is possible to build all packages in the project. This might be useful as a CI check, but is generally unnecessary. + + If you want to publish the packages in your repository you can add a `build:packages` script that calls `backstage-cli repo build`. This will skip the frontend and backend packages builds, as those are quite time consuming. + + To apply these changes to an existing project, make the following change to the root `package.json` file: + + ```diff + - "build": "backstage-cli repo build --all", + + "build:backend": "yarn workspace backend build", + + "build:all": "backstage-cli repo build --all", + ``` + + There are also a couple of places where documentation has been updated, see the [upgrade helper](https://backstage.github.io/upgrade-helper/?to=1.8.0) for a full list of changes. + +- 384eaa2307: Switched Node.js version to support version 16 & 18, rather than 14 & 16. To switch the Node.js version in your own project, apply the following change to the root `package.json`: + + ```diff + "engines": { + - "node": "14 || 16" + + "node": "16 || 18" + }, + ``` + + As well as the following change to `packages/app/package.json`: + + ```diff + - "@types/node": "^14.14.32", + + "@types/node": "^16.11.26", + ``` + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- 864c876e57: Fixed incorrect comments in the templated `app-config.yaml` and `app-config.production.yaml`. The `backend.listen` directive is not in fact needed to override the `backend.baseUrl`, the backend listens to all interfaces by default. The configuration has also been updated to listen to all interfaces, rather than just IPv4 ones, as this is required for Node.js v18. The production configuration now also shows the option to specify `backend.listen` as a single string. + + To apply this changes to an existing app, make the following change to `app-config.yaml`: + + ```diff + - # Uncomment the following host directive to bind to all IPv4 interfaces and + - # not just the baseUrl hostname. + - # host: 0.0.0.0 + + # Uncomment the following host directive to bind to specific interfaces + + # host: 127.0.0.1 + ``` + + And the following change to `app-config.production.yaml`: + + ```diff + - listen: + - port: 7007 + - # The following host directive binds to all IPv4 interfaces when its value + - # is "0.0.0.0". This is the most permissive setting. The right value depends + - # on your specific deployment. If you remove the host line entirely, the + - # backend will bind on the interface that corresponds to the backend.baseUrl + - # hostname. + - host: 0.0.0.0 + + # The listener can also be expressed as a single : string. In this case we bind to + + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + + listen: ':7007' + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## 0.4.34-next.2 + +### Patch Changes + +- 384eaa2307: Switched Node.js version to support version 16 & 18, rather than 14 & 16. To switch the Node.js version in your own project, apply the following change to the root `package.json`: + + ```diff + "engines": { + - "node": "14 || 16" + + "node": "16 || 18" + }, + ``` + + As well as the following change to `packages/app/package.json`: + + ```diff + - "@types/node": "^14.14.32", + + "@types/node": "^16.11.26", + ``` + +- 864c876e57: Fixed incorrect comments in the templated `app-config.yaml` and `app-config.production.yaml`. The `backend.listen` directive is not in fact needed to override the `backend.baseUrl`, the backend listens to all interfaces by default. The configuration has also been updated to listen to all interfaces, rather than just IPv4 ones, as this is required for Node.js v18. The production configuration now also shows the option to specify `backend.listen` as a single string. + + To apply this changes to an existing app, make the following change to `app-config.yaml`: + + ```diff + - # Uncomment the following host directive to bind to all IPv4 interfaces and + - # not just the baseUrl hostname. + - # host: 0.0.0.0 + + # Uncomment the following host directive to bind to specific interfaces + + # host: 127.0.0.1 + ``` + + And the following change to `app-config.production.yaml`: + + ```diff + - listen: + - port: 7007 + - # The following host directive binds to all IPv4 interfaces when its value + - # is "0.0.0.0". This is the most permissive setting. The right value depends + - # on your specific deployment. If you remove the host line entirely, the + - # backend will bind on the interface that corresponds to the backend.baseUrl + - # hostname. + - host: 0.0.0.0 + + # The listener can also be expressed as a single : string. In this case we bind to + + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + + listen: ':7007' + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + ## 0.4.33-next.1 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 932d54ee03..fada03dc79 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.33-next.1", + "version": "0.4.34", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/templates/default-app/app-config.production.yaml b/packages/create-app/templates/default-app/app-config.production.yaml index 6535d967d5..df09dac50a 100644 --- a/packages/create-app/templates/default-app/app-config.production.yaml +++ b/packages/create-app/templates/default-app/app-config.production.yaml @@ -9,14 +9,9 @@ backend: # callers. When its value is "http://localhost:7007", it's strictly private # and can't be reached by others. baseUrl: http://localhost:7007 - listen: - port: 7007 - # The following host directive binds to all IPv4 interfaces when its value - # is "0.0.0.0". This is the most permissive setting. The right value depends - # on your specific deployment. If you remove the host line entirely, the - # backend will bind on the interface that corresponds to the backend.baseUrl - # hostname. - host: 0.0.0.0 + # The listener can also be expressed as a single : string. In this case we bind to + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + listen: ':7007' # config options: https://node-postgres.com/api/client database: diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index 4a058deefd..1a45d4015b 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -15,9 +15,8 @@ backend: baseUrl: http://localhost:7007 listen: port: 7007 - # Uncomment the following host directive to bind to all IPv4 interfaces and - # not just the baseUrl hostname. - # host: 0.0.0.0 + # Uncomment the following host directive to bind to specific interfaces + # host: 127.0.0.1 csp: connect-src: ["'self'", 'http:', 'https:'] # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index c5810d8880..070cb871bc 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -3,13 +3,14 @@ "version": "1.0.0", "private": true, "engines": { - "node": "14 || 16" + "node": "16 || 18" }, "scripts": { "dev": "concurrently \"yarn start\" \"yarn start-backend\"", "start": "yarn workspace app start", "start-backend": "yarn workspace backend start", - "build": "backstage-cli repo build --all", + "build:backend": "yarn workspace backend build", + "build:all": "backstage-cli repo build --all", "build-image": "yarn workspace backend build-image", "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", diff --git a/packages/create-app/templates/default-app/packages/app/public/index.html b/packages/create-app/templates/default-app/packages/app/public/index.html index a936c73602..c6083b3dd2 100644 --- a/packages/create-app/templates/default-app/packages/app/public/index.html +++ b/packages/create-app/templates/default-app/packages/app/public/index.html @@ -43,24 +43,6 @@ color="#5bbad5" /> <%= config.getString('app.title') %> - <% if (config.has('app.googleAnalyticsTrackingId')) { %> - - - <% } %> @@ -72,8 +54,8 @@ You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the tag. - To begin the development, run `npm start` or `yarn start`. - To create a production bundle, use `npm run build` or `yarn build`. + To begin the development, run `yarn start`. + To create a production bundle, use `yarn build`. --> diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index f0be3ac1d3..51f7124db4 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -5,7 +5,7 @@ # # yarn install # yarn tsc -# yarn build +# yarn build:backend # # Once the commands have been run, you can build the image using `yarn build-image` diff --git a/packages/create-app/templates/default-app/packages/backend/README.md b/packages/create-app/templates/default-app/packages/backend/README.md index 02426ef9b3..aa042db030 100644 --- a/packages/create-app/templates/default-app/packages/backend/README.md +++ b/packages/create-app/templates/default-app/packages/backend/README.md @@ -16,8 +16,6 @@ To run the example backend, first go to the project root and run ```bash yarn install -yarn tsc -yarn build ``` You should only need to do this once. @@ -25,16 +23,11 @@ You should only need to do this once. After that, go to the `packages/backend` directory and run ```bash -AUTH_GOOGLE_CLIENT_ID=x AUTH_GOOGLE_CLIENT_SECRET=x \ -AUTH_GITHUB_CLIENT_ID=x AUTH_GITHUB_CLIENT_SECRET=x \ -AUTH_OAUTH2_CLIENT_ID=x AUTH_OAUTH2_CLIENT_SECRET=x \ -AUTH_OAUTH2_AUTH_URL=x AUTH_OAUTH2_TOKEN_URL=x \ -LOG_LEVEL=debug \ yarn start ``` -Substitute `x` for actual values, or leave them as dummy values just to try out -the backend without using the auth or sentry features. +If you want to override any configuration locally, for example adding any secrets, +you can do so in `app-config.local.yaml`. The backend starts up on port 7007 per default. diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 7177a25fb2..f9ba61bc5b 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/dev-utils +## 1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## 1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 1.0.8-next.0 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0decdbe985..08c2a2c305 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "1.0.8-next.0", + "version": "1.0.8", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -47,7 +47,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "react-use": "^17.2.4", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/packages/e2e-test/README.md b/packages/e2e-test/README.md index 139213c0c1..f3692de2a7 100644 --- a/packages/e2e-test/README.md +++ b/packages/e2e-test/README.md @@ -11,7 +11,7 @@ All packages need to be installed and built before running the test. In a fresh ```sh yarn install yarn tsc -yarn build +yarn build:all ``` Once those tasks have completed, you can now run the test using `yarn e2e-test run`. diff --git a/packages/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts index 3f9d28eadd..fe4d87bea4 100644 --- a/packages/e2e-test/src/commands/run.ts +++ b/packages/e2e-test/src/commands/run.ts @@ -275,7 +275,7 @@ async function createApp( for (const cmd of [ 'install', 'tsc:full', - 'build', + 'build:all', 'lint:all', 'prettier:check', 'test:all', @@ -507,6 +507,7 @@ async function testBackendStart(appDir: string, ...args: string[]) { // Skipping the whole block throw new Error(stderr); } + await new Promise(resolve => setTimeout(resolve, 500)); print('Try to fetch entities from the backend'); // Try fetch entities, should be ok diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index f64792a5a3..c2ed34574e 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/errors +## 1.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + ## 1.1.3-next.0 ### Patch Changes diff --git a/packages/errors/package.json b/packages/errors/package.json index 9b9e0dcd1d..91ec9b68b1 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/errors", "description": "Common utilities for error handling within Backstage", - "version": "1.1.3-next.0", + "version": "1.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index b396593d12..8b0d83db82 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/integration-react +## 1.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## 1.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + ## 1.1.6-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 7efea2e74a..4267d46758 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "1.1.6-next.0", + "version": "1.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 4c34e91f8d..2789af6f60 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/integration +## 1.4.0 + +### Minor Changes + +- d05e1841ce: This patch brings Gitea as a valid integration: target, via the ScmIntegration interface. It adds gitea to the relevant static properties (get integration by name, get integration by type) for plugins to be able to reference the same Gitea server. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. + + Deprecates: + + - `getGitHubFileFetchUrl` replaced by `getGithubFileFetchUrl` + - `GitHubIntegrationConfig` replaced by `GithubIntegrationConfig` + - `GitHubIntegration` replaced by `GithubIntegration` + - `readGitHubIntegrationConfig` replaced by `readGithubIntegrationConfig` + - `readGitHubIntegrationConfigs` replaced by `readGithubIntegrationConfigs` + - `replaceGitHubUrlType` replaced by `replaceGithubUrlType` + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + ## 1.4.0-next.0 ### Minor Changes diff --git a/packages/integration/config.d.ts b/packages/integration/config.d.ts index 49a121aff3..a1eb7aceb9 100644 --- a/packages/integration/config.d.ts +++ b/packages/integration/config.d.ts @@ -189,6 +189,14 @@ export interface Config { * @visibility secret */ clientSecret: string; + /** + * List of installation owners allowed to be used by this GitHub app. The GitHub UI does not provide a way to list the installations. + * However you can list the installations with the GitHub API. You can find the list of installations here: + * https://api.github.com/app/installations + * The relevant documentation for this is here. + * https://docs.github.com/en/rest/reference/apps#list-installations-for-the-authenticated-app--code-samples + */ + allowedInstallationOwners?: string[]; }>; }>; diff --git a/packages/integration/package.json b/packages/integration/package.json index bbed7de2d1..77f1bd05d7 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.4.0-next.0", + "version": "1.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@backstage/config-loader": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/packages/release-manifests/CHANGELOG.md b/packages/release-manifests/CHANGELOG.md index 177ea55a5a..148df0a1a7 100644 --- a/packages/release-manifests/CHANGELOG.md +++ b/packages/release-manifests/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/release-manifests +## 0.0.7 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + +## 0.0.7-next.0 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + ## 0.0.6 ### Patch Changes diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 949cd2bcd5..633ddee0ca 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/release-manifests", "description": "Helper library for receiving release manifests", - "version": "0.0.6", + "version": "0.0.7", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -38,7 +38,7 @@ "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/node": "^16.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 272555df70..6a53f993c8 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -17,7 +17,11 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { setupRequestMockHandlers } from '@backstage/test-utils'; -import { getManifestByReleaseLine, getManifestByVersion } from './manifest'; +import { + getManifestByReleaseLine, + getManifestByVersion, + withFallback, +} from './manifest'; describe('Release Manifests', () => { const worker = setupServer(); @@ -86,3 +90,50 @@ describe('Release Manifests', () => { }); }); }); + +describe('withFallback', () => { + it('should use the first value to resolve', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.resolve(1)); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 100)).resolves.toBe(1); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2).not.toHaveBeenCalled(); + }); + + it('should fall back on rejection', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('1'))); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 0)).resolves.toBe(2); + expect(fn1.mock.lastCall?.[0].aborted).toBe(true); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should fall back on timeout', async () => { + const fn1 = jest.fn((_s: AbortSignal) => new Promise(() => {})); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 0)).resolves.toBe(2); + expect(fn1.mock.lastCall?.[0].aborted).toBe(true); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should always reject with the first error', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('1'))); + const fn2 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('2'))); + await expect(withFallback(fn1, fn2, 0)).rejects.toThrow('1'); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should always reject with the first error even if rejected after', async () => { + const fn1 = jest.fn( + (_s: AbortSignal) => + new Promise((_resolve, reject) => { + setTimeout(() => reject(new Error('1')), 100); + }), + ); + const fn2 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('2'))); + await expect(withFallback(fn1, fn2, 0)).rejects.toThrow('1'); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); +}); diff --git a/packages/release-manifests/src/manifest.ts b/packages/release-manifests/src/manifest.ts index 955cf7308c..004ccfc77c 100644 --- a/packages/release-manifests/src/manifest.ts +++ b/packages/release-manifests/src/manifest.ts @@ -16,7 +16,9 @@ import fetch from 'cross-fetch'; -const VERSIONS_DOMAIN = 'https://versions.backstage.io'; +const VERSIONS_BASE_URL = 'https://versions.backstage.io'; +const GITHUB_RAW_BASE_URL = + 'https://raw.githubusercontent.com/backstage/versions/main'; /** * Contains mapping between Backstage release and package versions. @@ -35,6 +37,45 @@ export type GetManifestByVersionOptions = { version: string; }; +// Wait for waitMs, or until signal is aborted. +function wait(waitMs: number, signal: AbortSignal) { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + if (!signal.aborted) { + resolve(); + } + }, waitMs); + signal.addEventListener('abort', () => { + clearTimeout(timeout); + reject(new Error('Aborted')); + }); + }); +} + +// Run fn1 and then fn2 after fallbackDelayMs. Whichever one finishes +// first wins, and the other one is aborted through the provided signal. +export async function withFallback( + fn1: (signal: AbortSignal) => Promise, + fn2: (signal: AbortSignal) => Promise, + fallbackDelayMs: number, +): Promise { + const c1 = new AbortController(); + const c2 = new AbortController(); + + const promise1 = fn1(c1.signal).then(res => { + c2.abort(); + return res; + }); + const promise2 = wait(fallbackDelayMs, c2.signal) + .then(() => fn2(c2.signal)) + .then(res => { + c1.abort(); + return res; + }); + + return Promise.any([promise1, promise2]).catch(() => promise1); +} + /** * Returns a release manifest based on supplied version. * @public @@ -42,19 +83,27 @@ export type GetManifestByVersionOptions = { export async function getManifestByVersion( options: GetManifestByVersionOptions, ): Promise { - const url = `${VERSIONS_DOMAIN}/v1/releases/${encodeURIComponent( - options.version, - )}/manifest.json`; - const response = await fetch(url); - if (response.status === 404) { + const versionEnc = encodeURIComponent(options.version); + const res = await withFallback( + signal => + fetch(`${VERSIONS_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { + signal, + }), + signal => + fetch(`${GITHUB_RAW_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { + signal, + }), + 500, + ); + if (res.status === 404) { throw new Error(`No release found for ${options.version} version`); } - if (response.status !== 200) { + if (res.status !== 200) { throw new Error( - `Unexpected response status ${response.status} when fetching release from ${url}.`, + `Unexpected response status ${res.status} when fetching release from ${res.url}.`, ); } - return await response.json(); + return res.json(); } /** @@ -72,17 +121,31 @@ export type GetManifestByReleaseLineOptions = { export async function getManifestByReleaseLine( options: GetManifestByReleaseLineOptions, ): Promise { - const url = `${VERSIONS_DOMAIN}/v1/tags/${encodeURIComponent( - options.releaseLine, - )}/manifest.json`; - const response = await fetch(url); - if (response.status === 404) { + const releaseEnc = encodeURIComponent(options.releaseLine); + const res = await withFallback( + signal => + fetch(`${VERSIONS_BASE_URL}/v1/tags/${releaseEnc}/manifest.json`, { + signal, + }), + async signal => { + // The release tags are symlinks, which we need to follow manually when fetching from GitHub. + const baseUrl = `${GITHUB_RAW_BASE_URL}/v1/tags/${releaseEnc}`; + const linkRes = await fetch(baseUrl, { signal }); + if (!linkRes.ok) { + return linkRes; + } + const link = (await linkRes.text()).trim(); + return fetch(new URL(`${link}/manifest.json`, baseUrl), { signal }); + }, + 1000, + ); + if (res.status === 404) { throw new Error(`No '${options.releaseLine}' release line found`); } - if (response.status !== 200) { + if (res.status !== 200) { throw new Error( - `Unexpected response status ${response.status} when fetching release from ${url}.`, + `Unexpected response status ${res.status} when fetching release from ${res.url}.`, ); } - return await response.json(); + return res.json(); } diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 35515eb5d2..6308ca41ad 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,43 @@ # techdocs-cli-embedded-app +## 0.2.76 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-catalog@1.6.1 + - @backstage/app-defaults@1.0.8 + - @backstage/integration-react@1.1.6 + - @backstage/test-utils@1.2.2 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## 0.2.76-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 0.2.76-next.1 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 740889a661..03794a9363 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.76-next.1", + "version": "0.2.76", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli-embedded-app/public/index.html b/packages/techdocs-cli-embedded-app/public/index.html index b548d8fb70..c6083b3dd2 100644 --- a/packages/techdocs-cli-embedded-app/public/index.html +++ b/packages/techdocs-cli-embedded-app/public/index.html @@ -54,8 +54,8 @@ You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the tag. - To begin the development, run `npm start` or `yarn start`. - To create a production bundle, use `npm run build` or `yarn build`. + To begin the development, run `yarn start`. + To create a production bundle, use `yarn build`. --> diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 26f085b6ce..af177189a2 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,27 @@ # @techdocs/cli +## 1.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-techdocs-node@1.4.2 + - @backstage/catalog-model@1.1.3 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4 + +## 1.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + ## 1.2.3-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 10b738c025..16d9ede690 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.2.3-next.0", + "version": "1.2.3", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index c2e2975656..051b487fda 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7 + ## 1.2.2-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 70e6dca4cc..fb8dff4192 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.2.2-next.0", + "version": "1.2.2", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -45,7 +45,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", @@ -57,7 +57,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 9070442f8f..23a136a9da 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/types +## 1.0.1 + +### Patch Changes + +- 30e43717c7: Added the `HumanDuration` type, moved here from `@backstage/backend-tasks`. This type matches the `Duration.fromObject` form of `luxon`. + ## 1.0.1-next.0 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index a9c340cec3..eaf2723155 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/types", "description": "Common TypeScript types used within Backstage", - "version": "1.0.1-next.0", + "version": "1.0.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/cli": "workspace:^", "@types/zen-observable": "^0.8.0", "luxon": "^3.0.0", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "files": [ "dist" diff --git a/packages/version-bridge/CHANGELOG.md b/packages/version-bridge/CHANGELOG.md index c3c3a9a57f..a36630e594 100644 --- a/packages/version-bridge/CHANGELOG.md +++ b/packages/version-bridge/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/version-bridge +## 1.0.2 + +### Patch Changes + +- e70984325d: Updated the value created by `createVersionedValueMap` to give it an extra hidden property that makes it easier to inspect during debugging. + ## 1.0.1 ### Patch Changes diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 3abfcd40f6..736ae4037b 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/version-bridge", "description": "Utilities used by @backstage packages to support multiple concurrent versions", - "version": "1.0.1", + "version": "1.0.2", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/version-bridge/src/lib/VersionedValue.ts b/packages/version-bridge/src/lib/VersionedValue.ts index b7c2153e38..51a9fd7879 100644 --- a/packages/version-bridge/src/lib/VersionedValue.ts +++ b/packages/version-bridge/src/lib/VersionedValue.ts @@ -36,9 +36,17 @@ export function createVersionedValueMap< Versions extends { [version: number]: unknown }, >(versions: Versions): VersionedValue { Object.freeze(versions); - return { + const versionedValue: VersionedValue = { atVersion(version) { return versions[version]; }, }; + Object.defineProperty(versionedValue, '$map', { + configurable: true, + enumerable: true, + get() { + return versions; + }, + }); + return versionedValue; } diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 84143ccf78..d63b5909a6 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-adr-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-adr-common@0.2.3 + - @backstage/plugin-search-common@1.1.1 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index ccbd3f119e..f22cc06543 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.2.3-next.0", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@backstage/cli": "workspace:^", "@types/marked": "^4.0.0", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index f9093a1dcf..fb97b9bcaf 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-search-common@1.1.1 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index e9a9edc597..2ed4532a15 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.2.3-next.0", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index e1f34381e4..e18d2695ba 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-adr +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3 + - @backstage/plugin-search-common@1.1.1 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index e6113c7a83..163ad2d656 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.2.3-next.0", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@types/git-url-parse": "^9.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index 38ed0acbc7..4cd5d7ea5b 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-airbrake-backend +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index f8904563a4..915ffcec84 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.2.11-next.0", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/cli": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index a714e4d69f..b9f61927b2 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-airbrake +## 0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/dev-utils@1.0.8 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/dev-utils@1.0.8-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 3f04501019..c2d4696dd4 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.11-next.0", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@types/node": "^16.11.26", "@types/object-hash": "^2.2.1", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 0f57d596c5..09663e7363 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-allure +## 0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 68808cf511..5c89e152ac 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.27-next.0", + "version": "0.1.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 149215b223..96a16a46f5 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-analytics-module-ga +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index ac94ad8979..33a1b973ea 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.22-next.0", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index b4dee086eb..a1845e0030 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-apache-airflow +## 0.2.4 + +### Patch Changes + +- 989731cabf: 1. Added a new column in the table to quickly view the latest DAG runs, plus a link to it if you want to have a deeper look. 2. Table columns are togglable 3. Set hidden columns 4. Fixed bug with turning on/off the DAGs +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index bba1177b06..af174da0ea 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.2.4-next.0", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts index 838292524a..128f6e551d 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts @@ -16,6 +16,7 @@ import { createApiRef, DiscoveryApi } from '@backstage/core-plugin-api'; import { Dag, InstanceStatus, InstanceVersion } from './types'; +import { DagRun } from './types/Dags'; export const apacheAirflowApiRef = createApiRef({ id: 'plugin.apacheairflow.service', @@ -27,6 +28,10 @@ export type ApacheAirflowApi = { listDags(options?: { objectsPerRequest: number }): Promise; getDags(dagIds: string[]): Promise<{ dags: Dag[]; dagsNotFound: string[] }>; updateDag(dagId: string, isPaused: boolean): Promise; + getDagRuns( + dagId: string, + options?: { objectsPerRequest?: number; limit?: number }, + ): Promise; getInstanceStatus(): Promise; getInstanceVersion(): Promise; }; diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts index b9bdb02283..ab0565f4e4 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts @@ -20,6 +20,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ApacheAirflowClient } from './index'; import { Dag } from './types'; +import { DagRun } from './types/Dags'; const server = setupServer(); @@ -66,12 +67,45 @@ const dags: Dag[] = [ }, ]; +const dagRuns: DagRun[] = [ + { + dag_run_id: 'mock dag run 1', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'success', + external_trigger: true, + conf: {}, + }, + { + dag_run_id: 'mock dag run 2', + dag_id: 'mock_dag_2', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'running', + external_trigger: true, + conf: {}, + }, + { + dag_run_id: 'mock dag run 3', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'failed', + external_trigger: true, + conf: {}, + }, +]; + describe('ApacheAirflowClient', () => { setupRequestMockHandlers(server); const mockBaseUrl = 'http://backstage:9191/api/proxy'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); - + let client: ApacheAirflowClient; const setupHandlers = () => { server.use( rest.get(`${mockBaseUrl}/airflow/dags`, (req, res, ctx) => { @@ -116,41 +150,61 @@ describe('ApacheAirflowClient', () => { return res(ctx.status(404)); }), - rest.patch(`${mockBaseUrl}/airflow/dags/:dag_id`, (req, res, ctx) => { - const { dag_id } = req.params; - const body = JSON.parse(req.body as string); - expect(body.is_paused).toBeDefined(); - return res( - ctx.json({ - dag_id: dag_id, - root_dag_id: 'string', - is_paused: body.is_paused, - is_active: true, - is_subdag: true, - fileloc: 'string', - file_token: 'string', - owners: ['string'], - description: 'string', - schedule_interval: { - __type: 'string', - days: 0, - seconds: 0, - microseconds: 0, - }, - tags: [{}], - }), - ); - }), + rest.get( + `${mockBaseUrl}/airflow/dags/:dag_id/dagRuns`, + (req, res, ctx) => { + const { dag_id } = req.params; + const runs = dagRuns.filter(run => run.dag_id === dag_id); + // event if the dag_id is invalid, airflow returns a valid response (with 0 dag runs) + return res( + ctx.json({ + dag_runs: runs, + total_entries: runs.length, + }), + ); + }, + ), + + rest.patch( + `${mockBaseUrl}/airflow/dags/:dag_id`, + async (req, res, ctx) => { + const { dag_id } = req.params; + const body = JSON.parse(await req.text()); + expect(body.is_paused).toBeDefined(); + return res( + ctx.json({ + dag_id: dag_id, + root_dag_id: 'string', + is_paused: body.is_paused, + is_active: true, + is_subdag: true, + fileloc: 'string', + file_token: 'string', + owners: ['string'], + description: 'string', + schedule_interval: { + __type: 'string', + days: 0, + seconds: 0, + microseconds: 0, + }, + tags: [{}], + }), + ); + }, + ), ); }; - it('list dags should return all dags with emulated pagination', async () => { + beforeEach(() => { setupHandlers(); - const client = new ApacheAirflowClient({ + client = new ApacheAirflowClient({ discoveryApi: discoveryApi, baseUrl: 'localhost:8080/', }); + }); + it('list dags should return all dags with emulated pagination', async () => { // call with limit of 2, to force two paginations in requesting all dags // as our mocked response has 4 total entries const responseDags = await client.listDags({ objectsPerRequest: 2 }); @@ -159,11 +213,6 @@ describe('ApacheAirflowClient', () => { }); it('update dag should return dag information with updated paused attribute', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagId = 'mock_dag_1'; const response: Dag = await client.updateDag(dagId, true); expect(response.dag_id).toEqual(dagId); @@ -171,11 +220,6 @@ describe('ApacheAirflowClient', () => { }); it('get only some dags', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagIds = ['mock_dag_1', 'mock_dag_3']; const response = await client.getDags(dagIds); expect(response.dags.length).toEqual(dagIds.length); @@ -186,11 +230,6 @@ describe('ApacheAirflowClient', () => { }); it('get dags but ignore NOT FOUND errors', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagIds = ['mock_dag_1', 'a-random-DAG-id']; const response = await client.getDags(dagIds); expect(response.dags.length).toEqual(1); @@ -198,4 +237,11 @@ describe('ApacheAirflowClient', () => { expect(response.dagsNotFound.length).toEqual(1); expect(response.dagsNotFound[0]).toEqual('a-random-DAG-id'); }); + + it('should get dag runs', async () => { + const dagId = 'mock_dag_1'; + const response = await client.getDagRuns(dagId); + expect(response.length).toEqual(2); + response.forEach(run => expect(run.dag_id).toEqual(dagId)); + }); }); diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts index c722f5977d..ebd60b668a 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts @@ -25,6 +25,7 @@ import { InstanceVersion, ListDagsParams, } from './types'; +import { DagRun } from './types/Dags'; export class ApacheAirflowClient implements ApacheAirflowApi { discoveryApi: DiscoveryApi; @@ -97,11 +98,56 @@ export class ApacheAirflowClient implements ApacheAirflowApi { async updateDag(dagId: string, isPaused: boolean): Promise { const init = { method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, body: JSON.stringify({ is_paused: isPaused }), }; return await this.fetch(`/dags/${dagId}`, init); } + /** + * Get the latest DAG Runs of a specific DAG. + * The DAG runs are ordered by start date + * + * @remarks + * + * The "limit" option means the maximum number of DAG runs to return + * "objectsPerRequest" means the maximum number of DAG runs to be taken per fetch request. + * This is just to make sure the response payloads are not too big + */ + async getDagRuns( + dagId: string, + options = { objectsPerRequest: 100, limit: 5 }, + ): Promise { + const dagRuns: DagRun[] = []; + const searchParams: ListDagsParams = { + limit: Math.min(options.objectsPerRequest || 100, options.limit || 5), + offset: 0, + order_by: '-start_date', + }; + + for (;;) { + const response = await this.fetch<{ + dag_runs: DagRun[]; + total_entries: number; + }>(`/dags/${dagId}/dagRuns?${qs.stringify(searchParams)}`); + dagRuns.push(...response.dag_runs); + + if (response.dag_runs.length < searchParams.limit!) { + break; + } + if ( + dagRuns.length >= response.total_entries || + dagRuns.length >= options.limit + ) { + break; + } + searchParams.offset! += response.dag_runs.length; + } + return dagRuns; + } + async getInstanceStatus(): Promise { return await this.fetch('/health'); } diff --git a/plugins/apache-airflow/src/api/types/Dags.ts b/plugins/apache-airflow/src/api/types/Dags.ts index 8f1d68fb2d..702a6470e7 100644 --- a/plugins/apache-airflow/src/api/types/Dags.ts +++ b/plugins/apache-airflow/src/api/types/Dags.ts @@ -44,6 +44,17 @@ export interface Dag { tags: Tag[]; } +export interface DagRun { + dag_run_id: string; + dag_id: string; + logical_date: string; + start_date: string; + end_date: string; + state: 'queued' | 'running' | 'success' | 'failed'; + external_trigger: boolean; + conf: {}; +} + export interface TimeDelta { __type: 'TimeDelta'; days: number; diff --git a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx index fcd87b2020..2660e9380e 100644 --- a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx +++ b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx @@ -22,7 +22,7 @@ import { TableColumn, WarningPanel, } from '@backstage/core-components'; -import { useApi } from '@backstage/core-plugin-api'; +import { storageApiRef, useApi } from '@backstage/core-plugin-api'; import Box from '@material-ui/core/Box'; import Chip from '@material-ui/core/Chip'; import IconButton from '@material-ui/core/IconButton'; @@ -31,101 +31,151 @@ import Tooltip from '@material-ui/core/Tooltip'; import Typography from '@material-ui/core/Typography'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import Alert from '@material-ui/lab/Alert'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import { apacheAirflowApiRef } from '../../api'; import { Dag } from '../../api/types'; import { ScheduleIntervalLabel } from '../ScheduleIntervalLabel'; +import { LatestDagRunsStatus } from '../LatestDagRunsStatus'; type DagTableRow = Dag & { id: string; dagUrl: string; }; -const columns: TableColumn[] = [ - { - title: 'Paused', - field: 'is_paused', - render: (row: Partial) => ( - - - - ), - width: '5%', - }, - { - title: 'DAG', - field: 'id', - render: (row: Partial) => ( -
- - {row.id} - - - {row.tags?.map((tag, ix) => ( - - ))} - -
- ), - width: '60%', - }, - { - title: 'Owner', - field: 'owners', - render: (row: Partial) => ( - - {row.owners?.map((owner, ix) => ( - - ))} - - ), - width: '10%', - }, - { - title: 'Active', - render: (row: Partial) => ( - - {row.is_active ? : } - - {row.is_active ? 'Active' : 'Inactive'} - - - ), - width: '10%', - }, - { - title: 'Schedule', - render: (row: Partial) => ( - - ), - width: '10%', - }, - { - title: 'Link', - field: 'dagUrl', - render: (row: Partial) => ( - - - - - - ), - width: '5%', - }, -]; - type DenseTableProps = { dags: Dag[]; + rowClick: Function; }; -export const DenseTable = ({ dags }: DenseTableProps) => { +export const DenseTable = ({ dags, rowClick }: DenseTableProps) => { + const storage = useApi(storageApiRef); + const hiddenColumnsKey = 'dag-table-hidden-columns'; + const [hiddenColumns, setHiddenColumns] = useState([]); + + useEffect(() => { + const hiddenState = storage.snapshot(hiddenColumnsKey); + if (hiddenState.presence === 'present') { + setHiddenColumns(hiddenState.value as string[]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const columns: TableColumn[] = [ + { + title: 'Paused', + field: 'is_paused', + render: (row: Partial) => ( + + + + ), + width: '5%', + hidden: hiddenColumns.some(field => field === 'is_paused'), + }, + { + title: 'DAG', + field: 'id', + render: (row: Partial) => ( +
+ + {row.id} + + + {row.tags?.map((tag, ix) => ( + + ))} + +
+ ), + width: '50%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'id'), + }, + { + title: 'Runs', + field: 'runs', + render: (row: Partial) => ( + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'runs'), + }, + { + title: 'Owner', + field: 'owners', + render: (row: Partial) => ( + + {row.owners?.map((owner, ix) => ( + + ))} + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'owners'), + }, + { + title: 'Active', + field: 'active', + render: (row: Partial) => ( + + {row.is_active ? : } + + {row.is_active ? 'Active' : 'Inactive'} + + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'active'), + }, + { + title: 'Schedule', + field: 'schedule', + render: (row: Partial) => ( + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'schedule'), + }, + { + title: 'Link', + field: 'dagUrl', + render: (row: Partial) => ( + + + + + + ), + width: '5%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'dagUrl'), + }, + ]; + return ( rowClick(rowData)} + onChangeColumnHidden={(column, hidden) => { + if (column.field) { + let newHiddenColumns: string[]; + if (hidden) { + newHiddenColumns = hiddenColumns.concat(column.field); + } else { + newHiddenColumns = hiddenColumns.filter(v => v !== column.field); + } + setHiddenColumns(newHiddenColumns); + storage.set(hiddenColumnsKey, newHiddenColumns); + } + }} /> ); }; @@ -136,27 +186,54 @@ type DagTableComponentProps = { export const DagTableComponent = (props: DagTableComponentProps) => { const { dagIds } = props; + const [dagsData, setDagsData] = useState([]); const apiClient = useApi(apacheAirflowApiRef); - const { value, loading, error } = useAsync(async (): Promise => { + const updatePaused = async (rowData: Dag): Promise => { + const newDag = await apiClient.updateDag( + rowData.dag_id, + !rowData.is_paused, + ); + + const newDags = dagsData.map(el => { + if (el.dag_id === newDag.dag_id) { + return { ...el, is_paused: newDag.is_paused }; + } + return el; + }); + + setDagsData(newDags); + return newDag; + }; + + const { value, loading, error } = useAsync(async (): Promise< + DagTableRow[] + > => { + let dags: Dag[] = []; if (dagIds) { - const { dags } = await apiClient.getDags(dagIds); - return dags; + dags = (await apiClient.getDags(dagIds)).dags; + } else { + dags = await apiClient.listDags(); } - return await apiClient.listDags(); + return dags.map(el => ({ + ...el, + id: el.dag_id, // table records require `id` attribute + dagUrl: `${apiClient.baseUrl}dag_details?dag_id=${el.dag_id}`, // construct path to DAG using `baseUrl` + })); }, []); + useEffect(() => { + if (value) { + setDagsData(value); + } + }, [value]); + if (loading) { return ; } else if (error) { return {error.message}; } - const data = value?.map(el => ({ - ...el, - id: el.dag_id, // table records require `id` attribute - dagUrl: `${apiClient.baseUrl}dag_details?dag_id=${el.dag_id}`, // construct path to DAG using `baseUrl` - })); const dagsNotFound = dagIds && value ? dagIds.filter(id => !value.find(d => d.dag_id === id)) @@ -172,7 +249,7 @@ export const DagTableComponent = (props: DagTableComponentProps) => { ) : ( '' )} - + ); }; diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx new file mode 100644 index 0000000000..fb020ee9e9 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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 { ApacheAirflowApi, apacheAirflowApiRef } from '../../api'; +import { DagRun } from '../../api/types/Dags'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; +import { LatestDagRunsStatus } from './LatestDagRunsStatus'; + +describe('LatestDagRunsStatus', () => { + const baseDagRun: Partial = { + dag_run_id: 'mock dag run 1', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'success', + external_trigger: true, + conf: {}, + }; + const mockApi: jest.Mocked = { + getDagRuns: jest.fn().mockResolvedValue([ + baseDagRun, + { + ...baseDagRun, + dag_run_id: 'mock dag run 2', + state: 'running', + }, + { + ...baseDagRun, + dag_run_id: 'mock dag run 3', + state: 'failed', + }, + { + ...baseDagRun, + dag_run_id: 'mock dag run 3', + state: 'queued', + }, + ] as DagRun[]), + } as any; + + it('should render the status of mock dag 1', async () => { + const dagId = 'mock_dag_1'; + + const { getByLabelText } = await renderInTestApp( + + + , + ); + expect(getByLabelText('Status ok')).toBeInTheDocument(); + expect(getByLabelText('Status running')).toBeInTheDocument(); + expect(getByLabelText('Status error')).toBeInTheDocument(); + expect(getByLabelText('Status pending')).toBeInTheDocument(); + }); +}); diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx new file mode 100644 index 0000000000..90cb0694f8 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx @@ -0,0 +1,161 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { apacheAirflowApiRef } from '../../api'; +import useAsync from 'react-use/lib/useAsync'; +import { DagRun } from '../../api/types/Dags'; +import { useApi } from '@backstage/core-plugin-api'; +import { + Box, + Button, + CircularProgress, + List, + ListItem, + ListItemIcon, + makeStyles, + Tooltip, + Typography, +} from '@material-ui/core'; +import { + Link, + StatusError, + StatusOK, + StatusPending, + StatusRunning, +} from '@backstage/core-components'; +import DirectionsRun from '@material-ui/icons/DirectionsRun'; +import Check from '@material-ui/icons/Check'; +import CalendarToday from '@material-ui/icons/CalendarToday'; +import qs from 'qs'; +import AccountTree from '@material-ui/icons/AccountTree'; + +interface LatestDagRunsStatusProps { + dagId: string; + limit?: number; +} + +const useStyles = makeStyles(() => ({ + noMaxWidth: { + maxWidth: 'none', + }, +})); + +const DagRunTooltip = ({ + dagRun, + graphUrl, +}: { + dagRun: DagRun; + graphUrl: string; +}) => { + return ( + + + + + + {dagRun.dag_run_id} + + + + + + {new Date(dagRun.start_date).toLocaleString()} + + + + + + + {dagRun.end_date ? new Date(dagRun.end_date).toLocaleString() : '-'} + + + + + + + ); +}; + +export const LatestDagRunsStatus = ({ + dagId, + limit = 5, +}: LatestDagRunsStatusProps) => { + const classes = useStyles(); + const apiClient = useApi(apacheAirflowApiRef); + const { value, loading, error } = useAsync( + async (): Promise => await apiClient.getDagRuns(dagId, { limit }), + [dagId, limit], + ); + + if (loading) { + return ( + + + + ); + } + + if (error) { + return Can't get dag runs; + } + + const statusDots: JSX.Element[] | undefined = value?.map(dagRun => { + function status() { + switch (dagRun.state) { + case 'success': + return ; + case 'failed': + return ; + case 'running': + return ; + case 'queued': + return ; + default: + return Unrecognized state; + } + } + + const key = dagRun.dag_id + dagRun.dag_run_id; + const dagRunParams = { + dag_id: dagRun.dag_id, + execution_date: dagRun.logical_date, + }; + const graphUrl = `${apiClient.baseUrl}graph?${qs.stringify(dagRunParams)}`; + return ( + } + key={key} + classes={{ tooltip: classes.noMaxWidth }} + interactive + > + + {status()} + + + ); + }); + + return {statusDots}; +}; diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts b/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts new file mode 100644 index 0000000000..acd84a3584 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { LatestDagRunsStatus } from './LatestDagRunsStatus'; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index de93784591..b340f3712e 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-api-docs +## 0.8.11 + +### Patch Changes + +- 4db78c2296: Updated dependency `@asyncapi/react-component` to `1.0.0-next.44`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-catalog@1.6.1 + - @backstage/theme@0.2.16 + +## 0.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.8.11-next.0 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index ecb6fe3ff4..db3a86c19b 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.8.11-next.0", + "version": "0.8.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.0.0-next.43", + "@asyncapi/react-component": "1.0.0-next.44", "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", @@ -66,7 +66,7 @@ "@types/node": "^16.11.26", "@types/swagger-ui-react": "^4.1.1", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 5ef5cb16f9..e5d8786870 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-apollo-explorer +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 91fe56950e..62d697317a 100644 --- a/plugins/apollo-explorer/package.json +++ b/plugins/apollo-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apollo-explorer", - "version": "0.1.4-next.0", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 81c2020152..f08415c4fb 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-app-backend +## 0.3.38 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 + - @backstage/config-loader@1.1.6 + +## 0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.3.38-next.0 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 5e72d7b666..cc772a843a 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.38-next.0", + "version": "0.3.38", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -58,7 +58,7 @@ "@types/supertest": "^2.0.8", "get-port": "^6.1.2", "mock-fs": "^5.1.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "node-fetch": "^2.6.7", "supertest": "^6.1.3" }, diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index a65fa417d8..a89be139f1 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-auth-backend +## 0.17.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- cbe11d1e23: Tweak README +- 89d705e806: Add support for custom JWT header name in GCP IAP auth. +- abaed9770e: Improve logging +- d80833fe0c: Inject optional `CatalogApi` into auth-backend `createRouter` function. This will enable developers to use customized `CatalogApi` when creating the router. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.17.1-next.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- abaed9770e: Improve logging +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.17.1-next.0 ### Patch Changes diff --git a/plugins/auth-backend/README.md b/plugins/auth-backend/README.md index d13a5e5a20..ba0042c6f9 100644 --- a/plugins/auth-backend/README.md +++ b/plugins/auth-backend/README.md @@ -34,8 +34,8 @@ Follow this link, [Create new OAuth App](https://github.com/settings/application 1. Set Application Name to `backstage-dev` or something along those lines. 1. You can set the Homepage URL to whatever you want to. 1. The Authorization Callback URL should match the redirect URI set in Backstage. - 1. Set this to `http://localhost:7007/api/auth/github` for local development. - 1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/github` for non-local deployments. + 1. Set this to `http://localhost:7007/api/auth/github/handler/frame` for local development. + 1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/github/handler/frame` for non-local deployments. ```bash export AUTH_GITHUB_CLIENT_ID=x diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index cc6962cdbe..cec3422d9c 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -669,6 +669,8 @@ export const readState: (stateString: string) => OAuthState; // @public (undocumented) export interface RouterOptions { + // (undocumented) + catalogApi?: CatalogApi; // (undocumented) config: Config; // (undocumented) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 4b3d7910e5..a3b5c5d158 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.17.1-next.0", + "version": "0.17.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "morgan": "^1.10.0", "node-cache": "^5.1.2", "node-fetch": "^2.6.7", - "openid-client": "^5.1.3", + "openid-client": "^5.2.1", "passport": "^0.6.0", "passport-auth0": "^1.4.3", "passport-bitbucket-oauth2": "^0.1.2", @@ -89,7 +89,7 @@ "@types/passport-saml": "^1.1.3", "@types/passport-strategy": "^0.2.35", "@types/xml2js": "^0.4.7", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index e4d9304892..96cd8d32cb 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -24,7 +24,7 @@ import { import { CatalogIdentityClient } from './CatalogIdentityClient'; describe('CatalogIdentityClient', () => { - const catalogApi: jest.Mocked = { + const catalogApi = { getLocationById: jest.fn(), getEntityByRef: jest.fn(), getEntities: jest.fn(), @@ -48,7 +48,7 @@ describe('CatalogIdentityClient', () => { catalogApi.getEntities.mockResolvedValueOnce({ items: [{} as UserEntity] }); tokenManager.getToken.mockResolvedValue({ token: 'my-token' }); const client = new CatalogIdentityClient({ - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, tokenManager, }); @@ -106,7 +106,7 @@ describe('CatalogIdentityClient', () => { tokenManager.getToken.mockResolvedValue({ token: 'my-token' }); const client = new CatalogIdentityClient({ - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, tokenManager, }); diff --git a/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts b/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts index c0e351c90b..0162366f61 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts @@ -95,19 +95,19 @@ describe('helpers', () => { parseRequestToken(7, undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); await expect( parseRequestToken(undefined, undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); await expect( parseRequestToken('', undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); }); diff --git a/plugins/auth-backend/src/providers/gcp-iap/helpers.ts b/plugins/auth-backend/src/providers/gcp-iap/helpers.ts index c7e81adc73..26d9a8c904 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/helpers.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/helpers.ts @@ -17,7 +17,7 @@ import { AuthenticationError } from '@backstage/errors'; import { OAuth2Client, TokenPayload } from 'google-auth-library'; import { AuthHandler } from '../types'; -import { GcpIapResult, IAP_JWT_HEADER } from './types'; +import { GcpIapResult } from './types'; export function createTokenValidator( audience: string, @@ -52,9 +52,7 @@ export async function parseRequestToken( tokenValidator: (token: string) => Promise, ): Promise { if (typeof jwtToken !== 'string' || !jwtToken) { - throw new AuthenticationError( - `Missing Google IAP header: ${IAP_JWT_HEADER}`, - ); + throw new AuthenticationError('Missing Google IAP header'); } let payload: TokenPayload; diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts index b1b2a3f66e..c01db3a853 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts @@ -18,6 +18,7 @@ import express from 'express'; import request from 'supertest'; import { AuthResolverContext } from '../types'; import { GcpIapProvider } from './provider'; +import { DEFAULT_IAP_JWT_HEADER } from './types'; beforeEach(() => { jest.clearAllMocks(); @@ -28,44 +29,47 @@ describe('GcpIapProvider', () => { const signInResolver = jest.fn(); const tokenValidator = jest.fn(); - it('runs the happy path', async () => { - const provider = new GcpIapProvider({ - authHandler, - signInResolver, - tokenValidator, - resolverContext: {} as AuthResolverContext, - }); + it.each([undefined, 'x-custom-header'])( + 'runs the happy path', + async jwtHeader => { + const provider = new GcpIapProvider({ + authHandler, + signInResolver, + tokenValidator, + resolverContext: {} as AuthResolverContext, + jwtHeader: jwtHeader, + }); - // { "sub": "user:default/me", "ent": ["group:default/home"] } - const backstageToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvbWUiLCJlbnQiOlsiZ3JvdXA6ZGVmYXVsdC9ob21lIl19.CbmAKzFErGmtsnpRxyPc7dHv7WEjb5lY6206YCzR_Rc'; - const iapToken = { sub: 's', email: 'e@mail.com' }; + // { "sub": "user:default/me", "ent": ["group:default/home"] } + const backstageToken = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvbWUiLCJlbnQiOlsiZ3JvdXA6ZGVmYXVsdC9ob21lIl19.CbmAKzFErGmtsnpRxyPc7dHv7WEjb5lY6206YCzR_Rc'; + const iapToken = { sub: 's', email: 'e@mail.com' }; - authHandler.mockResolvedValueOnce({ email: 'e@mail.com' }); - signInResolver.mockResolvedValueOnce({ token: backstageToken }); - tokenValidator.mockResolvedValueOnce(iapToken); + authHandler.mockResolvedValueOnce({ email: 'e@mail.com' }); + signInResolver.mockResolvedValueOnce({ token: backstageToken }); + tokenValidator.mockResolvedValueOnce(iapToken); - const app = express(); - app.use('/refresh', provider.refresh.bind(provider)); + const app = express(); + app.use('/refresh', provider.refresh.bind(provider)); - const response = await request(app) - .get('/refresh') - .set('x-goog-iap-jwt-assertion', 'token'); + const header = jwtHeader || DEFAULT_IAP_JWT_HEADER; + const response = await request(app).get('/refresh').set(header, 'token'); - expect(response.status).toBe(200); - expect(response.get('content-type')).toBe( - 'application/json; charset=utf-8', - ); - expect(response.body).toEqual({ - backstageIdentity: { - token: backstageToken, - identity: { - type: 'user', - userEntityRef: 'user:default/me', - ownershipEntityRefs: ['group:default/home'], + expect(response.status).toBe(200); + expect(response.get('content-type')).toBe( + 'application/json; charset=utf-8', + ); + expect(response.body).toEqual({ + backstageIdentity: { + token: backstageToken, + identity: { + type: 'user', + userEntityRef: 'user:default/me', + ownershipEntityRefs: ['group:default/home'], + }, }, - }, - providerInfo: { iapToken }, - }); - }); + providerInfo: { iapToken }, + }); + }, + ); }); diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.ts index 500b062d5b..7e77853737 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.ts @@ -29,24 +29,27 @@ import { defaultAuthHandler, parseRequestToken, } from './helpers'; -import { GcpIapResponse, GcpIapResult, IAP_JWT_HEADER } from './types'; +import { GcpIapResponse, GcpIapResult, DEFAULT_IAP_JWT_HEADER } from './types'; export class GcpIapProvider implements AuthProviderRouteHandlers { private readonly authHandler: AuthHandler; private readonly signInResolver: SignInResolver; private readonly tokenValidator: (token: string) => Promise; private readonly resolverContext: AuthResolverContext; + private readonly jwtHeader: string; constructor(options: { authHandler: AuthHandler; signInResolver: SignInResolver; tokenValidator: (token: string) => Promise; resolverContext: AuthResolverContext; + jwtHeader?: string; }) { this.authHandler = options.authHandler; this.signInResolver = options.signInResolver; this.tokenValidator = options.tokenValidator; this.resolverContext = options.resolverContext; + this.jwtHeader = options?.jwtHeader || DEFAULT_IAP_JWT_HEADER; } async start() {} @@ -55,7 +58,7 @@ export class GcpIapProvider implements AuthProviderRouteHandlers { async refresh(req: express.Request, res: express.Response): Promise { const result = await parseRequestToken( - req.header(IAP_JWT_HEADER), + req.header(this.jwtHeader), this.tokenValidator, ); @@ -103,6 +106,7 @@ export const gcpIap = createAuthProviderIntegration({ }) { return ({ config, resolverContext }) => { const audience = config.getString('audience'); + const jwtHeader = config.getOptionalString('jwtHeader'); const authHandler = options.authHandler ?? defaultAuthHandler; const signInResolver = options.signIn.resolver; @@ -113,6 +117,7 @@ export const gcpIap = createAuthProviderIntegration({ signInResolver, tokenValidator, resolverContext, + jwtHeader, }); }; }, diff --git a/plugins/auth-backend/src/providers/gcp-iap/types.ts b/plugins/auth-backend/src/providers/gcp-iap/types.ts index 25828b7d51..6519de64ac 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/types.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/types.ts @@ -20,7 +20,7 @@ import { AuthResponse } from '../types'; /** * The header name used by the IAP. */ -export const IAP_JWT_HEADER = 'x-goog-iap-jwt-assertion'; +export const DEFAULT_IAP_JWT_HEADER = 'x-goog-iap-jwt-assertion'; /** * The data extracted from an IAP token. diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 8fd758f1b4..8013777415 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -28,7 +28,7 @@ import { TokenManager, } from '@backstage/backend-common'; import { assertError, NotFoundError } from '@backstage/errors'; -import { CatalogClient } from '@backstage/catalog-client'; +import { CatalogApi, CatalogClient } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { createOidcRouter, TokenFactory, KeyStores } from '../identity'; import session from 'express-session'; @@ -48,6 +48,7 @@ export interface RouterOptions { tokenManager: TokenManager; tokenFactoryAlgorithm?: string; providerFactories?: ProviderFactories; + catalogApi?: CatalogApi; } /** @public */ @@ -62,6 +63,7 @@ export async function createRouter( tokenManager, tokenFactoryAlgorithm, providerFactories, + catalogApi, } = options; const router = Router(); @@ -78,7 +80,6 @@ export async function createRouter( logger: logger.child({ component: 'token-factory' }), algorithm: tokenFactoryAlgorithm, }); - const catalogApi = new CatalogClient({ discoveryApi: discovery }); const secret = config.getOptionalString('auth.session.secret'); if (secret) { @@ -114,7 +115,7 @@ export async function createRouter( allProviderFactories, )) { if (configuredProviders.includes(providerId)) { - logger.info(`Configuring provider, ${providerId}`); + logger.info(`Configuring auth provider: ${providerId}`); try { const provider = providerFactory({ providerId, @@ -127,7 +128,8 @@ export async function createRouter( logger, resolverContext: CatalogAuthResolverContext.create({ logger, - catalogApi, + catalogApi: + catalogApi ?? new CatalogClient({ discoveryApi: discovery }), tokenIssuer, tokenManager, }), diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index aac75b87e9..79bcabe134 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-auth-node +## 0.2.7 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 79dcc6d6b8..af412bbbb7 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.2.7-next.0", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", + "msw": "^0.48.0", "uuid": "^8.0.0" }, "files": [ diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index ae57ae23a9..3f5c5bbca5 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-azure-devops-backend +## 0.3.17 + +### Patch Changes + +- 62f284e394: - Adjusted the asset parser to accept case sensitive + - Fixed fetching data that was using the deprecated function +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/plugin-azure-devops-common@0.3.0 + +## 0.3.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-devops-common@0.3.0 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 50a99dbc2a..d528b2b7fa 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.3.17-next.1", + "version": "0.3.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 1317547b7f..3eb99ef36f 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-azure-devops +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index a2ffd77c84..d86bc871eb 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.2.2-next.0", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index b06742648f..27d237d786 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-azure-sites-backend +## 0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-azure-sites-common@0.1.0 + - @backstage/config@1.0.4 + +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index f6529b7a3d..4b1300220c 100644 --- a/plugins/azure-sites-backend/package.json +++ b/plugins/azure-sites-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites-backend", - "version": "0.1.0-next.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/azure-sites-common/CHANGELOG.md b/plugins/azure-sites-common/CHANGELOG.md index 387e8d9ddd..f210cdf7bb 100644 --- a/plugins/azure-sites-common/CHANGELOG.md +++ b/plugins/azure-sites-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-azure-sites-common +## 0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/azure-sites-common/package.json b/plugins/azure-sites-common/package.json index 568edaeff9..c1bf28c65b 100644 --- a/plugins/azure-sites-common/package.json +++ b/plugins/azure-sites-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-azure-sites-common", "description": "Common functionalities for the azure plugin", - "version": "0.1.0-next.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 4e1b2bb12b..40bc2a2107 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-azure-sites +## 0.1.0 + +### Minor Changes + +- 4a75ce761c: Azure Sites (Apps & Functions) support for a given entity. View the current status of the site, quickly jump to site's Overview page, or Log Stream page. + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-azure-sites-common@0.1.0 + - @backstage/theme@0.2.16 + +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index feff8e8645..3bea29111f 100644 --- a/plugins/azure-sites/package.json +++ b/plugins/azure-sites/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites", - "version": "0.1.0-next.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index c88b7cf763..009a0a63b6 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-badges-backend +## 0.1.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.1.32-next.0 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index a8e465597c..b4f83b2ab6 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.1.32-next.0", + "version": "0.1.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/src/service/router.test.ts b/plugins/badges-backend/src/service/router.test.ts index 9dc60ea1b5..109b64231d 100644 --- a/plugins/badges-backend/src/service/router.test.ts +++ b/plugins/badges-backend/src/service/router.test.ts @@ -29,7 +29,19 @@ import { BadgeBuilder } from '../lib'; describe('createRouter', () => { let app: express.Express; let badgeBuilder: jest.Mocked; - let catalog: jest.Mocked; + const catalog = { + addLocation: jest.fn(), + getEntities: jest.fn(), + getEntityByRef: jest.fn(), + getLocationByRef: jest.fn(), + getLocationById: jest.fn(), + removeLocationById: jest.fn(), + removeEntityByUid: jest.fn(), + refreshEntity: jest.fn(), + getEntityAncestors: jest.fn(), + getEntityFacets: jest.fn(), + validateEntity: jest.fn(), + }; let config: Config; let discovery: PluginEndpointDiscovery; @@ -57,20 +69,6 @@ describe('createRouter', () => { createBadgeJson: jest.fn(), createBadgeSvg: jest.fn(), }; - catalog = { - addLocation: jest.fn(), - getEntities: jest.fn(), - getEntityByRef: jest.fn(), - getLocationByRef: jest.fn(), - getLocationById: jest.fn(), - removeLocationById: jest.fn(), - removeEntityByUid: jest.fn(), - refreshEntity: jest.fn(), - getEntityAncestors: jest.fn(), - getEntityFacets: jest.fn(), - validateEntity: jest.fn(), - }; - config = new ConfigReader({ backend: { baseUrl: 'http://127.0.0.1', @@ -81,7 +79,7 @@ describe('createRouter', () => { const router = await createRouter({ badgeBuilder, - catalog, + catalog: catalog as Partial as CatalogApi, config, discovery, }); @@ -95,7 +93,7 @@ describe('createRouter', () => { it('works', async () => { const router = await createRouter({ badgeBuilder, - catalog, + catalog: catalog as Partial as CatalogApi, config, discovery, }); diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index f736588933..65528d8934 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-badges +## 0.2.35 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.2.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.35-next.0 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 68d47e08ac..62a62969e9 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.35-next.0", + "version": "0.2.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index d0524bd9f5..64f55c9e7a 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-bazaar-backend +## 0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/backend-test-utils@0.1.30 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.1-next.0 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 2f0e766917..9441d9155c 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.2.1-next.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 7ff38b63f8..20db63abe7 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-bazaar +## 0.2.0 + +### Minor Changes + +- 28b39e0e0e: The limit prop of BazaarOverviewCard has been removed entirely, and instead replaced with a new optional boolean prop `fullWidth`. The BazaarOverviewCard now always use full height without fixed width. Also fixed problem with link to Bazaar. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/cli@0.21.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-catalog@1.6.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index eb0542a504..259f2bae14 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.0-next.0", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index d3ab58bf5a..413d23e509 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.1 + +### Patch Changes + +- d089fbe7dc: Add interfaces for Bitbucket Cloud (webhook) events. +- Updated dependencies + - @backstage/integration@1.4.0 + ## 0.2.1-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/api-report.md b/plugins/bitbucket-cloud-common/api-report.md index d66b8b9a70..5182579a4b 100644 --- a/plugins/bitbucket-cloud-common/api-report.md +++ b/plugins/bitbucket-cloud-common/api-report.md @@ -24,6 +24,57 @@ export class BitbucketCloudClient { ): WithPagination; } +// @public (undocumented) +export namespace Events { + // (undocumented) + export interface Change { + // (undocumented) + closed: boolean; + // (undocumented) + commits: Models.Commit[]; + // (undocumented) + created: boolean; + // (undocumented) + forced: boolean; + // (undocumented) + links: ChangeLinks; + // (undocumented) + new: Models.Branch; + // (undocumented) + old: Models.Branch; + // (undocumented) + truncated: boolean; + } + // (undocumented) + export interface ChangeLinks { + // (undocumented) + commits: Models.Link; + // (undocumented) + diff: Models.Link; + // (undocumented) + html: Models.Link; + } + // (undocumented) + export interface RepoEvent { + // (undocumented) + actor: Models.Account; + // (undocumented) + repository: Models.Repository & { + workspace: Models.Workspace; + }; + } + // (undocumented) + export interface RepoPush { + // (undocumented) + changes: Change[]; + } + // (undocumented) + export interface RepoPushEvent extends RepoEvent { + // (undocumented) + push: RepoPush; + } +} + // @public (undocumented) export type FilterAndSortOptions = { q?: string; @@ -340,6 +391,37 @@ export namespace Models { // (undocumented) self?: Link; } + export interface Workspace extends ModelObject { + // (undocumented) + created_on?: string; + is_private?: boolean; + // (undocumented) + links?: WorkspaceLinks; + name?: string; + slug?: string; + // (undocumented) + updated_on?: string; + uuid?: string; + } + // (undocumented) + export interface WorkspaceLinks { + // (undocumented) + avatar?: Link; + // (undocumented) + html?: Link; + // (undocumented) + members?: Link; + // (undocumented) + owners?: Link; + // (undocumented) + projects?: Link; + // (undocumented) + repositories?: Link; + // (undocumented) + self?: Link; + // (undocumented) + snippets?: Link; + } } // @public (undocumented) diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index fbc63e4497..b4ff3bea3e 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", "description": "Common functionalities for bitbucket-cloud plugins", - "version": "0.2.1-next.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@openapitools/openapi-generator-cli": "^2.4.26", - "msw": "^0.47.0", + "msw": "^0.48.0", "ts-morph": "^15.0.0" }, "files": [ diff --git a/plugins/bitbucket-cloud-common/scripts/reduce-models.js b/plugins/bitbucket-cloud-common/scripts/reduce-models.js index 9d458f4e74..115020493c 100755 --- a/plugins/bitbucket-cloud-common/scripts/reduce-models.js +++ b/plugins/bitbucket-cloud-common/scripts/reduce-models.js @@ -30,6 +30,14 @@ const modelsModule = modelsFile.getModuleOrThrow('Models'); const clientFile = project.getSourceFile('src/BitbucketCloudClient.ts'); const clientClass = clientFile.getClassOrThrow('BitbucketCloudClient'); +const eventsFile = project.getSourceFile('src/events/index.ts'); +const eventsModule = eventsFile.getModuleOrThrow('Events'); +const eventsStmts = [ + ...eventsModule.getClasses(), + ...eventsModule.getInterfaces(), + ...eventsModule.getTypeAliases(), +]; + /** * Returns an array of the unique items of the provided array. * @@ -79,7 +87,11 @@ function referencedModelsIdentifiers(stmt, processed) { } // all directly or transitively referenced/used `Models.[...]` are allowed to stay -const allowed = referencedModelsIdentifiers(clientClass); +const processed = []; +const allowed = referencedModelsIdentifiers(clientClass, processed); +allowed.push( + ...eventsStmts.flatMap(stmt => referencedModelsIdentifiers(stmt, processed)), +); // remove everything not part of the "allow list" modelsModule diff --git a/plugins/bitbucket-cloud-common/src/events/index.ts b/plugins/bitbucket-cloud-common/src/events/index.ts new file mode 100644 index 0000000000..53658be032 --- /dev/null +++ b/plugins/bitbucket-cloud-common/src/events/index.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2022 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 { Models } from '../models'; + +// source: https://support.atlassian.com/bitbucket-cloud/docs/event-payloads + +/** @public */ +export namespace Events { + /** @public */ + export interface RepoEvent { + repository: Models.Repository & { workspace: Models.Workspace }; + actor: Models.Account; + } + + /** @public */ + export interface RepoPushEvent extends RepoEvent { + push: RepoPush; + } + + /** @public */ + export interface RepoPush { + changes: Change[]; + } + + /** @public */ + export interface Change { + old: Models.Branch; + new: Models.Branch; + truncated: boolean; + created: boolean; + forced: boolean; + closed: boolean; + links: ChangeLinks; + commits: Models.Commit[]; + } + + /** @public */ + export interface ChangeLinks { + commits: Models.Link; + diff: Models.Link; + html: Models.Link; + } +} diff --git a/plugins/bitbucket-cloud-common/src/index.ts b/plugins/bitbucket-cloud-common/src/index.ts index 4edf148240..4a9b00e89b 100644 --- a/plugins/bitbucket-cloud-common/src/index.ts +++ b/plugins/bitbucket-cloud-common/src/index.ts @@ -21,6 +21,7 @@ */ export * from './BitbucketCloudClient'; +export * from './events'; export * from './models'; export * from './pagination'; export * from './types'; diff --git a/plugins/bitbucket-cloud-common/src/models/index.ts b/plugins/bitbucket-cloud-common/src/models/index.ts index 580f23a13f..9d25bbb873 100644 --- a/plugins/bitbucket-cloud-common/src/models/index.ts +++ b/plugins/bitbucket-cloud-common/src/models/index.ts @@ -518,4 +518,46 @@ export namespace Models { repositories?: Link; self?: Link; } + + /** + * A Bitbucket workspace. + * Workspaces are used to organize repositories. + * @public + */ + export interface Workspace extends ModelObject { + created_on?: string; + /** + * Indicates whether the workspace is publicly accessible, or whether it is + * private to the members and consequently only visible to members. + */ + is_private?: boolean; + links?: WorkspaceLinks; + /** + * The name of the workspace. + */ + name?: string; + /** + * The short label that identifies this workspace. + */ + slug?: string; + updated_on?: string; + /** + * The workspace's immutable id. + */ + uuid?: string; + } + + /** + * @public + */ + export interface WorkspaceLinks { + avatar?: Link; + html?: Link; + members?: Link; + owners?: Link; + projects?: Link; + repositories?: Link; + self?: Link; + snippets?: Link; + } } diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 2ec214ea00..3a950d33d0 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-bitrise +## 0.1.38 + +### Patch Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.38-next.0 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index cb23af3b90..6c7bf7cfbb 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.38-next.0", + "version": "0.1.38", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx b/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx index 2dcffc3bb3..7992e08f37 100644 --- a/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx +++ b/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx @@ -46,7 +46,7 @@ describe('BitriseArtifactsComponent', () => { const rendered = renderComponent(); const btn = await rendered.findByTestId('btn'); - expect(await rendered.queryByText('VISIBLE')).not.toBeInTheDocument(); + expect(rendered.queryByText('VISIBLE')).not.toBeInTheDocument(); btn.click(); diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 59ab7970f2..48ff05053d 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.1.11 + +### Patch Changes + +- bae3617be5: `AwsS3EntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://backstage.io/docs/integrations/aws-s3/discovery + +- defb389ecd: Add `awsS3EntityProviderCatalogModule` (new backend-plugin-api, alpha). +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index a000ee9d84..5723841562 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.1.11-next.0", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 7fed636045..5e67f292b4 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.9 + +### Patch Changes + +- 87ff05892d: `AzureDevOpsEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://backstage.io/docs/integrations/azure/discovery + +- 0ca399b31b: Add `azureDevOpsEntityProviderCatalogModule` (new backend-plugin-api, alpha). +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 204321f876..5e5f1afb4f 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", "description": "A Backstage catalog backend module that helps integrate towards Azure", - "version": "0.1.9-next.0", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -53,7 +52,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 47cc94f257..c2a83050ad 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,74 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.5 + +### Patch Changes + +- d089fbe7dc: Handle Bitbucket Cloud `repo:push` events at the `BitbucketCloudEntityProvider` + by subscribing to the topic `bitbucketCloud.repo:push.` + + Implements `EventSubscriber` to receive events for the topic `bitbucketCloud.repo:push`. + + On `repo:push`, the affected repository will be refreshed. + This includes adding new Location entities, refreshing existing ones, + and removing obsolete ones. + + To support this, a new annotation `bitbucket.org/repo-url` was added + to Location entities. + + A full refresh will require 1 API call to Bitbucket Cloud to discover all catalog files. + When we handle one `repo:push` event, we also need 1 API call in order to know + which catalog files exist. + This may lead to more discovery-related API calls (code search). + The main cause for hitting the rate limits are Locations refresh-related operations. + + A reduction of total API calls to reduce the rate limit issues can only be achieved in + combination with + + 1. reducing the full refresh frequency (e.g., to monthly) + 2. reducing the frequency of general Location refresh operations by the processing loop + + For (2.), it is not possible to reduce the frequency only for Bitbucket Cloud-related + Locations though. + + Further optimizations might be required to resolve the rate limit issue. + + **Installation and Migration** + + Please find more information at + https://backstage.io/docs/integrations/bitbucketCloud/discovery, + in particular the section about "_Installation with Events Support_". + + In case of the new backend-plugin-api _(alpha)_ the module will take care of + registering itself at both. + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-events-node@0.1.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/plugin-catalog-common@1.0.8 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/api-report.md b/plugins/catalog-backend-module-bitbucket-cloud/api-report.md index 162ff8f67e..480395e477 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/api-report.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/api-report.md @@ -4,24 +4,33 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; +import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { EntityProvider } from '@backstage/plugin-catalog-backend'; import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; +import { EventParams } from '@backstage/plugin-events-node'; +import { Events } from '@backstage/plugin-bitbucket-cloud-common'; +import { EventSubscriber } from '@backstage/plugin-events-node'; import { Logger } from 'winston'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TaskRunner } from '@backstage/backend-tasks'; +import { TokenManager } from '@backstage/backend-common'; // @public -export class BitbucketCloudEntityProvider implements EntityProvider { +export class BitbucketCloudEntityProvider + implements EntityProvider, EventSubscriber +{ // (undocumented) connect(connection: EntityProviderConnection): Promise; // (undocumented) static fromConfig( config: Config, options: { + catalogApi?: CatalogApi; logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + tokenManager?: TokenManager; }, ): BitbucketCloudEntityProvider[]; // (undocumented) @@ -29,7 +38,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { // (undocumented) getTaskId(): string; // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + onRepoPush(event: Events.RepoPushEvent): Promise; + // (undocumented) refresh(logger: Logger): Promise; + // (undocumented) + supportsEventTopics(): string[]; } // @alpha (undocumented) diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 93a9407aa1..fef92b7d1e 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", - "version": "0.1.5-next.0", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "p-limit": "^3.1.0", "uuid": "^8.0.0", "winston": "^3.2.1" }, @@ -48,7 +54,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts index 7d780cd064..72974a1c94 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts @@ -333,6 +333,8 @@ describe('BitbucketCloudEntityProvider', () => { annotations: { 'backstage.io/managed-by-location': `url:${url}`, 'backstage.io/managed-by-origin-location': `url:${url}`, + 'bitbucket.org/repo-url': + 'https://bitbucket.org/test-ws/test-repo2', }, name: 'generated-7c2e6263b6cc2d14e69fd4d029afba601ad6dc3b', }, diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts index f3334a6574..37ad60426d 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts @@ -14,7 +14,14 @@ * limitations under the License. */ +import { TokenManager } from '@backstage/backend-common'; import { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks'; +import { CatalogApi } from '@backstage/catalog-client'; +import { + Entity, + LocationEntity, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { BitbucketCloudIntegration, @@ -22,22 +29,35 @@ import { } from '@backstage/integration'; import { BitbucketCloudClient, + Events, Models, } from '@backstage/plugin-bitbucket-cloud-common'; import { + DeferredEntity, EntityProvider, EntityProviderConnection, - LocationSpec, locationSpecToLocationEntity, } from '@backstage/plugin-catalog-backend'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { EventParams, EventSubscriber } from '@backstage/plugin-events-node'; import { BitbucketCloudEntityProviderConfig, readProviderConfigs, } from './BitbucketCloudEntityProviderConfig'; +import limiterFactory from 'p-limit'; import * as uuid from 'uuid'; import { Logger } from 'winston'; const DEFAULT_BRANCH = 'master'; +const TOPIC_REPO_PUSH = 'bitbucketCloud/repo:push'; + +/** @public */ +export const ANNOTATION_BITBUCKET_CLOUD_REPO_URL = 'bitbucket.org/repo-url'; + +interface IngestionTarget { + fileUrl: string; + repoUrl: string; +} /** * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org). @@ -47,19 +67,27 @@ const DEFAULT_BRANCH = 'master'; * * @public */ -export class BitbucketCloudEntityProvider implements EntityProvider { +export class BitbucketCloudEntityProvider + implements EntityProvider, EventSubscriber +{ private readonly client: BitbucketCloudClient; private readonly config: BitbucketCloudEntityProviderConfig; private readonly logger: Logger; private readonly scheduleFn: () => Promise; + private readonly catalogApi?: CatalogApi; + private readonly tokenManager?: TokenManager; private connection?: EntityProviderConnection; + private eventConfigErrorThrown = false; + static fromConfig( config: Config, options: { + catalogApi?: CatalogApi; logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + tokenManager?: TokenManager; }, ): BitbucketCloudEntityProvider[] { const integrations = ScmIntegrations.fromConfig(config); @@ -90,6 +118,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { integration, options.logger, taskRunner, + options.catalogApi, + options.tokenManager, ); }); } @@ -99,6 +129,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { integration: BitbucketCloudIntegration, logger: Logger, taskRunner: TaskRunner, + catalogApi?: CatalogApi, + tokenManager?: TokenManager, ) { this.client = BitbucketCloudClient.fromConfig(integration.config); this.config = config; @@ -106,6 +138,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { target: this.getProviderName(), }); this.scheduleFn = this.createScheduleFn(taskRunner); + this.catalogApi = catalogApi; + this.tokenManager = tokenManager; } private createScheduleFn(schedule: TaskRunner): () => Promise { @@ -154,15 +188,7 @@ export class BitbucketCloudEntityProvider implements EntityProvider { logger.info('Discovering catalog files in Bitbucket Cloud repositories'); const targets = await this.findCatalogFiles(); - const entities = targets - .map(BitbucketCloudEntityProvider.toLocationSpec) - .map(location => locationSpecToLocationEntity({ location })) - .map(entity => { - return { - locationKey: this.getProviderName(), - entity: entity, - }; - }); + const entities = this.toDeferredEntities(targets); await this.connection.applyMutation({ type: 'full', @@ -174,7 +200,135 @@ export class BitbucketCloudEntityProvider implements EntityProvider { ); } - private async findCatalogFiles(): Promise { + /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */ + supportsEventTopics(): string[] { + return [TOPIC_REPO_PUSH]; + } + + /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */ + async onEvent(params: EventParams): Promise { + if (params.topic !== TOPIC_REPO_PUSH) { + return; + } + + if (params.metadata?.['x-event-key'] === 'repo:push') { + await this.onRepoPush(params.eventPayload as Events.RepoPushEvent); + } + } + + private canHandleEvents(): boolean { + if (this.catalogApi && this.tokenManager) { + return true; + } + + // throw only once + if (!this.eventConfigErrorThrown) { + this.eventConfigErrorThrown = true; + throw new Error( + `${this.getProviderName()} not well configured to handle repo:push. Missing CatalogApi and/or TokenManager.`, + ); + } + + return false; + } + + async onRepoPush(event: Events.RepoPushEvent): Promise { + if (!this.canHandleEvents()) { + return; + } + + if (!this.connection) { + throw new Error('Not initialized'); + } + + if (event.repository.workspace.slug !== this.config.workspace) { + return; + } + + if (!this.matchesFilters(event.repository)) { + return; + } + + const repoName = event.repository.slug; + const repoUrl = event.repository.links!.html!.href!; + this.logger.info(`handle repo:push event for ${repoUrl}`); + + // The commit information at the webhook only contains some high level metadata. + // In order to understand whether relevant files have changed we would need to + // look up all commits which would cost additional API calls. + // The overall goal is to optimize the necessary amount of API calls. + // Hence, we will just trigger a refresh for catalog file(s) within the repository + // if we get notified about changes there. + + const targets = await this.findCatalogFiles(repoName); + + const { token } = await this.tokenManager!.getToken(); + const existing = await this.findExistingLocations(repoUrl, token); + + const added: DeferredEntity[] = this.toDeferredEntities( + targets.filter( + // All Locations are managed by this provider and only have `target`, never `targets`. + // All URLs (fileUrl, target) are created using `BitbucketCloudEntityProvider.toUrl`. + // Hence, we can keep the comparison simple and don't need to handle different + // casing or encoding, etc. + target => !existing.find(item => item.spec.target === target.fileUrl), + ), + ); + + const limiter = limiterFactory(10); + + const stillExisting: Entity[] = []; + const removed: DeferredEntity[] = []; + existing.forEach(item => { + if (targets.find(value => value.fileUrl === item.spec.target)) { + stillExisting.push(item); + } else { + removed.push({ + locationKey: this.getProviderName(), + entity: item, + }); + } + }); + + const promises: Promise[] = stillExisting.map(entity => + limiter(async () => + this.catalogApi!.refreshEntity(stringifyEntityRef(entity), { token }), + ), + ); + + if (added.length > 0 || removed.length > 0) { + const connection = this.connection; + promises.push( + limiter(async () => + connection.applyMutation({ + type: 'delta', + added: added, + removed: removed, + }), + ), + ); + } + + await Promise.all(promises); + } + + private async findExistingLocations( + repoUrl: string, + token: string, + ): Promise { + const filter: Record = {}; + filter.kind = 'Location'; + filter[`metadata.annotations.${ANNOTATION_BITBUCKET_CLOUD_REPO_URL}`] = + repoUrl; + + return this.catalogApi!.getEntities({ filter }, { token }).then( + result => result.items, + ) as Promise; + } + + private async findCatalogFiles( + repoName?: string, + ): Promise { const workspace = this.config.workspace; const catalogPath = this.config.catalogPath; @@ -197,12 +351,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { // ...except the one we need '+values.file.commit.repository.links.html.href', ].join(','); - const query = `"${catalogFilename}" path:${catalogPath}`; + const optRepoFilter = repoName ? ` repo:${repoName}` : ''; + const query = `"${catalogFilename}" path:${catalogPath}${optRepoFilter}`; const searchResults = this.client .searchCode(workspace, query, { fields }) .iterateResults(); - const result: string[] = []; + const result: IngestionTarget[] = []; for await (const searchResult of searchResults) { // not a file match, but a code match @@ -212,12 +367,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { const repository = searchResult.file!.commit!.repository!; if (this.matchesFilters(repository)) { - result.push( - BitbucketCloudEntityProvider.toUrl( + result.push({ + fileUrl: BitbucketCloudEntityProvider.toUrl( repository, searchResult.file!.path!, ), - ); + repoUrl: repository.links!.html!.href!, + }); } } @@ -234,11 +390,32 @@ export class BitbucketCloudEntityProvider implements EntityProvider { ); } + private toDeferredEntities(targets: IngestionTarget[]): DeferredEntity[] { + return targets + .map(target => { + const location = BitbucketCloudEntityProvider.toLocationSpec( + target.fileUrl, + ); + const entity = locationSpecToLocationEntity({ location }); + entity.metadata.annotations = { + ...entity.metadata.annotations, + [ANNOTATION_BITBUCKET_CLOUD_REPO_URL]: target.repoUrl, + }; + return entity; + }) + .map(entity => { + return { + locationKey: this.getProviderName(), + entity: entity, + }; + }); + } + private static toUrl( repository: Models.Repository, filePath: string, ): string { - const repoUrl = repository.links!.html!.href; + const repoUrl = repository.links!.html!.href!; const branch = repository.mainbranch?.name ?? DEFAULT_BRANCH; return `${repoUrl}/src/${branch}/${filePath}`; diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts similarity index 74% rename from plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts rename to plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts index 6307bee282..3fcc39fdd0 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts @@ -15,11 +15,17 @@ */ import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; +import { + getVoidLogger, + PluginEndpointDiscovery, + TokenManager, +} from '@backstage/backend-common'; import { configServiceRef, + discoveryServiceRef, loggerServiceRef, schedulerServiceRef, + tokenManagerServiceRef, } from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, @@ -27,20 +33,27 @@ import { } from '@backstage/backend-tasks'; import { startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; -import { bitbucketCloudEntityProviderCatalogModule } from './BitbucketCloudEntityProviderCatalogModule'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; import { Duration } from 'luxon'; +import { bitbucketCloudEntityProviderCatalogModule } from './BitbucketCloudEntityProviderCatalogModule'; import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider'; describe('bitbucketCloudEntityProviderCatalogModule', () => { it('should register provider at the catalog extension point', async () => { let addedProviders: Array | undefined; + let addedSubscribers: Array | undefined; let usedSchedule: TaskScheduleDefinition | undefined; - const extensionPoint = { + const catalogExtensionPointImpl = { addEntityProvider: (providers: any) => { addedProviders = providers; }, }; + const eventsExtensionPointImpl = { + addSubscribers: (subscribers: any) => { + addedSubscribers = subscribers; + }, + }; const runner = jest.fn(); const scheduler = { createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { @@ -48,6 +61,8 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { return runner; }, } as unknown as PluginTaskScheduler; + const discovery = jest.fn() as any as PluginEndpointDiscovery; + const tokenManager = jest.fn() as any as TokenManager; const config = new ConfigReader({ catalog: { @@ -64,11 +79,16 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { }); await startTestBackend({ - extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + extensionPoints: [ + [catalogProcessingExtensionPoint, catalogExtensionPointImpl], + [eventsExtensionPoint, eventsExtensionPointImpl], + ], services: [ [configServiceRef, config], + [discoveryServiceRef, discovery], [loggerServiceRef, getVoidLogger()], [schedulerServiceRef, scheduler], + [tokenManagerServiceRef, tokenManager], ], features: [bitbucketCloudEntityProviderCatalogModule()], }); @@ -79,6 +99,7 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { expect(addedProviders?.pop()?.getProviderName()).toEqual( 'bitbucketCloud-provider:default', ); + expect(addedSubscribers).toEqual(addedProviders); expect(runner).not.toHaveBeenCalled(); }); }); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts index d137bd7166..1c005991a6 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts @@ -20,8 +20,13 @@ import { loggerServiceRef, loggerToWinstonLogger, schedulerServiceRef, + tokenManagerServiceRef, } from '@backstage/backend-plugin-api'; -import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; +import { + catalogProcessingExtensionPoint, + catalogServiceRef, +} from '@backstage/plugin-catalog-node'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider'; /** @@ -34,18 +39,34 @@ export const bitbucketCloudEntityProviderCatalogModule = createBackendModule({ env.registerInit({ deps: { catalog: catalogProcessingExtensionPoint, + catalogApi: catalogServiceRef, config: configServiceRef, + // TODO(pjungermann): How to make this optional for those which only want the provider without event support? + // Do we even want to support this? + events: eventsExtensionPoint, logger: loggerServiceRef, scheduler: schedulerServiceRef, + tokenManager: tokenManagerServiceRef, }, - async init({ catalog, config, logger, scheduler }) { + async init({ + catalog, + catalogApi, + config, + events, + logger, + scheduler, + tokenManager, + }) { const winstonLogger = loggerToWinstonLogger(logger); const providers = BitbucketCloudEntityProvider.fromConfig(config, { + catalogApi, logger: winstonLogger, scheduler, + tokenManager, }); catalog.addEntityProvider(providers); + events.addSubscribers(providers); }, }); }, diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 1224da8bdd..dbc8f168e5 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.3 + +### Patch Changes + +- 68f7f5a857: `BitbucketServerEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://backstage.io/docs/integrations/bitbucketServer/discovery + +- cd48ed8370: Add `bitbucketServerEntityProviderCatalogModule` (new backend-plugin-api, alpha). +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 594b5f0852..eaf5da84fc 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.3-next.0", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 571c18de00..774596c16f 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.5 + +### Patch Changes + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + ## 0.2.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 8ee6661b01..41e6327ba8 100644 --- a/plugins/catalog-backend-module-bitbucket/package.json +++ b/plugins/catalog-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket", - "version": "0.2.5-next.0", + "version": "0.2.5", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", @@ -42,14 +42,14 @@ "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/lodash": "^4.14.151" + "@types/lodash": "^4.14.151", + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index a6babaf4fc..a2d9fbd8ae 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.6 + +### Patch Changes + +- 4fba50f5d4: Add `gerritEntityProviderCatalogModule` (new backend-plugin-api, alpha). +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- 134b69f478: `GerritEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://backstage.io/docs/integrations/gerrit/discovery + +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index c6d342640f..4c9a1498d6 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.6-next.0", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,6 @@ "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "fs-extra": "10.1.0", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -48,7 +47,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/fs-extra": "^9.0.1", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index b89231a422..6630fc2052 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-catalog-backend-module-github +## 0.2.0 + +### Minor Changes + +- 67fe5bc9a9: BREAKING: Support authenticated backends by including a server token for catalog requests. The constructor of `GithubLocationAnalyzer` now requires an instance of `TokenManager` to be supplied: + + ```diff + ... + builder.addLocationAnalyzers( + new GitHubLocationAnalyzer({ + discovery: env.discovery, + config: env.config, + + tokenManager: env.tokenManager, + }), + ); + ... + ``` + +- f64d66a45c: Added the ability for the GitHub discovery provider to validate that catalog files exist before emitting them. + + Users can now set the `validateLocationsExist` property to `true` in their GitHub discovery configuration to opt in to this feature. + This feature only works with `catalogPath`s that do not contain wildcards. + + When `validateLocationsExist` is set to `true`, the GitHub discovery provider will retrieve the object from the + repository at the provided `catalogPath`. + If this file exists and is non-empty, then it will be emitted as a location for further processing. + If this file does not exist or is empty, then it will not be emitted. + Not emitting locations that do not exist allows for far fewer calls to the GitHub API to validate locations that do not exist. + +### Patch Changes + +- 67fe5bc9a9: Properly derive Github credentials when making requests in `GithubLocationAnalyzer` to support Github App authentication +- bef063dc8d: - Make it possible to inject custom user and team transformers when configuring the `GithubOrgEntityProvider` +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index a9587e172b..e749549646 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -13,6 +13,8 @@ import { EntityProvider } from '@backstage/plugin-catalog-backend'; import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; import { GithubCredentialsProvider } from '@backstage/integration'; import { GithubIntegrationConfig } from '@backstage/integration'; +import { graphql } from '@octokit/graphql'; +import { GroupEntity } from '@backstage/catalog-model'; import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { Logger } from 'winston'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; @@ -21,6 +23,13 @@ import { ScmIntegrationRegistry } from '@backstage/integration'; import { ScmLocationAnalyzer } from '@backstage/plugin-catalog-backend'; import { TaskRunner } from '@backstage/backend-tasks'; import { TokenManager } from '@backstage/backend-common'; +import { UserEntity } from '@backstage/catalog-model'; + +// @public +export const defaultOrganizationTeamTransformer: TeamTransformer; + +// @public +export const defaultUserTransformer: UserTransformer; // @public export class GithubDiscoveryProcessor implements CatalogProcessor { @@ -129,6 +138,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { logger: Logger; orgs: GithubMultiOrgConfig; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }); // (undocumented) static fromConfig( @@ -136,6 +147,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { options: { logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ): GithubMultiOrgReaderProcessor; // (undocumented) @@ -165,6 +178,8 @@ export class GithubOrgEntityProvider implements EntityProvider { gitHubConfig: GithubIntegrationConfig; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }); // (undocumented) connect(connection: EntityProviderConnection): Promise; @@ -188,6 +203,8 @@ export interface GithubOrgEntityProviderOptions { logger: Logger; orgUrl: string; schedule?: 'manual' | TaskRunner; + teamTransformer?: TeamTransformer; + userTransformer?: UserTransformer; } // @public @@ -214,4 +231,48 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { emit: CatalogProcessorEmit, ): Promise; } + +// @public +export type GithubTeam = { + slug: string; + combinedSlug: string; + name?: string; + description?: string; + avatarUrl?: string; + editTeamUrl?: string; + parentTeam?: GithubTeam; + members: GithubUser[]; +}; + +// @public +export type GithubUser = { + login: string; + bio?: string; + avatarUrl?: string; + email?: string; + name?: string; + organizationVerifiedDomainEmails?: string[]; +}; + +// @public +export type TeamTransformer = ( + item: GithubTeam, + ctx: TransformerContext, +) => Promise; + +// @public +export interface TransformerContext { + // (undocumented) + client: typeof graphql; + // (undocumented) + org: string; + // (undocumented) + query: string; +} + +// @public +export type UserTransformer = ( + item: GithubUser, + ctx: TransformerContext, +) => Promise; ``` diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 60185636ea..f0df0cb04a 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.2.0-next.0", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,6 @@ "@octokit/rest": "^19.0.3", "git-url-parse": "^13.0.0", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -57,7 +56,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-github/src/index.ts b/plugins/catalog-backend-module-github/src/index.ts index f38035db15..b005780758 100644 --- a/plugins/catalog-backend-module-github/src/index.ts +++ b/plugins/catalog-backend-module-github/src/index.ts @@ -15,14 +15,13 @@ */ /** - * A Backstage catalog backend module that helps integrate towards GitHub + * A Backstage catalog backend module that helps integrate towards Github * * @packageDocumentation */ export { GithubLocationAnalyzer } from './analyzers/GithubLocationAnalyzer'; export type { GithubLocationAnalyzerOptions } from './analyzers/GithubLocationAnalyzer'; -export type { GithubMultiOrgConfig } from './lib'; export { GithubDiscoveryProcessor } from './processors/GithubDiscoveryProcessor'; export { GithubMultiOrgReaderProcessor } from './processors/GithubMultiOrgReaderProcessor'; export { GithubOrgReaderProcessor } from './processors/GithubOrgReaderProcessor'; @@ -30,5 +29,15 @@ export { GithubEntityProvider } from './providers/GithubEntityProvider'; export { GithubOrgEntityProvider } from './providers/GithubOrgEntityProvider'; export type { GithubOrgEntityProviderOptions } from './providers/GithubOrgEntityProvider'; export { githubEntityProviderCatalogModule } from './service/GithubEntityProviderCatalogModule'; +export { + type GithubMultiOrgConfig, + type GithubTeam, + type GithubUser, + type UserTransformer, + defaultUserTransformer, + type TeamTransformer, + defaultOrganizationTeamTransformer, + type TransformerContext, +} from './lib'; export * from './deprecated'; diff --git a/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts new file mode 100644 index 0000000000..efd3eedd5d --- /dev/null +++ b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts @@ -0,0 +1,127 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { graphql } from '@octokit/graphql'; +import { GithubTeam, GithubUser } from './github'; + +/** + * Context passed to Transformers + * + * @public + */ +export interface TransformerContext { + client: typeof graphql; + query: string; + org: string; +} + +/** + * Transformer for GitHub users to UserEntity + * + * @public + */ +export type UserTransformer = ( + item: GithubUser, + ctx: TransformerContext, +) => Promise; + +/** + * Transformer for GitHub Team to GroupEntity + * + * @public + */ +export type TeamTransformer = ( + item: GithubTeam, + ctx: TransformerContext, +) => Promise; + +/** + * Default transformer for GitHub users to UserEntity + * + * @public + */ +export const defaultUserTransformer: UserTransformer = async ( + item: GithubUser, +) => { + const entity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: item.login, + annotations: { + 'github.com/user-login': item.login, + }, + }, + spec: { + profile: {}, + memberOf: [], + }, + }; + + if (item.bio) entity.metadata.description = item.bio; + if (item.name) entity.spec.profile!.displayName = item.name; + if (item.email) entity.spec.profile!.email = item.email; + if (item.avatarUrl) entity.spec.profile!.picture = item.avatarUrl; + return entity; +}; + +/** + * Default transformer for GitHub Team to GroupEntity + * + * @public + */ +export const defaultOrganizationTeamTransformer: TeamTransformer = + async team => { + const annotations: { [annotationName: string]: string } = { + 'github.com/team-slug': team.combinedSlug, + }; + + if (team.editTeamUrl) { + annotations['backstage.io/edit-url'] = team.editTeamUrl; + } + + const entity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: team.slug, + annotations, + }, + spec: { + type: 'team', + profile: {}, + children: [], + }, + }; + + if (team.description) { + entity.metadata.description = team.description; + } + if (team.name) { + entity.spec.profile!.displayName = team.name; + } + if (team.avatarUrl) { + entity.spec.profile!.picture = team.avatarUrl; + } + if (team.parentTeam) { + entity.spec.parent = team.parentTeam.slug; + } + + entity.spec.members = team.members.map(user => user.login); + + return entity; + }; diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index 25878c2005..d07d2f6af8 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -15,22 +15,32 @@ */ import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; import { setupServer } from 'msw/node'; +import { TeamTransformer, UserTransformer } from './defaultTransformers'; + import { getOrganizationTeams, getOrganizationUsers, getTeamMembers, getOrganizationRepositories, QueryResponse, + GithubUser, + GithubTeam, } from './github'; +import fetch from 'node-fetch'; + +// Workaround for Node.js 18, where native fetch is available, but not yet picked up by msw +// TODO(Rugvip): remove once https://github.com/mswjs/msw/issues/1388 is resolved +(global as any).fetch = fetch; describe('github', () => { const server = setupServer(); setupRequestMockHandlers(server); - describe('getOrganizationUsers', () => { + describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { const input: QueryResponse = { organization: { @@ -71,7 +81,120 @@ describe('github', () => { }); }); - describe('getOrganizationTeams', () => { + describe('getOrganizationUsers using custom UserTransformer', () => { + const customUserTransformer: UserTransformer = async ( + item: GithubUser, + {}, + ) => { + if (item.login === 'aa') { + return undefined; + } + + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: `${item.login}-custom`, + annotations: { + 'github.com/user-login': item.login, + }, + }, + spec: { + profile: {}, + memberOf: [], + }, + } as UserEntity; + }; + + it('reads members', async () => { + const input: QueryResponse = { + organization: { + membersWithRole: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + login: 'a', + name: 'b', + bio: 'c', + email: 'd', + avatarUrl: 'e', + }, + ], + }, + }, + }; + + const output = { + users: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'a-custom', + }), + }), + ], + }; + + server.use( + graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + ); + + await expect( + getOrganizationUsers(graphql, 'a', 'token', customUserTransformer), + ).resolves.toEqual(output); + }); + + it('reads members if undefined is returned from transformer', async () => { + const input: QueryResponse = { + organization: { + membersWithRole: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + login: 'a', + name: 'b', + bio: 'c', + email: 'd', + avatarUrl: 'e', + }, + { + login: 'aa', + name: 'bb', + bio: 'cc', + email: 'dd', + avatarUrl: 'ee', + }, + ], + }, + }, + }; + + const output = { + users: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'a-custom', + }), + }), + ], + }; + + server.use( + graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + ); + + const users = await getOrganizationUsers( + graphql, + 'a', + 'token', + customUserTransformer, + ); + + expect(users.users).toHaveLength(1); + expect(users).toEqual(output); + }); + }); + + describe('getOrganizationTeams using default TeamTransformer', () => { let input: QueryResponse; beforeEach(() => { @@ -90,7 +213,7 @@ describe('github', () => { parentTeam: { slug: 'parent', combinedSlug: '', - members: { pageInfo: { hasNextPage: false }, nodes: [] }, + members: [], }, members: { pageInfo: { hasNextPage: false }, @@ -124,10 +247,10 @@ describe('github', () => { }, parent: 'parent', children: [], + members: ['user'], }, }), ], - groupMemberUsers: new Map([['team', ['user']]]), }; server.use( @@ -136,37 +259,192 @@ describe('github', () => { await expect(getOrganizationTeams(graphql, 'a')).resolves.toEqual(output); }); + }); - it('applies namespaces', async () => { + describe('getOrganizationTeams using custom TeamTransformer', () => { + let input: QueryResponse; + + const customTeamTransformer: TeamTransformer = async ( + item: GithubTeam, + {}, + ) => { + if (item.name === 'aa') { + return undefined; + } + + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: `${item.name}-custom`, + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, + description: item.description, + }, + spec: { + type: 'team', + profile: { + displayName: `${item.name}-custom`, + picture: 'http://example.com/team.jpeg', + }, + parent: 'parent', + children: [], + members: ['user'], + }, + } as GroupEntity; + }; + + beforeEach(() => { + input = { + organization: { + teams: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'Team', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + ], + }, + }, + }; + }); + + it('reads teams', async () => { const output = { groups: [ expect.objectContaining({ metadata: expect.objectContaining({ - name: 'team', - namespace: 'foo', + name: 'Team-custom', description: 'The one and only team', + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, }), spec: { type: 'team', profile: { - displayName: 'Team', + displayName: 'Team-custom', picture: 'http://example.com/team.jpeg', }, parent: 'parent', children: [], + members: ['user'], }, }), ], - groupMemberUsers: new Map([['foo/team', ['user']]]), }; server.use( graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), ); - await expect(getOrganizationTeams(graphql, 'a', 'foo')).resolves.toEqual( - output, + await expect( + getOrganizationTeams(graphql, 'a', customTeamTransformer), + ).resolves.toEqual(output); + }); + + it('reads teams if undefined is returned', async () => { + input = { + organization: { + teams: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'Team', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'aa', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + ], + }, + }, + }; + + const output = { + groups: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'Team-custom', + description: 'The one and only team', + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, + }), + spec: { + type: 'team', + profile: { + displayName: 'Team-custom', + picture: 'http://example.com/team.jpeg', + }, + parent: 'parent', + children: [], + members: ['user'], + }, + }), + ], + }; + + server.use( + graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), ); + + const teams = await getOrganizationTeams( + graphql, + 'a', + customTeamTransformer, + ); + + expect(teams.groups).toHaveLength(1); + expect(teams).toEqual(output); }); }); @@ -186,7 +464,7 @@ describe('github', () => { }; const output = { - members: ['user'], + members: [{ login: 'user' }], }; server.use( diff --git a/plugins/catalog-backend-module-github/src/lib/github.ts b/plugins/catalog-backend-module-github/src/lib/github.ts index ef6a7f817a..4d583d0730 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.ts @@ -17,19 +17,30 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { GithubCredentialType } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; +import { + defaultOrganizationTeamTransformer, + defaultUserTransformer, + TeamTransformer, + TransformerContext, + UserTransformer, +} from './defaultTransformers'; // Graphql types export type QueryResponse = { - organization?: Organization; - repositoryOwner?: Organization | User; + organization?: OrganizationResponse; + repositoryOwner?: RepositoryOwnerResponse; }; -export type Organization = { - membersWithRole?: Connection; - team?: Team; - teams?: Connection; - repositories?: Connection; +type RepositoryOwnerResponse = { + repositories?: Connection; +}; + +export type OrganizationResponse = { + membersWithRole?: Connection; + team?: GithubTeamResponse; + teams?: Connection; + repositories?: Connection; }; export type PageInfo = { @@ -37,27 +48,41 @@ export type PageInfo = { endCursor?: string; }; -export type User = { +/** + * Github User + * + * @public + */ +export type GithubUser = { login: string; bio?: string; avatarUrl?: string; email?: string; name?: string; - repositories?: Connection; + organizationVerifiedDomainEmails?: string[]; }; -export type Team = { +/** + * Github Team + * + * @public + */ +export type GithubTeam = { slug: string; combinedSlug: string; name?: string; description?: string; avatarUrl?: string; editTeamUrl?: string; - parentTeam?: Team; - members: Connection; + parentTeam?: GithubTeam; + members: GithubUser[]; }; -export type Repository = { +export type GithubTeamResponse = Omit & { + members: Connection; +}; + +export type RepositoryResponse = { name: string; url: string; isArchived: boolean; @@ -88,7 +113,7 @@ export type Connection = { }; /** - * Gets all the users out of a GitHub organization. + * Gets all the users out of a Github organization. * * Note that the users will not have their memberships filled in. * @@ -99,7 +124,7 @@ export async function getOrganizationUsers( client: typeof graphql, org: string, tokenType: GithubCredentialType, - userNamespace?: string, + userTransformer: UserTransformer = defaultUserTransformer, ): Promise<{ users: UserEntity[] }> { const query = ` query users($org: String!, $email: Boolean!, $cursor: String) { @@ -111,7 +136,8 @@ export async function getOrganizationUsers( bio, email @include(if: $email), login, - name + name, + organizationVerifiedDomainEmails(login: $org) } } } @@ -119,44 +145,24 @@ export async function getOrganizationUsers( // There is no user -> teams edge, so we leave the memberships empty for // now and let the team iteration handle it instead - const mapper = (user: User) => { - const entity: UserEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { - name: user.login, - annotations: { - 'github.com/user-login': user.login, - }, - }, - spec: { - profile: {}, - memberOf: [], - }, - }; - - if (userNamespace) entity.metadata.namespace = userNamespace; - if (user.bio) entity.metadata.description = user.bio; - if (user.name) entity.spec.profile!.displayName = user.name; - if (user.email) entity.spec.profile!.email = user.email; - if (user.avatarUrl) entity.spec.profile!.picture = user.avatarUrl; - - return entity; - }; const users = await queryWithPaging( client, query, + org, r => r.organization?.membersWithRole, - mapper, - { org, email: tokenType === 'token' }, + userTransformer, + { + org, + email: tokenType === 'token', + }, ); return { users }; } /** - * Gets all the teams out of a GitHub organization. + * Gets all the teams out of a Github organization. * * Note that the teams will not have any relations apart from parent filled in. * @@ -166,10 +172,9 @@ export async function getOrganizationUsers( export async function getOrganizationTeams( client: typeof graphql, org: string, - orgNamespace?: string, + teamTransformer: TeamTransformer = defaultOrganizationTeamTransformer, ): Promise<{ groups: GroupEntity[]; - groupMemberUsers: Map; }> { const query = ` query teams($org: String!, $cursor: String) { @@ -193,86 +198,51 @@ export async function getOrganizationTeams( } }`; - // Gets populated inside the mapper below - const groupMemberUsers = new Map(); + const materialisedTeams = async ( + item: GithubTeamResponse, + ctx: TransformerContext, + ): Promise => { + const memberNames: GithubUser[] = []; - const mapper = async (team: Team) => { - const annotations: { [annotationName: string]: string } = { - 'github.com/team-slug': team.combinedSlug, - }; - - if (team.editTeamUrl) { - annotations['backstage.io/edit-url'] = team.editTeamUrl; - } - - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: team.slug, - annotations, - }, - spec: { - type: 'team', - profile: {}, - children: [], - }, - }; - - if (orgNamespace) { - entity.metadata.namespace = orgNamespace; - } - - if (team.description) { - entity.metadata.description = team.description; - } - if (team.name) { - entity.spec.profile!.displayName = team.name; - } - if (team.avatarUrl) { - entity.spec.profile!.picture = team.avatarUrl; - } - if (team.parentTeam) { - entity.spec.parent = team.parentTeam.slug; - } - - const memberNames: string[] = []; - const groupKey = orgNamespace ? `${orgNamespace}/${team.slug}` : team.slug; - groupMemberUsers.set(groupKey, memberNames); - - if (!team.members.pageInfo.hasNextPage) { + if (!item.members.pageInfo.hasNextPage) { // We got all the members in one go, run the fast path - for (const user of team.members.nodes) { - memberNames.push(user.login); + for (const user of item.members.nodes) { + memberNames.push(user); } } else { // There were more than a hundred immediate members - run the slow // path of fetching them explicitly - const { members } = await getTeamMembers(client, org, team.slug); + const { members } = await getTeamMembers(ctx.client, ctx.org, item.slug); for (const userLogin of members) { memberNames.push(userLogin); } } - return entity; + const team: GithubTeam = { + ...item, + members: memberNames, + }; + + return await teamTransformer(team, ctx); }; const groups = await queryWithPaging( client, query, + org, r => r.organization?.teams, - mapper, + materialisedTeams, { org }, ); - return { groups, groupMemberUsers }; + return { groups }; } export async function getOrganizationRepositories( client: typeof graphql, org: string, catalogPath: string, -): Promise<{ repositories: Repository[] }> { +): Promise<{ repositories: RepositoryResponse[] }> { let relativeCatalogPathRef: string; // We must strip the leading slash or the query for objects does not work if (catalogPath.startsWith('/')) { @@ -321,8 +291,9 @@ export async function getOrganizationRepositories( const repositories = await queryWithPaging( client, query, + org, r => r.repositoryOwner?.repositories, - x => x, + async x => x, { org, catalogPathRef }, ); @@ -330,7 +301,7 @@ export async function getOrganizationRepositories( } /** - * Gets all the users out of a GitHub organization. + * Gets all the users out of a Github organization. * * Note that the users will not have their memberships filled in. * @@ -342,7 +313,7 @@ export async function getTeamMembers( client: typeof graphql, org: string, teamSlug: string, -): Promise<{ members: string[] }> { +): Promise<{ members: GithubUser[] }> { const query = ` query members($org: String!, $teamSlug: String!, $cursor: String) { organization(login: $org) { @@ -358,8 +329,9 @@ export async function getTeamMembers( const members = await queryWithPaging( client, query, + org, r => r.organization?.team?.members, - user => user.login, + async user => user, { org, teamSlug }, ); @@ -379,7 +351,7 @@ export async function getTeamMembers( * @param query - The query to execute * @param connection - A function that, given the response, picks out the actual * Connection object that's being iterated - * @param mapper - A function that, given one of the nodes in the Connection, + * @param transformer - A function that, given one of the nodes in the Connection, * returns the model mapped form of it * @param variables - The variable values that the query needs, minus the cursor */ @@ -391,8 +363,12 @@ export async function queryWithPaging< >( client: typeof graphql, query: string, + org: string, connection: (response: Response) => Connection | undefined, - mapper: (item: GraphqlType) => Promise | OutputType, + transformer: ( + item: GraphqlType, + ctx: TransformerContext, + ) => Promise, variables: Variables, ): Promise { const result: OutputType[] = []; @@ -410,7 +386,15 @@ export async function queryWithPaging< } for (const node of conn.nodes) { - result.push(await mapper(node)); + const transformedNode = await transformer(node, { + client, + query, + org, + }); + + if (transformedNode) { + result.push(transformedNode); + } } if (!conn.pageInfo.hasNextPage) { diff --git a/plugins/catalog-backend-module-github/src/lib/index.ts b/plugins/catalog-backend-module-github/src/lib/index.ts index 6402b69121..14f78fdeee 100644 --- a/plugins/catalog-backend-module-github/src/lib/index.ts +++ b/plugins/catalog-backend-module-github/src/lib/index.ts @@ -20,6 +20,15 @@ export { getOrganizationRepositories, getOrganizationTeams, getOrganizationUsers, + type GithubUser, + type GithubTeam, } from './github'; +export { + type UserTransformer, + defaultUserTransformer, + type TeamTransformer, + defaultOrganizationTeamTransformer, + type TransformerContext, +} from './defaultTransformers'; export { assignGroupsToUsers, buildOrgHierarchy } from './org'; export { parseGithubOrgUrl } from './util'; diff --git a/plugins/catalog-backend-module-github/src/lib/org.test.ts b/plugins/catalog-backend-module-github/src/lib/org.test.ts index 8a8f47642a..712c7c0b88 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.test.ts @@ -68,13 +68,47 @@ describe('buildOrgHierarchy', () => { describe('assignGroupsToUsers', () => { it('should assign groups to users', () => { const users: UserEntity[] = [u('u1'), u('u2')]; - const groupMemberUsers = new Map([ - ['g1', ['u1', 'u2']], - ['g2', ['u2']], - ['g3', ['u3']], - ]); - assignGroupsToUsers(users, groupMemberUsers); + const groups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g1', + }, + spec: { + type: 'team', + children: [], + members: ['u1', 'u2'], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g2', + }, + spec: { + type: 'team', + children: [], + members: ['u2'], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g3', + }, + spec: { + type: 'team', + children: [], + members: ['u3'], + }, + }, + ]; + + assignGroupsToUsers(users, groups); expect(users[0].spec.memberOf).toEqual(['g1']); expect(users[1].spec.memberOf).toEqual(['g1', 'g2']); diff --git a/plugins/catalog-backend-module-github/src/lib/org.ts b/plugins/catalog-backend-module-github/src/lib/org.ts index 79a96b5e71..275c5f4aeb 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { + DEFAULT_NAMESPACE, + GroupEntity, + UserEntity, +} from '@backstage/catalog-model'; export function buildOrgHierarchy(groups: GroupEntity[]) { const groupsByName = new Map(groups.map(g => [g.metadata.name, g])); @@ -52,8 +56,19 @@ export function buildOrgHierarchy(groups: GroupEntity[]) { // Ensure that users have their direct group memberships. export function assignGroupsToUsers( users: UserEntity[], - groupMemberUsers: Map, + groups: GroupEntity[], ) { + const groupMemberUsers = new Map( + groups.map(group => { + const groupKey = + group.metadata.namespace && + group.metadata.namespace !== DEFAULT_NAMESPACE + ? `${group.metadata.namespace}/${group.metadata.name}` + : group.metadata.name; + return [groupKey, group.spec.members || []]; + }), + ); + const usersByName = new Map(users.map(u => [u.metadata.name, u])); for (const [groupName, userNames] of groupMemberUsers.entries()) { for (const userName of userNames) { diff --git a/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts index 7bb73990b3..745f52d6c5 100644 --- a/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { GroupEntity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { DefaultGithubCredentialsProvider, @@ -32,11 +33,15 @@ import { import { graphql } from '@octokit/graphql'; import { Logger } from 'winston'; import { + assignGroupsToUsers, buildOrgHierarchy, + defaultOrganizationTeamTransformer, getOrganizationTeams, getOrganizationUsers, GithubMultiOrgConfig, readGithubMultiOrgConfig, + TeamTransformer, + UserTransformer, } from '../lib'; /** @@ -57,6 +62,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { options: { logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ) { const c = config.getOptionalConfig('catalog.processors.githubMultiOrg'); @@ -69,12 +76,16 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { }); } - constructor(options: { - integrations: ScmIntegrationRegistry; - logger: Logger; - orgs: GithubMultiOrgConfig; - githubCredentialsProvider?: GithubCredentialsProvider; - }) { + constructor( + private options: { + integrations: ScmIntegrationRegistry; + logger: Logger; + orgs: GithubMultiOrgConfig; + githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; + }, + ) { this.integrations = options.integrations; this.logger = options.logger; this.orgs = options.orgs; @@ -130,12 +141,22 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { client, orgConfig.name, tokenType, - orgConfig.userNamespace, + this.options.userTransformer, ); - const { groups, groupMemberUsers } = await getOrganizationTeams( + const { groups } = await getOrganizationTeams( client, orgConfig.name, - orgConfig.groupNamespace, + async (team, ctx): Promise => { + const result = this.options.teamTransformer + ? await this.options.teamTransformer(team, ctx) + : await defaultOrganizationTeamTransformer(team, ctx); + + if (result) { + result.metadata.namespace = orgConfig.groupNamespace; + } + + return result; + }, ); const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1); @@ -151,15 +172,7 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { allUsersMap.set(prefix + u.metadata.name, u); } }); - - for (const [groupName, userNames] of groupMemberUsers.entries()) { - for (const userName of userNames) { - const user = allUsersMap.get(prefix + userName); - if (user && !user.spec.memberOf.includes(groupName)) { - user.spec.memberOf.push(groupName); - } - } - } + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); for (const group of groups) { diff --git a/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts index 0ef81ac907..90c168ccf4 100644 --- a/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts @@ -101,17 +101,14 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { this.logger.info('Reading GitHub users and groups'); const { users } = await getOrganizationUsers(client, org, tokenType); - const { groups, groupMemberUsers } = await getOrganizationTeams( - client, - org, - ); + const { groups } = await getOrganizationTeams(client, org); const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1); this.logger.debug( `Read ${users.length} GitHub users and ${groups.length} GitHub groups in ${duration} seconds`, ); - assignGroupsToUsers(users, groupMemberUsers); + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); // Done! diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index 6d3badf865..9a75f52afa 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -37,7 +37,7 @@ import { readProviderConfigs, GithubEntityProviderConfig, } from './GithubEntityProviderConfig'; -import { getOrganizationRepositories, Repository } from '../lib/github'; +import { getOrganizationRepositories, RepositoryResponse } from '../lib/github'; import { satisfiesTopicFilter } from '../lib/util'; /** @@ -175,7 +175,7 @@ export class GithubEntityProvider implements EntityProvider { } // go to the server and get all of the repositories - private async findCatalogFiles(): Promise { + private async findCatalogFiles(): Promise { const organization = this.config.organization; const host = this.integration.host; const catalogPath = this.config.catalogPath; @@ -208,7 +208,7 @@ export class GithubEntityProvider implements EntityProvider { return repositories; } - private matchesFilters(repositories: Repository[]) { + private matchesFilters(repositories: RepositoryResponse[]) { const repositoryFilter = this.config.filters?.repository; const topicFilters = this.config.filters?.topic; @@ -226,7 +226,7 @@ export class GithubEntityProvider implements EntityProvider { return matchingRepositories; } - private createLocationUrl(repository: Repository): string { + private createLocationUrl(repository: RepositoryResponse): string { const branch = this.config.filters?.branch || repository.defaultBranchRef?.name || '-'; const catalogFile = this.config.catalogPath.startsWith('/') diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts index b3fc5022ec..0b8765b93e 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts @@ -163,6 +163,7 @@ describe('GithubOrgEntityProvider', () => { picture: 'http://example.com/team.jpeg', }, type: 'team', + members: ['a'], }, }, locationKey: 'github-org-provider:my-id', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts index 2fc8ce7300..210df46363 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts @@ -43,6 +43,7 @@ import { getOrganizationUsers, parseGithubOrgUrl, } from '../lib'; +import { TeamTransformer, UserTransformer } from '../lib/defaultTransformers'; /** * Options for {@link GithubOrgEntityProvider}. @@ -88,6 +89,16 @@ export interface GithubOrgEntityProviderOptions { * Optionally supply a custom credentials provider, replacing the default one. */ githubCredentialsProvider?: GithubCredentialsProvider; + + /** + * Optionally include a user transformer for transforming from GitHub users to User Entities + */ + userTransformer?: UserTransformer; + + /** + * Optionally include a team transformer for transforming from GitHub teams to Group Entities + */ + teamTransformer?: TeamTransformer; } // TODO: Consider supporting an (optional) webhook that reacts on org changes @@ -123,6 +134,8 @@ export class GithubOrgEntityProvider implements EntityProvider { githubCredentialsProvider: options.githubCredentialsProvider || DefaultGithubCredentialsProvider.fromIntegrations(integrations), + userTransformer: options.userTransformer, + teamTransformer: options.teamTransformer, }); provider.schedule(options.schedule); @@ -137,6 +150,8 @@ export class GithubOrgEntityProvider implements EntityProvider { gitHubConfig: GithubIntegrationConfig; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ) { this.credentialsProvider = @@ -177,12 +192,19 @@ export class GithubOrgEntityProvider implements EntityProvider { }); const { org } = parseGithubOrgUrl(this.options.orgUrl); - const { users } = await getOrganizationUsers(client, org, tokenType); - const { groups, groupMemberUsers } = await getOrganizationTeams( + const { users } = await getOrganizationUsers( client, org, + tokenType, + this.options.userTransformer, ); - assignGroupsToUsers(users, groupMemberUsers); + const { groups } = await getOrganizationTeams( + client, + org, + this.options.teamTransformer, + ); + + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); const { markCommitComplete } = markReadComplete({ users, groups }); diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 18cce9e01e..3eed702b41 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.1.9 + +### Patch Changes + +- 6bb046bcbe: Add `gitlabDiscoveryEntityProviderCatalogModule` (new backend-plugin-api, alpha). +- 81cedb5033: `GitlabDiscoveryEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://backstage.io/docs/integrations/gitlab/discovery + +- 4c9f7847e4: Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index e556d4b2de..4f9e4a6848 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.1.9-next.0", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -54,7 +53,8 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/uuid": "^8.0.0", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 8a58fce1f5..19c1811c7c 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.5.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index d095be6b5c..2afdd4984c 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend module that helps integrate towards LDAP", - "version": "0.5.5-next.0", + "version": "0.5.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 8b8d4479d3..92182202a7 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.4.4 + +### Patch Changes + +- 0e37858f22: Added cause information to logged warnings +- 8d1a5e08ca: `MicrosoftGraphOrgEntityProvider`: Add option to configure schedule via `app-config.yaml` instead of in code. + + Please find how to configure the schedule at the config at + https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-msgraph#readme + +- 384f99c276: Add `microsoftGraphOrgEntityProviderCatalogModule` (new backend-plugin-api, alpha). +- Updated dependencies + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + +## 0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index cf301c71a0..de191f2fce 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.4.4-next.0", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts index 8e1d9a3776..0ed411bfea 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts @@ -122,7 +122,7 @@ export async function readMicrosoftGraphUsers( 120, ); } catch (e) { - options.logger.warn(`Unable to load photo for ${user.id}`); + options.logger.warn(`Unable to load photo for ${user.id}, ${e}`); } const entity = await transformer(user, userPhoto); @@ -206,7 +206,7 @@ export async function readMicrosoftGraphUsersInGroups( expand: options.userExpand, }); } catch (e) { - options.logger.warn(`Unable to load user for ${userId}`); + options.logger.warn(`Unable to load user for ${userId}, ${e}`); } if (user) { try { @@ -217,7 +217,7 @@ export async function readMicrosoftGraphUsersInGroups( 120, ); } catch (e) { - options.logger.warn(`Unable to load userphoto for ${userId}`); + options.logger.warn(`Unable to load userphoto for ${userId}, ${e}`); } const entity = await transformer(user, userPhoto); diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 0dc46b07a7..519efcc45d 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.4 + +### Patch Changes + +- 4ce887400d: Added support to use the `UrlReaders` when `$ref` pointing to a URL. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/config@1.0.4 + +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 6f21b8b2e0..1055b5ea92 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", - "version": "0.1.4-next.0", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 494f332c12..75913bdf52 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-catalog-backend +## 1.5.1 + +### Patch Changes + +- c1a4addda3: Improve processing error logging. + + Adds `location` and `owner` to the logging meta if they are available. + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-scaffolder-common@1.2.2 + - @backstage/plugin-search-common@1.1.1 + +## 1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.5.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 10b9afc291..e5d464c29a 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -37,7 +37,7 @@ import { EntityRelationSpec } from '@backstage/plugin-catalog-node'; import { GetEntitiesRequest } from '@backstage/catalog-client'; import { JsonValue } from '@backstage/types'; import { LocationEntityV1alpha1 } from '@backstage/catalog-model'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec as LocationSpec_2 } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { Permission } from '@backstage/plugin-permission-common'; import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; @@ -86,9 +86,9 @@ export class AnnotateLocationEntityProcessor implements CatalogProcessor { // (undocumented) preProcessEntity( entity: Entity, - location: LocationSpec, + location: LocationSpec_2, _: CatalogProcessorEmit, - originLocation: LocationSpec, + originLocation: LocationSpec_2, ): Promise; } @@ -100,7 +100,7 @@ export class AnnotateScmSlugEntityProcessor implements CatalogProcessor { // (undocumented) getProcessorName(): string; // (undocumented) - preProcessEntity(entity: Entity, location: LocationSpec): Promise; + preProcessEntity(entity: Entity, location: LocationSpec_2): Promise; } // @public (undocumented) @@ -110,7 +110,7 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor { // (undocumented) postProcessEntity( entity: Entity, - _location: LocationSpec, + _location: LocationSpec_2, emit: CatalogProcessorEmit, ): Promise; // (undocumented) @@ -284,7 +284,7 @@ export class CodeOwnersProcessor implements CatalogProcessor { // (undocumented) getProcessorName(): string; // (undocumented) - preProcessEntity(entity: Entity, location: LocationSpec): Promise; + preProcessEntity(entity: Entity, location: LocationSpec_2): Promise; } // @alpha @@ -409,7 +409,7 @@ export class FileReaderProcessor implements CatalogProcessor { getProcessorName(): string; // (undocumented) readLocation( - location: LocationSpec, + location: LocationSpec_2, optional: boolean, emit: CatalogProcessorEmit, parser: CatalogProcessorParser, @@ -431,7 +431,7 @@ export class LocationEntityProcessor implements CatalogProcessor { // (undocumented) postProcessEntity( entity: Entity, - location: LocationSpec, + location: LocationSpec_2, emit: CatalogProcessorEmit, ): Promise; } @@ -441,18 +441,19 @@ export type LocationEntityProcessorOptions = { integrations: ScmIntegrationRegistry; }; -export { LocationSpec }; +// @public @deprecated +export type LocationSpec = LocationSpec_2; // @public (undocumented) export function locationSpecToLocationEntity(opts: { - location: LocationSpec; + location: LocationSpec_2; parentEntity?: Entity; }): LocationEntityV1alpha1; // @public (undocumented) export function parseEntityYaml( data: Buffer, - location: LocationSpec, + location: LocationSpec_2, ): Iterable; // @alpha @@ -518,7 +519,7 @@ export class PlaceholderProcessor implements CatalogProcessor { // (undocumented) preProcessEntity( entity: Entity, - location: LocationSpec, + location: LocationSpec_2, emit: CatalogProcessorEmit, ): Promise; } @@ -574,7 +575,7 @@ export class UrlReaderProcessor implements CatalogProcessor { getProcessorName(): string; // (undocumented) readLocation( - location: LocationSpec, + location: LocationSpec_2, optional: boolean, emit: CatalogProcessorEmit, parser: CatalogProcessorParser, diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts index 950ed2f63c..daa70656bc 100644 --- a/plugins/catalog-backend/config.d.ts +++ b/plugins/catalog-backend/config.d.ts @@ -25,7 +25,7 @@ export interface Config { * An undefined list of matchers means match all, an empty list of * matchers means match none. * - * This is commonly used to put in what amounts to a whitelist of kinds + * This is commonly used to put in what amounts to an allowlist of kinds * that regular users of Backstage are permitted to register locations * for. This can be used to stop them from registering yaml files * describing for example a Group entity called "admin" that they make diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index b18a133505..8d8c6b1271 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.5.1-next.0", + "version": "1.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -80,7 +80,7 @@ "@types/uuid": "^8.0.0", "better-sqlite3": "^7.5.0", "luxon": "^3.0.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3", "wait-for-expect": "^3.0.2" }, diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 34060814aa..84673a3900 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -80,6 +80,36 @@ export type EntitiesResponse = { pageInfo: PageInfo; }; +/** + * A request for a batch of entities. + */ +export interface EntitiesBatchRequest { + /** + * The refs for which to fetch entities. + */ + entityRefs: string[]; + /** + * Any additional filters to apply in the selection of the entities. + */ + filter?: EntityFilter; + /** + * Strips out only the parts of the entity bodies to include in the response. + */ + fields?: (entity: Entity) => Entity; + /** + * The optional token that authorizes the action. + */ + authorizationToken?: string; +} + +export interface EntitiesBatchResponse { + /** + * The list of entities, in the same order as the refs in the request. Entries + * that are null signify that no entity existed with that ref. + */ + items: Array; +} + export type EntityAncestryResponse = { rootEntityRef: string; items: Array<{ @@ -130,6 +160,11 @@ export interface EntitiesCatalog { */ entities(request?: EntitiesRequest): Promise; + /** + * Fetches a batch of entities. + */ + entitiesBatch(request: EntitiesBatchRequest): Promise; + /** * Removes a single entity. * diff --git a/plugins/catalog-backend/src/index.ts b/plugins/catalog-backend/src/index.ts index 88696498d0..000dd94e8b 100644 --- a/plugins/catalog-backend/src/index.ts +++ b/plugins/catalog-backend/src/index.ts @@ -22,7 +22,6 @@ export type { DeferredEntity, - LocationSpec, EntityRelationSpec, CatalogProcessor, CatalogProcessorParser, @@ -48,3 +47,19 @@ export * from './processing'; export * from './search'; export * from './service'; export * from './util'; + +import { LocationSpec as NonDeprecatedLocationSpec } from '@backstage/plugin-catalog-common'; + +/** + * Holds the entity location information. + * + * @remarks + * + * `presence` flag: when using repo importer plugin, location is being created before the component yaml file is merged to the main branch. + * This flag is then set to indicate that the file can be not present. + * default value: 'required'. + * + * @public + * @deprecated use the same type from `@backstage/plugin-catalog-common` instead + */ +export type LocationSpec = NonDeprecatedLocationSpec; diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.ts index ce226bd09d..548c71d833 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.ts @@ -17,7 +17,7 @@ import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; import path from 'path'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; /** * Rules to apply to catalog entities. diff --git a/plugins/catalog-backend/src/modules/codeowners/CodeOwnersProcessor.ts b/plugins/catalog-backend/src/modules/codeowners/CodeOwnersProcessor.ts index 63f3d406f5..186b732271 100644 --- a/plugins/catalog-backend/src/modules/codeowners/CodeOwnersProcessor.ts +++ b/plugins/catalog-backend/src/modules/codeowners/CodeOwnersProcessor.ts @@ -22,7 +22,8 @@ import { ScmIntegrations, } from '@backstage/integration'; import { Logger } from 'winston'; -import { CatalogProcessor, LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { findCodeOwnerByTarget } from './lib'; const ALLOWED_KINDS = ['API', 'Component', 'Domain', 'Resource', 'System']; diff --git a/plugins/catalog-backend/src/modules/core/AnnotateLocationEntityProcessor.ts b/plugins/catalog-backend/src/modules/core/AnnotateLocationEntityProcessor.ts index a86525429e..d3329fa86c 100644 --- a/plugins/catalog-backend/src/modules/core/AnnotateLocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/AnnotateLocationEntityProcessor.ts @@ -25,10 +25,10 @@ import { } from '@backstage/catalog-model'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { identity, merge, pickBy } from 'lodash'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, } from '@backstage/plugin-catalog-node'; /** @public */ diff --git a/plugins/catalog-backend/src/modules/core/AnnotateScmSlugEntityProcessor.ts b/plugins/catalog-backend/src/modules/core/AnnotateScmSlugEntityProcessor.ts index 41e75e5e8e..2c18ba1d7d 100644 --- a/plugins/catalog-backend/src/modules/core/AnnotateScmSlugEntityProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/AnnotateScmSlugEntityProcessor.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Entity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { @@ -21,7 +22,8 @@ import { } from '@backstage/integration'; import parseGitUrl from 'git-url-parse'; import { identity, merge, pickBy } from 'lodash'; -import { CatalogProcessor, LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; const GITHUB_ACTIONS_ANNOTATION = 'github.com/project-slug'; const GITLAB_ACTIONS_ANNOTATION = 'gitlab.com/project-slug'; diff --git a/plugins/catalog-backend/src/modules/core/BuiltinKindsEntityProcessor.ts b/plugins/catalog-backend/src/modules/core/BuiltinKindsEntityProcessor.ts index 6e05daf591..4dbb23addc 100644 --- a/plugins/catalog-backend/src/modules/core/BuiltinKindsEntityProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/BuiltinKindsEntityProcessor.ts @@ -48,10 +48,10 @@ import { UserEntity, userEntityV1alpha1Validator, } from '@backstage/catalog-model'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog-backend/src/modules/core/FileReaderProcessor.ts b/plugins/catalog-backend/src/modules/core/FileReaderProcessor.ts index af6fba52c0..e0cd11fa3b 100644 --- a/plugins/catalog-backend/src/modules/core/FileReaderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/FileReaderProcessor.ts @@ -18,11 +18,11 @@ import fs from 'fs-extra'; import g from 'glob'; import path from 'path'; import { promisify } from 'util'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorEmit, CatalogProcessorParser, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts index 3676b4f727..1db74b3b56 100644 --- a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts @@ -17,11 +17,11 @@ import { Entity, LocationEntity } from '@backstage/catalog-model'; import { ScmIntegrationRegistry } from '@backstage/integration'; import path from 'path'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { processingResult, CatalogProcessor, CatalogProcessorEmit, - LocationSpec, } from '@backstage/plugin-catalog-node'; export function toAbsoluteUrl( diff --git a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts index e6b5ee279d..ec432c5fdc 100644 --- a/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/PlaceholderProcessor.ts @@ -19,10 +19,10 @@ import { Entity } from '@backstage/catalog-model'; import { JsonValue } from '@backstage/types'; import { ScmIntegrationRegistry } from '@backstage/integration'; import yaml from 'yaml'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts index fe9f21ebb4..5e31dcbd1a 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts @@ -20,6 +20,7 @@ import { assertError } from '@backstage/errors'; import parseGitUrl from 'git-url-parse'; import limiterFactory from 'p-limit'; import { Logger } from 'winston'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorCache, @@ -27,7 +28,6 @@ import { CatalogProcessorEntityResult, CatalogProcessorParser, CatalogProcessorResult, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog-backend/src/modules/util/parse.ts b/plugins/catalog-backend/src/modules/util/parse.ts index d3aa915e49..778c176323 100644 --- a/plugins/catalog-backend/src/modules/util/parse.ts +++ b/plugins/catalog-backend/src/modules/util/parse.ts @@ -17,10 +17,10 @@ import { Entity, stringifyLocationRef } from '@backstage/catalog-model'; import lodash from 'lodash'; import yaml from 'yaml'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessorParser, CatalogProcessorResult, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts index 2cc0e2dc40..bef2878099 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { + ANNOTATION_LOCATION, + Entity, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { assertError, serializeError, stringifyError } from '@backstage/errors'; import { Hash } from 'crypto'; import stableStringify from 'fast-json-stable-stringify'; @@ -116,11 +120,12 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { }); } + const location = + unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION]; for (const error of result.errors) { - // TODO(freben): Try to extract the location out of the unprocessed - // entity and add as meta to the log lines this.logger.warn(error.message, { entity: entityRef, + location, }); } const errorsString = JSON.stringify( diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts index 79876f70d8..e95fede8b7 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts @@ -32,10 +32,10 @@ import { JsonValue } from '@backstage/types'; import { ScmIntegrationRegistry } from '@backstage/integration'; import path from 'path'; import { Logger } from 'winston'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { CatalogProcessor, CatalogProcessorParser, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; import { diff --git a/plugins/catalog-backend/src/processing/util.ts b/plugins/catalog-backend/src/processing/util.ts index bd96763a54..cd93be3c8b 100644 --- a/plugins/catalog-backend/src/processing/util.ts +++ b/plugins/catalog-backend/src/processing/util.ts @@ -27,7 +27,7 @@ import { JsonObject, JsonValue } from '@backstage/types'; import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import path from 'path'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; export function isLocationEntity(entity: Entity): entity is LocationEntity { return entity.kind === 'Location'; diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts index 66764dc89f..cbaf876071 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts @@ -24,6 +24,7 @@ import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; describe('AuthorizedEntitiesCatalog', () => { const fakeCatalog = { entities: jest.fn(), + entitiesBatch: jest.fn(), removeEntityByUid: jest.fn(), entityAncestry: jest.fn(), facets: jest.fn(), @@ -92,6 +93,67 @@ describe('AuthorizedEntitiesCatalog', () => { }); }); + describe('entitiesBatch', () => { + it('returns empty response on DENY', async () => { + fakePermissionApi.authorizeConditional.mockResolvedValue([ + { result: AuthorizeResult.DENY }, + ]); + const catalog = createCatalog(); + + await expect( + catalog.entitiesBatch({ + entityRefs: ['component:default/component-a'], + authorizationToken: 'abcd', + }), + ).resolves.toEqual({ + items: [null], + }); + + expect(fakeCatalog.entitiesBatch).not.toHaveBeenCalled(); + }); + + it('calls underlying catalog method with correct filter on CONDITIONAL', async () => { + fakePermissionApi.authorizeConditional.mockResolvedValue([ + { + result: AuthorizeResult.CONDITIONAL, + conditions: { + rule: 'IS_ENTITY_KIND', + params: { kinds: ['b'] }, + }, + }, + ]); + const catalog = createCatalog(isEntityKind); + + await catalog.entitiesBatch({ + entityRefs: ['component:default/component-a'], + authorizationToken: 'abcd', + }); + + expect(fakeCatalog.entitiesBatch).toHaveBeenCalledWith({ + entityRefs: ['component:default/component-a'], + authorizationToken: 'abcd', + filter: { key: 'kind', values: ['b'] }, + }); + }); + + it('calls underlying catalog method on ALLOW', async () => { + fakePermissionApi.authorizeConditional.mockResolvedValue([ + { result: AuthorizeResult.ALLOW }, + ]); + const catalog = createCatalog(); + + await catalog.entitiesBatch({ + entityRefs: ['component:default/component-a'], + authorizationToken: 'abcd', + }); + + expect(fakeCatalog.entitiesBatch).toHaveBeenCalledWith({ + entityRefs: ['component:default/component-a'], + authorizationToken: 'abcd', + }); + }); + }); + describe('removeEntityByUid', () => { it('throws error on DENY', async () => { fakeCatalog.entities.mockResolvedValue({ diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts index 0e861a39e1..c62e9f9a84 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts @@ -26,6 +26,8 @@ import { } from '@backstage/plugin-permission-common'; import { ConditionTransformer } from '@backstage/plugin-permission-node'; import { + EntitiesBatchRequest, + EntitiesBatchResponse, EntitiesCatalog, EntitiesRequest, EntitiesResponse, @@ -73,6 +75,37 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog { return this.entitiesCatalog.entities(request); } + async entitiesBatch( + request: EntitiesBatchRequest, + ): Promise { + const authorizeDecision = ( + await this.permissionApi.authorizeConditional( + [{ permission: catalogEntityReadPermission }], + { token: request?.authorizationToken }, + ) + )[0]; + + if (authorizeDecision.result === AuthorizeResult.DENY) { + return { + items: new Array(request.entityRefs.length).fill(null), + }; + } + + if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) { + const permissionFilter: EntityFilter = this.transformConditions( + authorizeDecision.conditions, + ); + return this.entitiesCatalog.entitiesBatch({ + ...request, + filter: request?.filter + ? { allOf: [permissionFilter, request.filter] } + : permissionFilter, + }); + } + + return this.entitiesCatalog.entitiesBatch(request); + } + async removeEntityByUid( uid: string, options?: { authorizationToken?: string }, diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index 49d4fe9e19..515a862515 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -534,6 +534,60 @@ describe('DefaultEntitiesCatalog', () => { ); }); + describe('entitiesBatch', () => { + it.each(databases.eachSupportedId())( + 'queries for entities by ref, including duplicates, and gracefully returns null for missing entities', + async databaseId => { + const { knex } = await createDatabase(databaseId); + + await addEntity( + knex, + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'one' }, + spec: {}, + relations: [], + }, + [], + ); + await addEntity( + knex, + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'two' }, + spec: {}, + relations: [], + }, + [], + ); + + const catalog = new DefaultEntitiesCatalog(knex, stitcher); + + const { items } = await catalog.entitiesBatch({ + entityRefs: [ + 'k:default/two', + 'k:default/one', + 'k:default/two', + 'not-even-a-ref', + 'k:default/does-not-exist', + 'k:default/two', + ], + }); + + expect(items.map(e => e && stringifyEntityRef(e))).toEqual([ + 'k:default/two', + 'k:default/one', + 'k:default/two', + null, + null, + 'k:default/two', + ]); + }, + ); + }); + describe('removeEntityByUid', () => { it.each(databases.eachSupportedId())( 'also clears parent hashes', diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index dc84b12484..81de6484c3 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -23,6 +23,8 @@ import { InputError, NotFoundError } from '@backstage/errors'; import { Knex } from 'knex'; import lodash from 'lodash'; import { + EntitiesBatchRequest, + EntitiesBatchResponse, EntitiesCatalog, EntitiesRequest, EntitiesResponse, @@ -237,6 +239,38 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { }; } + async entitiesBatch( + request: EntitiesBatchRequest, + ): Promise { + const lookup = new Map(); + + for (const chunk of lodash.chunk(request.entityRefs, 200)) { + let query = this.database('final_entities') + .innerJoin('refresh_state', { + 'refresh_state.entity_id': 'final_entities.entity_id', + }) + .select({ + entityRef: 'refresh_state.entity_ref', + entity: 'final_entities.final_entity', + }) + .whereIn('refresh_state.entity_ref', chunk); + if (request?.filter) { + query = parseFilter(request.filter, query, this.database); + } + for (const row of await query) { + lookup.set(row.entityRef, row.entity ? JSON.parse(row.entity) : null); + } + } + + let items = request.entityRefs.map(ref => lookup.get(ref) ?? null); + + if (request.fields) { + items = items.map(e => e && request.fields!(e)); + } + + return { items }; + } + async removeEntityByUid(uid: string): Promise { // Clear the hashed state of the immediate parents of the deleted entity. // This makes sure that when they get reprocessed, their output is written diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index f383df7364..541359feb6 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -48,6 +48,7 @@ describe('createRouter readonly disabled', () => { beforeAll(async () => { entitiesCatalog = { entities: jest.fn(), + entitiesBatch: jest.fn(), removeEntityByUid: jest.fn(), entityAncestry: jest.fn(), facets: jest.fn(), @@ -257,6 +258,38 @@ describe('createRouter readonly disabled', () => { }); }); + describe('POST /entities/by-refs', () => { + it.each([ + '', + 'not json', + '[', + '[]', + '{}', + '{"unknown":7}', + '{"entityRefs":7}', + '{"entityRefs":[7]}', + ])('properly rejects malformed request body, %p', async p => { + await expect( + request(app) + .post('/entities/by-refs') + .set('Content-Type', 'application/json') + .send(p), + ).resolves.toMatchObject({ status: 400 }); + }); + + it('can fetch entities by refs', async () => { + const entity: Entity = {} as any; + entitiesCatalog.entitiesBatch.mockResolvedValue({ items: [entity] }); + const response = await request(app) + .post('/entities/by-refs') + .set('Content-Type', 'application/json') + .send('{"entityRefs":["a"]}'); + expect(entitiesCatalog.entitiesBatch).toHaveBeenCalledTimes(1); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ items: [entity] }); + }); + }); + describe('GET /locations', () => { it('happy path: lists locations', async () => { const locations: Location[] = [ @@ -517,6 +550,7 @@ describe('createRouter readonly enabled', () => { beforeAll(async () => { entitiesCatalog = { entities: jest.fn(), + entitiesBatch: jest.fn(), removeEntityByUid: jest.fn(), entityAncestry: jest.fn(), facets: jest.fn(), @@ -706,6 +740,7 @@ describe('NextRouter permissioning', () => { beforeAll(async () => { entitiesCatalog = { entities: jest.fn(), + entitiesBatch: jest.fn(), removeEntityByUid: jest.fn(), entityAncestry: jest.fn(), facets: jest.fn(), diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index 5267519c33..4680dbb899 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -28,24 +28,25 @@ import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import yn from 'yn'; +import { z } from 'zod'; import { EntitiesCatalog } from '../catalog/types'; import { LocationAnalyzer } from '../ingestion/types'; +import { CatalogProcessingOrchestrator } from '../processing/types'; +import { validateEntityEnvelope } from '../processing/util'; import { basicEntityFilter, + entitiesBatchRequest, parseEntityFilterParams, parseEntityPaginationParams, parseEntityTransformParams, } from './request'; +import { parseEntityFacetParams } from './request/parseEntityFacetParams'; +import { LocationService, RefreshOptions, RefreshService } from './types'; import { disallowReadonlyMode, locationInput, validateRequestBody, } from './util'; -import { z } from 'zod'; -import { parseEntityFacetParams } from './request/parseEntityFacetParams'; -import { RefreshOptions, LocationService, RefreshService } from './types'; -import { CatalogProcessingOrchestrator } from '../processing/types'; -import { validateEntityEnvelope } from '../processing/util'; /** * Options used by {@link createRouter}. @@ -173,6 +174,16 @@ export async function createRouter( res.status(200).json(response); }, ) + .post('/entities/by-refs', async (req, res) => { + const request = entitiesBatchRequest(req); + const token = getBearerToken(req.header('authorization')); + const response = await entitiesCatalog.entitiesBatch({ + entityRefs: request.entityRefs, + fields: parseEntityTransformParams(req.query), + authorizationToken: token, + }); + res.status(200).json(response); + }) .get('/entity-facets', async (req, res) => { const response = await entitiesCatalog.facets({ filter: parseEntityFilterParams(req.query), diff --git a/plugins/catalog-backend/src/service/request/entitiesBatchRequest.ts b/plugins/catalog-backend/src/service/request/entitiesBatchRequest.ts new file mode 100644 index 0000000000..b3a91f9491 --- /dev/null +++ b/plugins/catalog-backend/src/service/request/entitiesBatchRequest.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2022 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 { InputError } from '@backstage/errors'; +import { Request } from 'express'; +import { z } from 'zod'; + +const schema = z.object({ + entityRefs: z.array(z.string()), +}); + +export function entitiesBatchRequest(req: Request) { + try { + return schema.parse(req.body); + } catch (error) { + throw new InputError( + `Malformed request body (did you remember to specify an application/json content type?), ${error.message}`, + ); + } +} diff --git a/plugins/catalog-backend/src/service/request/index.ts b/plugins/catalog-backend/src/service/request/index.ts index 4ab579fbb6..0b09355e72 100644 --- a/plugins/catalog-backend/src/service/request/index.ts +++ b/plugins/catalog-backend/src/service/request/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export { entitiesBatchRequest } from './entitiesBatchRequest'; export { basicEntityFilter } from './basicEntityFilter'; export { parseEntityFilterParams } from './parseEntityFilterParams'; export { parseEntityPaginationParams } from './parseEntityPaginationParams'; diff --git a/plugins/catalog-backend/src/util/conversion.ts b/plugins/catalog-backend/src/util/conversion.ts index 83302722d2..0b92b88d90 100644 --- a/plugins/catalog-backend/src/util/conversion.ts +++ b/plugins/catalog-backend/src/util/conversion.ts @@ -23,7 +23,7 @@ import { stringifyLocationRef, } from '@backstage/catalog-model'; import { createHash } from 'crypto'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; export function locationSpecToMetadataName(location: LocationSpec) { const hash = createHash('sha1') diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index d1378e9418..ac236e1999 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-common +## 1.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-search-common@1.1.1 + ## 1.0.8-next.0 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 8af6d06c5a..5dcbc678b2 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-common", "description": "Common functionalities for the catalog plugin", - "version": "1.0.8-next.0", + "version": "1.0.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-customized/CHANGELOG.md b/plugins/catalog-customized/CHANGELOG.md index 04be429ab6..92c8a6e60f 100644 --- a/plugins/catalog-customized/CHANGELOG.md +++ b/plugins/catalog-customized/CHANGELOG.md @@ -1,5 +1,21 @@ # @internal/plugin-catalog-customized +## 0.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/plugin-catalog@1.6.1 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.0.4-next.0 ### Patch Changes diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 537180f05e..f302c48bf5 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -1,7 +1,7 @@ { "name": "@internal/plugin-catalog-customized", "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", - "version": "0.0.4-next.0", + "version": "0.0.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/.eslintrc.js b/plugins/catalog-graph/.eslintrc.js index e2a53a6ad2..45bb6db521 100644 --- a/plugins/catalog-graph/.eslintrc.js +++ b/plugins/catalog-graph/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + 'testing-library/prefer-screen-queries': 'error', + }, +}); diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 7f8e1e0277..29fa300e18 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-catalog-graph +## 0.2.23 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- 21d84ef332: feat: Enable theme overrides for components in catalog-graph plugin +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/theme@0.2.16 + +## 0.2.23-next.1 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.23-next.0 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 3b78d5d7ba..3216efb0ec 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.2.23-next.0", + "version": "0.2.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx index 74fcd4e501..27b67102e4 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Entity } from '@backstage/catalog-model'; import { ApiProvider } from '@backstage/core-app-api'; import { analyticsApiRef } from '@backstage/core-plugin-api'; import { - CatalogApi, catalogApiRef, EntityProvider, entityRouteRef, @@ -28,6 +28,7 @@ import { TestApiProvider, TestApiRegistry, } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { catalogGraphRouteRef } from '../../routes'; @@ -36,10 +37,24 @@ import { CatalogGraphCard } from './CatalogGraphCard'; describe('', () => { let entity: Entity; let wrapper: JSX.Element; - let catalog: jest.Mocked; + const catalog = { + getEntities: jest.fn(), + getEntityByRef: jest.fn(), + removeEntityByUid: jest.fn(), + getLocationById: jest.fn(), + getLocationByRef: jest.fn(), + addLocation: jest.fn(), + removeLocationById: jest.fn(), + refreshEntity: jest.fn(), + getEntityAncestors: jest.fn(), + getEntityFacets: jest.fn(), + validateEntity: jest.fn(), + }; let apis: TestApiRegistry; beforeEach(() => { + jest.clearAllMocks(); + entity = { apiVersion: 'a', kind: 'b', @@ -48,19 +63,6 @@ describe('', () => { namespace: 'd', }, }; - catalog = { - getEntities: jest.fn(), - getEntityByRef: jest.fn(async _ => ({ ...entity, relations: [] })), - removeEntityByUid: jest.fn(), - getLocationById: jest.fn(), - getLocationByRef: jest.fn(), - addLocation: jest.fn(), - removeLocationById: jest.fn(), - refreshEntity: jest.fn(), - getEntityAncestors: jest.fn(), - getEntityFacets: jest.fn(), - validateEntity: jest.fn(), - }; apis = TestApiRegistry.from([catalogApiRef, catalog]); wrapper = ( @@ -73,20 +75,30 @@ describe('', () => { }); test('renders without exploding', async () => { - const { findByText, findAllByTestId } = await renderInTestApp(wrapper, { + catalog.getEntityByRef.mockImplementation(async _ => ({ + ...entity, + relations: [], + })); + + await renderInTestApp(wrapper, { mountedRoutes: { '/entity/{kind}/{namespace}/{name}': entityRouteRef, '/catalog-graph': catalogGraphRouteRef, }, }); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(1); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(1); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(1); }); test('renders with custom title', async () => { - const { findByText } = await renderInTestApp( + catalog.getEntityByRef.mockImplementation(async _ => ({ + ...entity, + relations: [], + })); + + await renderInTestApp( @@ -100,29 +112,63 @@ describe('', () => { }, ); - expect(await findByText('Custom Title')).toBeInTheDocument(); + expect(await screen.findByText('Custom Title')).toBeInTheDocument(); }); test('renders link to standalone viewer', async () => { - const { findByText, getByText } = await renderInTestApp(wrapper, { + catalog.getEntityByRef.mockImplementation(async _ => ({ + ...entity, + relations: [], + })); + + await renderInTestApp(wrapper, { mountedRoutes: { '/entity/{kind}/{namespace}/{name}': entityRouteRef, '/catalog-graph': catalogGraphRouteRef, }, }); - expect(await findByText('b:d/c')).toBeInTheDocument(); - const button = getByText('View graph'); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + const button = screen.getByText('View graph'); expect(button).toBeInTheDocument(); expect(button.closest('a')).toHaveAttribute( 'href', - '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc', + '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc&maxDepth=2&unidirectional=true&mergeRelations=true&direction=LR', + ); + }); + + test('renders link to standalone viewer with custom config', async () => { + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/catalog-graph': catalogGraphRouteRef, + }, + }, + ); + + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + const button = screen.getByText('View graph'); + expect(button).toBeInTheDocument(); + expect(button.closest('a')).toHaveAttribute( + 'href', + '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc&maxDepth=3&unidirectional=true&mergeRelations=false&direction=LR', ); }); test('captures analytics event on click', async () => { + catalog.getEntityByRef.mockImplementation(async _ => ({ + ...entity, + relations: [], + })); + const analyticsSpy = new MockAnalyticsApi(); - const { findByText } = await renderInTestApp( + await renderInTestApp( {wrapper} , @@ -134,8 +180,8 @@ describe('', () => { }, ); - expect(await findByText('b:d/c')).toBeInTheDocument(); - await userEvent.click(await findByText('b:d/c')); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + await userEvent.click(await screen.findByText('b:d/c')); expect(analyticsSpy.getEvents()[0]).toMatchObject({ action: 'click', diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx index ae1ca9c22d..40ee90d784 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx @@ -39,18 +39,21 @@ import { RelationPairs, } from '../EntityRelationsGraph'; -const useStyles = makeStyles({ - card: ({ height }) => ({ - display: 'flex', - flexDirection: 'column', - maxHeight: height, - minHeight: height, - }), - graph: { - flex: 1, - minHeight: 0, +const useStyles = makeStyles( + { + card: ({ height }) => ({ + display: 'flex', + flexDirection: 'column', + maxHeight: height, + minHeight: height, + }), + graph: { + flex: 1, + minHeight: 0, + }, }, -}); + { name: 'PluginCatalogGraphCatalogGraphCard' }, +); export const CatalogGraphCard = (props: { variant?: InfoCardVariants; @@ -106,7 +109,15 @@ export const CatalogGraphCard = (props: { ); const catalogGraphParams = qs.stringify( - { rootEntityRefs: [stringifyEntityRef(entity)] }, + { + rootEntityRefs: [stringifyEntityRef(entity)], + maxDepth: maxDepth + 1, + unidirectional, + mergeRelations, + kinds, + relations, + direction, + }, { arrayFormat: 'brackets', addQueryPrefix: true }, ); const catalogGraphUrl = `${catalogGraphRoute()}${catalogGraphParams}`; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx index 9cca6ef9be..f7e1a9fbe7 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RELATION_HAS_PART, RELATION_PART_OF } from '@backstage/catalog-model'; import { analyticsApiRef } from '@backstage/core-plugin-api'; -import { - CatalogApi, - catalogApiRef, - entityRouteRef, -} from '@backstage/plugin-catalog-react'; +import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react'; import { MockAnalyticsApi, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { CatalogGraphPage } from './CatalogGraphPage'; @@ -38,63 +36,59 @@ jest.mock('react-router', () => ({ describe('', () => { let wrapper: JSX.Element; - let catalog: jest.Mocked; + const entityC = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + relations: [ + { + type: RELATION_PART_OF, + targetRef: 'b:d/e', + target: { + kind: 'b', + namespace: 'd', + name: 'e', + }, + }, + ], + }; + const entityE = { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'e', + namespace: 'd', + }, + relations: [ + { + type: RELATION_HAS_PART, + targetRef: 'b:d/c', + target: { + kind: 'b', + namespace: 'd', + name: 'c', + }, + }, + ], + }; + const catalog = { + getEntities: jest.fn(), + getEntityByRef: jest.fn(), + removeEntityByUid: jest.fn(), + getLocationById: jest.fn(), + getLocationByRef: jest.fn(), + addLocation: jest.fn(), + removeLocationById: jest.fn(), + refreshEntity: jest.fn(), + getEntityAncestors: jest.fn(), + getEntityFacets: jest.fn(), + validateEntity: jest.fn(), + }; beforeEach(() => { - const entityC = { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c', - namespace: 'd', - }, - relations: [ - { - type: RELATION_PART_OF, - targetRef: 'b:d/e', - target: { - kind: 'b', - namespace: 'd', - name: 'e', - }, - }, - ], - }; - const entityE = { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'e', - namespace: 'd', - }, - relations: [ - { - type: RELATION_HAS_PART, - targetRef: 'b:d/c', - target: { - kind: 'b', - namespace: 'd', - name: 'c', - }, - }, - ], - }; - catalog = { - getEntities: jest.fn(), - getEntityByRef: jest.fn(async (n: any) => - n === 'b:d/e' ? entityE : entityC, - ), - removeEntityByUid: jest.fn(), - getLocationById: jest.fn(), - getLocationByRef: jest.fn(), - addLocation: jest.fn(), - removeLocationById: jest.fn(), - refreshEntity: jest.fn(), - getEntityAncestors: jest.fn(), - getEntityFacets: jest.fn(), - validateEntity: jest.fn(), - }; - wrapper = ( ', () => { afterEach(() => jest.resetAllMocks()); test('should render without exploding', async () => { - const { getByText, findByText, findAllByTestId } = await renderInTestApp( - wrapper, - { - mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, - }, - }, + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, ); - expect(getByText('Catalog Graph')).toBeInTheDocument(); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/e')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(2); + await renderInTestApp(wrapper, { + mountedRoutes: { + '/entity/{kind}/{namespace}/{name}': entityRouteRef, + }, + }); + + expect(screen.getByText('Catalog Graph')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/e')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(2); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(2); }); test('should toggle filters', async () => { - const { getByText, queryByText } = await renderInTestApp(wrapper, { + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, + ); + + await renderInTestApp(wrapper, { mountedRoutes: { '/entity/{kind}/{namespace}/{name}': entityRouteRef, }, }); - expect(queryByText('Max Depth')).toBeNull(); + expect(screen.queryByText('Max Depth')).toBeNull(); - await userEvent.click(getByText('Filters')); + await userEvent.click(screen.getByText('Filters')); - expect(getByText('Max Depth')).toBeInTheDocument(); + expect(screen.getByText('Max Depth')).toBeInTheDocument(); }); test('should select other entity', async () => { - const { getByText, findByText, findAllByTestId } = await renderInTestApp( - wrapper, - { - mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, - }, - }, + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, ); - expect(await findAllByTestId('node')).toHaveLength(2); - - await userEvent.click(getByText('b:d/e')); - - expect(await findByText('hasPart')).toBeInTheDocument(); - }); - - test('should navigate to entity', async () => { - const { getByText, findAllByTestId } = await renderInTestApp(wrapper, { + await renderInTestApp(wrapper, { mountedRoutes: { '/entity/{kind}/{namespace}/{name}': entityRouteRef, }, }); - expect(await findAllByTestId('node')).toHaveLength(2); + expect(await screen.findAllByTestId('node')).toHaveLength(2); + + await userEvent.click(screen.getByText('b:d/e')); + + expect(await screen.findByText('hasPart')).toBeInTheDocument(); + }); + + test('should navigate to entity', async () => { + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, + ); + + await renderInTestApp(wrapper, { + mountedRoutes: { + '/entity/{kind}/{namespace}/{name}': entityRouteRef, + }, + }); + + expect(await screen.findAllByTestId('node')).toHaveLength(2); const user = userEvent.setup(); await user.keyboard('{Shift>}'); - await user.click(getByText('b:d/e')); + await user.click(screen.getByText('b:d/e')); expect(navigate).toHaveBeenCalledWith('/entity/{kind}/{namespace}/{name}'); }); test('should capture analytics event when selecting other entity', async () => { + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, + ); + const analyticsSpy = new MockAnalyticsApi(); - const { getByText, findAllByTestId } = await renderInTestApp( + await renderInTestApp( {wrapper} , @@ -186,12 +194,12 @@ describe('', () => { }, ); - expect(await findAllByTestId('node')).toHaveLength(2); + expect(await screen.findAllByTestId('node')).toHaveLength(2); // We wait a bit here to reliably reproduce an issue where that requires the `baseVal` and `view` mocks await new Promise(r => setTimeout(r, 100)); - await userEvent.click(getByText('b:d/e')); + await userEvent.click(screen.getByText('b:d/e')); expect(analyticsSpy.getEvents()[0]).toMatchObject({ action: 'click', @@ -200,8 +208,12 @@ describe('', () => { }); test('should capture analytics event when navigating to entity', async () => { + catalog.getEntityByRef.mockImplementation(async (n: any) => + n === 'b:d/e' ? entityE : entityC, + ); + const analyticsSpy = new MockAnalyticsApi(); - const { getByText, findAllByTestId } = await renderInTestApp( + await renderInTestApp( {wrapper} , @@ -212,11 +224,11 @@ describe('', () => { }, ); - expect(await findAllByTestId('node')).toHaveLength(2); + expect(await screen.findAllByTestId('node')).toHaveLength(2); const user = userEvent.setup(); await user.keyboard('{Shift>}'); - await user.click(getByText('b:d/e')); + await user.click(screen.getByText('b:d/e')); expect(analyticsSpy.getEvents()[0]).toMatchObject({ action: 'click', diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx index a6a6c2a711..4a36d516e2 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx @@ -48,57 +48,60 @@ import { SelectedRelationsFilter } from './SelectedRelationsFilter'; import { SwitchFilter } from './SwitchFilter'; import { useCatalogGraphPage } from './useCatalogGraphPage'; -const useStyles = makeStyles(theme => ({ - content: { - minHeight: 0, - }, - container: { - height: '100%', - maxHeight: '100%', - minHeight: 0, - }, - fullHeight: { - maxHeight: '100%', - display: 'flex', - minHeight: 0, - }, - graphWrapper: { - position: 'relative', - flex: 1, - minHeight: 0, - display: 'flex', - }, - graph: { - flex: 1, - minHeight: 0, - }, - legend: { - position: 'absolute', - bottom: 0, - right: 0, - padding: theme.spacing(1), - '& .icon': { - verticalAlign: 'bottom', +const useStyles = makeStyles( + theme => ({ + content: { + minHeight: 0, }, - }, - filters: { - display: 'grid', - gridGap: theme.spacing(1), - gridAutoRows: 'auto', - [theme.breakpoints.up('lg')]: { - display: 'block', + container: { + height: '100%', + maxHeight: '100%', + minHeight: 0, }, - [theme.breakpoints.only('md')]: { - gridTemplateColumns: 'repeat(3, 1fr)', + fullHeight: { + maxHeight: '100%', + display: 'flex', + minHeight: 0, }, - [theme.breakpoints.only('sm')]: { - gridTemplateColumns: 'repeat(2, 1fr)', + graphWrapper: { + position: 'relative', + flex: 1, + minHeight: 0, + display: 'flex', }, - [theme.breakpoints.down('xs')]: { - gridTemplateColumns: 'repeat(1, 1fr)', + graph: { + flex: 1, + minHeight: 0, }, - }, -})); + legend: { + position: 'absolute', + bottom: 0, + right: 0, + padding: theme.spacing(1), + '& .icon': { + verticalAlign: 'bottom', + }, + }, + filters: { + display: 'grid', + gridGap: theme.spacing(1), + gridAutoRows: 'auto', + [theme.breakpoints.up('lg')]: { + display: 'block', + }, + [theme.breakpoints.only('md')]: { + gridTemplateColumns: 'repeat(3, 1fr)', + }, + [theme.breakpoints.only('sm')]: { + gridTemplateColumns: 'repeat(2, 1fr)', + }, + [theme.breakpoints.down('xs')]: { + gridTemplateColumns: 'repeat(1, 1fr)', + }, + }, + }), + { name: 'PluginCatalogGraphCatalogGraphPage' }, +); export const CatalogGraphPage = (props: { relationPairs?: RelationPairs; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.test.tsx index 0be0fca66b..85d9d97c7f 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CurveFilter.test.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { render, waitFor } from '@testing-library/react'; + +import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { CurveFilter } from './CurveFilter'; @@ -21,26 +22,22 @@ import { CurveFilter } from './CurveFilter'; describe('', () => { test('should display current curve label', () => { const onChange = jest.fn(); - const { getByText } = render( - , - ); + render(); - expect(getByText('Monotone X')).toBeInTheDocument(); + expect(screen.getByText('Monotone X')).toBeInTheDocument(); }); test('should select an alternative curve factory', async () => { const onChange = jest.fn(); - const { getByText, getByTestId } = render( - , - ); + render(); - expect(getByText('Step Before')).toBeInTheDocument(); + expect(screen.getByText('Step Before')).toBeInTheDocument(); - await userEvent.click(getByTestId('select')); - await userEvent.click(getByText('Monotone X')); + await userEvent.click(screen.getByTestId('select')); + await userEvent.click(screen.getByText('Monotone X')); await waitFor(() => { - expect(getByText('Monotone X')).toBeInTheDocument(); + expect(screen.getByText('Monotone X')).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith('curveMonotoneX'); }); }); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/DirectionFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/DirectionFilter.test.tsx index 05c071f1f9..cb660b5a25 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/DirectionFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/DirectionFilter.test.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { render, waitFor } from '@testing-library/react'; + +import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { Direction } from '../EntityRelationsGraph'; @@ -21,26 +22,26 @@ import { DirectionFilter } from './DirectionFilter'; describe('', () => { test('should display current value', () => { - const { getByText } = render( + render( {}} />, ); - expect(getByText('Left to right')).toBeInTheDocument(); + expect(screen.getByText('Left to right')).toBeInTheDocument(); }); test('should select direction', async () => { const onChange = jest.fn(); - const { getByText, getByTestId } = render( + render( , ); - expect(getByText('Right to left')).toBeInTheDocument(); + expect(screen.getByText('Right to left')).toBeInTheDocument(); - await userEvent.click(getByTestId('select')); - await userEvent.click(getByText('Top to bottom')); + await userEvent.click(screen.getByTestId('select')); + await userEvent.click(screen.getByText('Top to bottom')); await waitFor(() => { - expect(getByText('Top to bottom')).toBeInTheDocument(); + expect(screen.getByText('Top to bottom')).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith(Direction.TOP_BOTTOM); }); }); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx index 3f3a7f82a6..89f3169981 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.test.tsx @@ -13,64 +13,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { render, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; + +import { render, screen } from '@testing-library/react'; +import user from '@testing-library/user-event'; import React from 'react'; import { MaxDepthFilter } from './MaxDepthFilter'; describe('', () => { test('should display current value', () => { - const { getByLabelText } = render( - {}} />, - ); + render( {}} />); - expect(getByLabelText('maxp')).toBeInTheDocument(); - expect(getByLabelText('maxp')).toHaveValue(5); + expect(screen.getByLabelText('maxp')).toBeInTheDocument(); + expect(screen.getByLabelText('maxp')).toHaveValue(5); }); test('should display infinite if non finite', () => { - const { getByPlaceholderText, getByLabelText } = render( + render( {}} />, ); - expect(getByPlaceholderText(/Infinite/)).toBeInTheDocument(); - expect(getByLabelText('maxp')).toHaveValue(null); + expect(screen.getByPlaceholderText(/Infinite/)).toBeInTheDocument(); + expect(screen.getByLabelText('maxp')).toHaveValue(null); }); test('should clear max depth', async () => { const onChange = jest.fn(); - const { getByLabelText } = render( - , - ); + render(); - await userEvent.click(getByLabelText('clear max depth')); + expect(onChange).not.toHaveBeenCalled(); + await user.click(screen.getByLabelText('clear max depth')); expect(onChange).toHaveBeenCalledWith(Number.POSITIVE_INFINITY); }); test('should set max depth to undefined if below one', async () => { const onChange = jest.fn(); - const { getByLabelText } = render( - , - ); + render(); - await userEvent.clear(getByLabelText('maxp')); - await userEvent.type(getByLabelText('maxp'), '0'); + await user.clear(screen.getByLabelText('maxp')); + await user.type(screen.getByLabelText('maxp'), '0'); expect(onChange).toHaveBeenCalledWith(Number.POSITIVE_INFINITY); }); test('should select direction', async () => { - const onChange = jest.fn(); - const { getByLabelText } = render( - , + let value = 5; + render( + { + value = v; + }} + />, ); - expect(getByLabelText('maxp')).toHaveValue(5); + expect(screen.getByLabelText('maxp')).toHaveValue(5); + expect(value).toBe(5); - await userEvent.clear(getByLabelText('maxp')); - await userEvent.type(getByLabelText('maxp'), '10'); - waitFor(() => { - expect(onChange).toHaveBeenCalledWith(10); - }); + await user.clear(screen.getByLabelText('maxp')); + expect(value).toBe(Number.POSITIVE_INFINITY); + await user.type(screen.getByLabelText('maxp'), '10'); + expect(value).toBe(10); }); }); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx index 7828a60fb6..e6fb2fbab4 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx @@ -23,34 +23,56 @@ import { Typography, } from '@material-ui/core'; import ClearIcon from '@material-ui/icons/Clear'; -import React, { useCallback } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; export type Props = { value: number; onChange: (value: number) => void; }; -const useStyles = makeStyles({ - formControl: { - width: '100%', - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + width: '100%', + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphMaxDepthFilter' }, +); export const MaxDepthFilter = ({ value, onChange }: Props) => { const classes = useStyles(); + const onChangeRef = useRef(onChange); + const [currentValue, setCurrentValue] = useState(value); + // Keep a fresh reference to the latest callback + useEffect(() => { + onChangeRef.current = onChange; + }, [onChange]); + + // If the value changes externally, update ourselves + useEffect(() => { + setCurrentValue(value); + }, [value]); + + // When the entered text changes, update ourselves and communicate externally const handleChange = useCallback( (event: React.ChangeEvent) => { - const v = Number(event.target.value); - onChange(v <= 0 ? Number.POSITIVE_INFINITY : v); + const newValueNumeric = Number(event.target.value); + const newValue = + Number.isFinite(newValueNumeric) && newValueNumeric > 0 + ? newValueNumeric + : Number.POSITIVE_INFINITY; + setCurrentValue(newValue); + onChangeRef.current(newValue); }, - [onChange], + [], ); const reset = useCallback(() => { - onChange(Number.POSITIVE_INFINITY); - }, [onChange]); + setCurrentValue(Number.POSITIVE_INFINITY); + onChangeRef.current(Number.POSITIVE_INFINITY); + }, [onChangeRef]); return ( @@ -59,7 +81,7 @@ export const MaxDepthFilter = ({ value, onChange }: Props) => { diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx index 580c118b27..511592af0c 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.test.tsx @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { GetEntityFacetsResponse } from '@backstage/catalog-client'; import { ApiProvider } from '@backstage/core-app-api'; import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { SelectedKindsFilter } from './SelectedKindsFilter'; @@ -42,37 +43,37 @@ const apis = TestApiRegistry.from( describe('', () => { it('should not explode while loading', async () => { - const rendered = await renderWithEffects( + const { baseElement } = await renderWithEffects( {}} /> , ); - expect(rendered.baseElement).toBeInTheDocument(); + expect(baseElement).toBeInTheDocument(); }); it('should render current value', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( {}} /> , ); - expect(rendered.getByText('API')).toBeInTheDocument(); - expect(rendered.getByText('Component')).toBeInTheDocument(); + expect(screen.getByText('API')).toBeInTheDocument(); + expect(screen.getByText('Component')).toBeInTheDocument(); }); it('should select value', async () => { const onChange = jest.fn(); - const { getByLabelText, getByText } = await renderWithEffects( + await renderWithEffects( , ); - await userEvent.click(getByLabelText('Open')); - await waitFor(() => expect(getByText('System')).toBeInTheDocument()); + await userEvent.click(screen.getByLabelText('Open')); + await waitFor(() => expect(screen.getByText('System')).toBeInTheDocument()); - await userEvent.click(getByText('System')); + await userEvent.click(screen.getByText('System')); await waitFor(() => { expect(onChange).toHaveBeenCalledWith(['api', 'component', 'system']); @@ -81,7 +82,7 @@ describe('', () => { it('should return undefined if all values are selected', async () => { const onChange = jest.fn(); - const { getByLabelText, getByText } = await renderWithEffects( + await renderWithEffects( ', () => { /> , ); - await userEvent.click(getByLabelText('Open')); + await userEvent.click(screen.getByLabelText('Open')); - await waitFor(() => expect(getByText('Resource')).toBeInTheDocument()); + await waitFor(() => + expect(screen.getByText('Resource')).toBeInTheDocument(), + ); - await userEvent.click(getByText('Resource')); + await userEvent.click(screen.getByText('Resource')); await waitFor(() => { expect(onChange).toHaveBeenCalledWith(undefined); @@ -102,13 +105,13 @@ describe('', () => { it('should return all values when cleared', async () => { const onChange = jest.fn(); - const { getByRole } = await renderWithEffects( + await renderWithEffects( , ); - await userEvent.click(getByRole('combobox')); + await userEvent.click(screen.getByRole('combobox')); await userEvent.tab(); await waitFor(() => { diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx index 316f83da62..0817a01e0b 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx @@ -30,11 +30,14 @@ import { Autocomplete } from '@material-ui/lab'; import React, { useCallback, useEffect, useMemo } from 'react'; import useAsync from 'react-use/lib/useAsync'; -const useStyles = makeStyles({ - formControl: { - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSelectedKindsFilter' }, +); export type Props = { value: string[] | undefined; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx index bcc67edc3d..8baa7865b9 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.test.tsx @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RELATION_CHILD_OF, RELATION_HAS_MEMBER, RELATION_OWNED_BY, } from '@backstage/catalog-model'; -import { render, waitFor } from '@testing-library/react'; +import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { ALL_RELATION_PAIRS } from '../EntityRelationsGraph'; @@ -26,7 +27,7 @@ import { SelectedRelationsFilter } from './SelectedRelationsFilter'; describe('', () => { test('should render current value', () => { - const { getByText } = render( + render( ', () => { />, ); - expect(getByText(RELATION_OWNED_BY)).toBeInTheDocument(); - expect(getByText(RELATION_CHILD_OF)).toBeInTheDocument(); + expect(screen.getByText(RELATION_OWNED_BY)).toBeInTheDocument(); + expect(screen.getByText(RELATION_CHILD_OF)).toBeInTheDocument(); }); test('should select value', async () => { const onChange = jest.fn(); - const { getByText, getByLabelText } = render( + render( ', () => { />, ); - await userEvent.click(getByLabelText('Open')); + await userEvent.click(screen.getByLabelText('Open')); await waitFor(() => - expect(getByText(RELATION_HAS_MEMBER)).toBeInTheDocument(), + expect(screen.getByText(RELATION_HAS_MEMBER)).toBeInTheDocument(), ); - await userEvent.click(getByText(RELATION_HAS_MEMBER)); + await userEvent.click(screen.getByText(RELATION_HAS_MEMBER)); await waitFor(() => { expect(onChange).toHaveBeenCalledWith([ @@ -67,7 +68,7 @@ describe('', () => { test('should return undefined if all values are selected', async () => { const onChange = jest.fn(); - const { getByText, getByLabelText } = render( + render( p).filter( @@ -77,13 +78,13 @@ describe('', () => { />, ); - await userEvent.click(getByLabelText('Open')); + await userEvent.click(screen.getByLabelText('Open')); await waitFor(() => - expect(getByText(RELATION_HAS_MEMBER)).toBeInTheDocument(), + expect(screen.getByText(RELATION_HAS_MEMBER)).toBeInTheDocument(), ); - await userEvent.click(getByText(RELATION_HAS_MEMBER)); + await userEvent.click(screen.getByText(RELATION_HAS_MEMBER)); await waitFor(() => { expect(onChange).toHaveBeenCalledWith(undefined); @@ -92,7 +93,7 @@ describe('', () => { test('should return all values when cleared', async () => { const onChange = jest.fn(); - const { getByRole } = render( + render( ', () => { />, ); - await userEvent.click(getByRole('combobox')); + await userEvent.click(screen.getByRole('combobox')); await userEvent.tab(); await waitFor(() => { diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx index 839bfbe425..197f65cef8 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx @@ -28,11 +28,14 @@ import { Autocomplete } from '@material-ui/lab'; import React, { useCallback, useMemo } from 'react'; import { RelationPairs } from '../EntityRelationsGraph'; -const useStyles = makeStyles({ - formControl: { - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSelectedRelationsFilter' }, +); export type Props = { relationPairs: RelationPairs; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.test.tsx index 08c7304989..322232d774 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.test.tsx @@ -13,31 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { render } from '@testing-library/react'; + +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { SwitchFilter } from './SwitchFilter'; describe('', () => { test('should render value', () => { - const { getByLabelText } = render( - {}} />, - ); + render( {}} />); - expect(getByLabelText('My label')).toBeInTheDocument(); - expect(getByLabelText('My label')).not.toBeChecked(); + expect(screen.getByLabelText('My label')).toBeInTheDocument(); + expect(screen.getByLabelText('My label')).not.toBeChecked(); }); test('should toggle value', async () => { const onChange = jest.fn(); - const { getByLabelText } = render( - , - ); + render(); - expect(getByLabelText('My label')).toBeInTheDocument(); - expect(getByLabelText('My label')).toBeChecked(); + expect(screen.getByLabelText('My label')).toBeInTheDocument(); + expect(screen.getByLabelText('My label')).toBeChecked(); - await userEvent.click(getByLabelText('My label')); + await userEvent.click(screen.getByLabelText('My label')); expect(onChange).toHaveBeenCalledWith(false); }); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx index 214080db6e..495f6b4db2 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx @@ -22,12 +22,15 @@ export type Props = { onChange: (value: boolean) => void; }; -const useStyles = makeStyles({ - root: { - width: '100%', - maxWidth: 300, +const useStyles = makeStyles( + { + root: { + width: '100%', + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSwitchFilter' }, +); export const SwitchFilter = ({ label, value, onChange }: Props) => { const classes = useStyles(); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx index 5b8f50b983..ab280aea81 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx @@ -13,17 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { RELATION_CHILD_OF, RELATION_PARENT_OF, } from '@backstage/catalog-model'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { CustomLabel } from './CustomLabel'; describe('', () => { test('renders label', () => { - const { getByText } = render( + render( ', () => { , ); - expect(getByText(RELATION_PARENT_OF)).toBeInTheDocument(); + expect(screen.getByText(RELATION_PARENT_OF)).toBeInTheDocument(); }); test('renders label with multiple relations', () => { - const { getByText } = render( + render( ', () => { , ); - expect(getByText(RELATION_PARENT_OF)).toBeInTheDocument(); - expect(getByText(RELATION_CHILD_OF)).toBeInTheDocument(); + expect(screen.getByText(RELATION_PARENT_OF)).toBeInTheDocument(); + expect(screen.getByText(RELATION_CHILD_OF)).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx index 60a858eee6..19082cfe81 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx @@ -20,14 +20,17 @@ import React from 'react'; import { EntityEdgeData } from './types'; import classNames from 'classnames'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ - text: { - fill: theme.palette.textContrast, - }, - secondary: { - fill: theme.palette.textSubtle, - }, -})); +const useStyles = makeStyles( + (theme: BackstageTheme) => ({ + text: { + fill: theme.palette.textContrast, + }, + secondary: { + fill: theme.palette.textSubtle, + }, + }), + { name: 'PluginCatalogGraphCustomLabel' }, +); export function CustomLabel({ edge: { relations }, diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx index ff9fc9377e..7a34bbf688 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { CustomNode } from './CustomNode'; import userEvent from '@testing-library/user-event'; describe('', () => { test('renders node', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(getByText('kind:namespace/name')).toBeInTheDocument(); + expect(screen.getByText('kind:namespace/name')).toBeInTheDocument(); }); test('renders node, skips default namespace', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(getByText('kind:name')).toBeInTheDocument(); + expect(screen.getByText('kind:name')).toBeInTheDocument(); }); test('renders node with onClick', async () => { const onClick = jest.fn(); - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(getByText('kind:namespace/name')).toBeInTheDocument(); - await userEvent.click(getByText('kind:namespace/name')); + expect(screen.getByText('kind:namespace/name')).toBeInTheDocument(); + await userEvent.click(screen.getByText('kind:namespace/name')); expect(onClick).toHaveBeenCalledTimes(1); }); test('renders title if entity has one', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(getByText('Custom Title')).toBeInTheDocument(); + expect(screen.getByText('Custom Title')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx index ae541fa997..edcdb97fcb 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx @@ -22,37 +22,40 @@ import React, { useLayoutEffect, useRef, useState } from 'react'; import { EntityKindIcon } from './EntityKindIcon'; import { EntityNodeData } from './types'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ - node: { - fill: theme.palette.grey[300], - stroke: theme.palette.grey[300], +const useStyles = makeStyles( + (theme: BackstageTheme) => ({ + node: { + fill: theme.palette.grey[300], + stroke: theme.palette.grey[300], - '&.primary': { - fill: theme.palette.primary.light, - stroke: theme.palette.primary.light, + '&.primary': { + fill: theme.palette.primary.light, + stroke: theme.palette.primary.light, + }, + '&.secondary': { + fill: theme.palette.secondary.light, + stroke: theme.palette.secondary.light, + }, }, - '&.secondary': { - fill: theme.palette.secondary.light, - stroke: theme.palette.secondary.light, - }, - }, - text: { - fill: theme.palette.getContrastText(theme.palette.grey[300]), + text: { + fill: theme.palette.getContrastText(theme.palette.grey[300]), - '&.primary': { - fill: theme.palette.primary.contrastText, + '&.primary': { + fill: theme.palette.primary.contrastText, + }, + '&.secondary': { + fill: theme.palette.secondary.contrastText, + }, + '&.focused': { + fontWeight: 'bold', + }, }, - '&.secondary': { - fill: theme.palette.secondary.contrastText, + clickable: { + cursor: 'pointer', }, - '&.focused': { - fontWeight: 'bold', - }, - }, - clickable: { - cursor: 'pointer', - }, -})); + }), + { name: 'PluginCatalogGraphCustomNode' }, +); export function CustomNode({ node: { diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx index 5d5f9dbf3c..6592c6195e 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityKindIcon.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { renderInTestApp } from '@backstage/test-utils'; import React from 'react'; import { EntityKindIcon } from './EntityKindIcon'; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx index c79f975789..8a3352abb4 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.test.tsx @@ -22,106 +22,105 @@ import { RELATION_PART_OF, } from '@backstage/catalog-model'; import { DependencyGraphTypes } from '@backstage/core-components'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { FunctionComponent } from 'react'; import { EntityRelationsGraph } from './EntityRelationsGraph'; describe('', () => { let Wrapper: FunctionComponent; - let catalog: jest.Mocked; + const entities: { [ref: string]: Entity } = { + 'b:d/c': { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c', + namespace: 'd', + }, + relations: [ + { + targetRef: 'k:d/a1', + type: RELATION_OWNER_OF, + }, + { + targetRef: 'b:d/c1', + type: RELATION_HAS_PART, + }, + ], + }, + 'k:d/a1': { + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'a1', + namespace: 'd', + }, + relations: [ + { + targetRef: 'b:d/c', + type: RELATION_OWNED_BY, + }, + { + targetRef: 'b:d/c1', + type: RELATION_OWNED_BY, + }, + ], + }, + 'b:d/c1': { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c1', + namespace: 'd', + }, + relations: [ + { + targetRef: 'b:d/c', + type: RELATION_PART_OF, + }, + { + targetRef: 'k:d/a1', + type: RELATION_OWNER_OF, + }, + { + targetRef: 'b:d/c2', + type: RELATION_HAS_PART, + }, + ], + }, + 'b:d/c2': { + apiVersion: 'a', + kind: 'b', + metadata: { + name: 'c2', + namespace: 'd', + }, + relations: [ + { + targetRef: 'b:d/c1', + type: RELATION_PART_OF, + }, + ], + }, + }; + const catalog = { + getEntities: jest.fn(), + getEntityByRef: jest.fn(), + removeEntityByUid: jest.fn(), + getLocationById: jest.fn(), + getLocationByRef: jest.fn(), + addLocation: jest.fn(), + removeLocationById: jest.fn(), + refreshEntity: jest.fn(), + getEntityAncestors: jest.fn(), + getEntityFacets: jest.fn(), + validateEntity: jest.fn(), + }; const CUSTOM_TEST_ID = 'custom-test-id'; beforeEach(() => { - const entities: { [ref: string]: Entity } = { - 'b:d/c': { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c', - namespace: 'd', - }, - relations: [ - { - targetRef: 'k:d/a1', - type: RELATION_OWNER_OF, - }, - { - targetRef: 'b:d/c1', - type: RELATION_HAS_PART, - }, - ], - }, - 'k:d/a1': { - apiVersion: 'a', - kind: 'k', - metadata: { - name: 'a1', - namespace: 'd', - }, - relations: [ - { - targetRef: 'b:d/c', - type: RELATION_OWNED_BY, - }, - { - targetRef: 'b:d/c1', - type: RELATION_OWNED_BY, - }, - ], - }, - 'b:d/c1': { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c1', - namespace: 'd', - }, - relations: [ - { - targetRef: 'b:d/c', - type: RELATION_PART_OF, - }, - { - targetRef: 'k:d/a1', - type: RELATION_OWNER_OF, - }, - { - targetRef: 'b:d/c2', - type: RELATION_HAS_PART, - }, - ], - }, - 'b:d/c2': { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'c2', - namespace: 'd', - }, - relations: [ - { - targetRef: 'b:d/c1', - type: RELATION_PART_OF, - }, - ], - }, - }; - catalog = { - getEntities: jest.fn(), - getEntityByRef: jest.fn(async n => entities[n as string]), - removeEntityByUid: jest.fn(), - getLocationById: jest.fn(), - getLocationByRef: jest.fn(), - addLocation: jest.fn(), - removeLocationById: jest.fn(), - refreshEntity: jest.fn(), - getEntityAncestors: jest.fn(), - getEntityFacets: jest.fn(), - validateEntity: jest.fn(), - }; - Wrapper = ({ children }) => ( {children} @@ -129,7 +128,7 @@ describe('', () => { ); }); - afterAll(() => { + afterEach(() => { jest.resetAllMocks(); }); @@ -144,7 +143,7 @@ describe('', () => { relations: [], }); - const { findByText, findAllByTestId } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(1); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(1); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(1); }); test('renders a progress indicator while loading', async () => { catalog.getEntityByRef.mockImplementation(() => new Promise(() => {})); - const { findByRole } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(await findByRole('progressbar')).toBeInTheDocument(); + expect(await screen.findByRole('progressbar')).toBeInTheDocument(); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(1); }); @@ -199,7 +198,7 @@ describe('', () => { return undefined; }); - const { findByText, findAllByTestId } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(1); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(1); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(2); }); test('renders at max depth of one', async () => { - const { findByText, findAllByTestId, findAllByText } = - await renderInTestApp( - - - , - ); + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/c1')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(3); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(1); - expect(await findAllByText('hasPart')).toHaveLength(1); - expect(await findAllByTestId('label')).toHaveLength(2); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c1')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(3); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(1); + expect(await screen.findAllByText('hasPart')).toHaveLength(1); + expect(await screen.findAllByTestId('label')).toHaveLength(2); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(3); }); - test('renders simplied graph at full depth', async () => { - const { findByText, findAllByText, findAllByTestId } = - await renderInTestApp( - - - , - ); + test('renders simplified graph at full depth', async () => { + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/c1')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findByText('b:d/c2')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(4); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(1); - expect(await findAllByText('hasPart')).toHaveLength(2); - expect(await findAllByTestId('label')).toHaveLength(3); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c1')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c2')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(4); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(1); + expect(await screen.findAllByText('hasPart')).toHaveLength(2); + expect(await screen.findAllByTestId('label')).toHaveLength(3); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(4); }); test('renders full graph at full depth', async () => { - const { findAllByText, findByText, findAllByTestId } = - await renderInTestApp( - - - , - ); + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/c1')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findByText('b:d/c2')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(4); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(2); - expect(await findAllByText('ownedBy')).toHaveLength(2); - expect(await findAllByText('hasPart')).toHaveLength(2); - expect(await findAllByText('partOf')).toHaveLength(2); - expect(await findAllByTestId('label')).toHaveLength(8); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c1')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c2')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(4); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(2); + expect(await screen.findAllByText('ownedBy')).toHaveLength(2); + expect(await screen.findAllByText('hasPart')).toHaveLength(2); + expect(await screen.findAllByText('partOf')).toHaveLength(2); + expect(await screen.findAllByTestId('label')).toHaveLength(8); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(4); }); test('renders full graph at full depth with merged relations', async () => { - const { findAllByText, findByText, findAllByTestId } = - await renderInTestApp( - - - , - ); + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/c1')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findByText('b:d/c2')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(4); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(2); - expect(await findAllByText('hasPart')).toHaveLength(2); - expect(await findAllByTestId('label')).toHaveLength(4); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c1')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c2')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(4); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(2); + expect(await screen.findAllByText('hasPart')).toHaveLength(2); + expect(await screen.findAllByTestId('label')).toHaveLength(4); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(4); }); test('renders a graph with multiple root nodes', async () => { - const { findAllByText, findByText, findAllByTestId } = - await renderInTestApp( - - - , - ); + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('b:d/c1')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findByText('b:d/c2')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(4); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(1); - expect(await findAllByText('partOf')).toHaveLength(2); - expect(await findAllByTestId('label')).toHaveLength(3); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c1')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findByText('b:d/c2')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(4); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(1); + expect(await screen.findAllByText('partOf')).toHaveLength(2); + expect(await screen.findAllByTestId('label')).toHaveLength(3); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(4); }); test('renders a graph with filtered kinds and relations', async () => { - const { findAllByText, findByText, findAllByTestId } = - await renderInTestApp( - - - , - ); + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); - expect(await findByText('b:d/c')).toBeInTheDocument(); - expect(await findByText('k:d/a1')).toBeInTheDocument(); - expect(await findAllByTestId('node')).toHaveLength(2); + await renderInTestApp( + + + , + ); - expect(await findAllByText('ownerOf')).toHaveLength(1); - expect(await findAllByTestId('label')).toHaveLength(1); + expect(await screen.findByText('b:d/c')).toBeInTheDocument(); + expect(await screen.findByText('k:d/a1')).toBeInTheDocument(); + expect(await screen.findAllByTestId('node')).toHaveLength(2); + + expect(await screen.findAllByText('ownerOf')).toHaveLength(1); + expect(await screen.findAllByTestId('label')).toHaveLength(1); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(2); }); test('handle clicks on a node', async () => { + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); + const onNodeClick = jest.fn(); - const { findByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - await userEvent.click(await findByText('k:d/a1')); + await userEvent.click(await screen.findByText('k:d/a1')); expect(onNodeClick).toHaveBeenCalledTimes(1); }); test('render custom node', async () => { + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); + const renderNode = (props: DependencyGraphTypes.RenderNodeProps) => ( {props.node.id} @@ -383,7 +392,7 @@ describe('', () => { ); - const { findAllByTestId, container } = await renderInTestApp( + const { container } = await renderInTestApp( ', () => { , ); - const node = await findAllByTestId(CUSTOM_TEST_ID); + const node = await screen.findAllByTestId(CUSTOM_TEST_ID); expect(node[0]).toBeInTheDocument(); expect(container.querySelector('circle')).toBeInTheDocument(); }); test('render custom label', async () => { + catalog.getEntityByRef.mockImplementation(async n => entities[n as string]); + const renderLabel = (props: DependencyGraphTypes.RenderLabelProps) => ( {`Test-Label${props.edge.label}`} @@ -405,7 +416,7 @@ describe('', () => { ); - const { findAllByTestId, findAllByText, container } = await renderInTestApp( + const { container } = await renderInTestApp( ', () => { /> , ); - const node = await findAllByTestId(CUSTOM_TEST_ID); + const node = await screen.findAllByTestId(CUSTOM_TEST_ID); expect(node[0]).toBeInTheDocument(); expect(container.querySelector('circle')).toBeInTheDocument(); - const labels = await findAllByText('Test-Labelvisible'); + const labels = await screen.findAllByText('Test-Labelvisible'); expect(labels[0]).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx index c0e2f610c1..72ec4b4aed 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx @@ -32,36 +32,39 @@ import { ALL_RELATION_PAIRS, RelationPairs } from './relations'; import { Direction, EntityEdge, EntityNode } from './types'; import { useEntityRelationNodesAndEdges } from './useEntityRelationNodesAndEdges'; -const useStyles = makeStyles(theme => ({ - progress: { - position: 'absolute', - left: '50%', - top: '50%', - marginLeft: '-20px', - marginTop: '-20px', - }, - container: { - position: 'relative', - width: '100%', - display: 'flex', - flexDirection: 'column', - }, - graph: { - width: '100%', - flex: 1, - // Right now there is no good way to style edges between nodes, we have to - // fallback to these hacks: - '& path[marker-end]': { - transition: 'filter 0.1s ease-in-out', +const useStyles = makeStyles( + theme => ({ + progress: { + position: 'absolute', + left: '50%', + top: '50%', + marginLeft: '-20px', + marginTop: '-20px', }, - '& path[marker-end]:hover': { - filter: `drop-shadow(2px 2px 4px ${theme.palette.primary.dark});`, + container: { + position: 'relative', + width: '100%', + display: 'flex', + flexDirection: 'column', }, - '& g[data-testid=label]': { - transition: 'transform 0s', + graph: { + width: '100%', + flex: 1, + // Right now there is no good way to style edges between nodes, we have to + // fallback to these hacks: + '& path[marker-end]': { + transition: 'filter 0.1s ease-in-out', + }, + '& path[marker-end]:hover': { + filter: `drop-shadow(2px 2px 4px ${theme.palette.primary.dark});`, + }, + '& g[data-testid=label]': { + transition: 'transform 0s', + }, }, - }, -})); + }), + { name: 'PluginCatalogGraphEntityRelationsGraph' }, +); /** * Core building block for custom entity relations diagrams. diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts index e76b1001c6..802f993802 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Entity } from '@backstage/catalog-model'; import { useApi as useApiMocked } from '@backstage/core-plugin-api'; -import { CatalogApi } from '@backstage/plugin-catalog-react'; import { act, renderHook } from '@testing-library/react-hooks'; import { useEntityStore } from './useEntityStore'; @@ -24,23 +24,21 @@ jest.mock('@backstage/core-plugin-api'); const useApi = useApiMocked as jest.Mocked; describe('useEntityStore', () => { - let catalogApi: jest.Mocked; + const catalogApi = { + getEntities: jest.fn(), + getEntityByRef: jest.fn(), + removeEntityByUid: jest.fn(), + getLocationById: jest.fn(), + getLocationByRef: jest.fn(), + addLocation: jest.fn(), + removeLocationById: jest.fn(), + refreshEntity: jest.fn(), + getEntityAncestors: jest.fn(), + getEntityFacets: jest.fn(), + validateEntity: jest.fn(), + }; beforeEach(() => { - catalogApi = { - getEntities: jest.fn(), - getEntityByRef: jest.fn(), - removeEntityByUid: jest.fn(), - getLocationById: jest.fn(), - getLocationByRef: jest.fn(), - addLocation: jest.fn(), - removeLocationById: jest.fn(), - refreshEntity: jest.fn(), - getEntityAncestors: jest.fn(), - getEntityFacets: jest.fn(), - validateEntity: jest.fn(), - }; - useApi.mockReturnValue(catalogApi); }); diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 97b2a49835..8f62b9f528 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-graphql +## 0.3.15 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + ## 0.3.15-next.0 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 503c7eb3b0..68bdf28a7d 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "An experimental Backstage catalog GraphQL module", - "version": "0.3.15-next.0", + "version": "0.3.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,7 +53,7 @@ "@graphql-codegen/typescript": "^2.4.2", "@graphql-codegen/typescript-resolvers": "^2.4.3", "@graphql-tools/schema": "^9.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/catalog-import/.eslintrc.js b/plugins/catalog-import/.eslintrc.js index e2a53a6ad2..45bb6db521 100644 --- a/plugins/catalog-import/.eslintrc.js +++ b/plugins/catalog-import/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + 'testing-library/prefer-screen-queries': 'error', + }, +}); diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 8562b77510..2f3bd8b9bf 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-catalog-import +## 0.9.1 + +### Patch Changes + +- 1e7b640518: Get rid of `this-is-undefined-in-esm` warning +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/integration-react@1.1.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + +## 0.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.9.1-next.0 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index b8cacc4450..ee6a3925bb 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.9.1-next.0", + "version": "0.9.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -68,7 +68,7 @@ "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index d507ac3bef..e77abc8a85 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -49,7 +49,7 @@ jest.mock('@octokit/rest', () => { import { ConfigReader, UrlPatternDiscovery } from '@backstage/core-app-api'; import { ScmIntegrations } from '@backstage/integration'; import { ScmAuthApi } from '@backstage/integration-react'; -import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { CatalogApi } from '@backstage/plugin-catalog-react'; import { setupRequestMockHandlers } from '@backstage/test-utils'; import { Octokit } from '@octokit/rest'; import { rest } from 'msw'; @@ -89,7 +89,7 @@ describe('CatalogImportClient', () => { }), ); - const catalogApi: jest.Mocked = { + const catalogApi = { getEntities: jest.fn(), addLocation: jest.fn(), removeLocationById: jest.fn(), @@ -111,7 +111,7 @@ describe('CatalogImportClient', () => { scmAuthApi, scmIntegrationsApi, identityApi, - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, configApi: new ConfigReader({ app: { baseUrl: 'https://demo.backstage.io/', @@ -458,7 +458,7 @@ describe('CatalogImportClient', () => { scmAuthApi, scmIntegrationsApi, identityApi, - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, configApi: new ConfigReader({ catalog: { import: { @@ -610,7 +610,7 @@ describe('CatalogImportClient', () => { scmAuthApi, scmIntegrationsApi, identityApi, - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, configApi: new ConfigReader({ catalog: { import: { @@ -680,7 +680,7 @@ describe('CatalogImportClient', () => { scmAuthApi, scmIntegrationsApi, identityApi, - catalogApi, + catalogApi: catalogApi as Partial as CatalogApi, configApi: new ConfigReader({ catalog: { import: { diff --git a/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx b/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx index d6132b249e..a231563484 100644 --- a/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx +++ b/plugins/catalog-import/src/components/DefaultImportPage/DefaultImportPage.test.tsx @@ -19,6 +19,7 @@ import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; import { configApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { catalogImportApiRef, CatalogImportClient } from '../../api'; import { DefaultImportPage } from './DefaultImportPage'; @@ -65,14 +66,14 @@ describe('', () => { }); it('renders without exploding', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( , ); expect( - getByText('Start tracking your component in Backstage'), + screen.getByText('Start tracking your component in Backstage'), ).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.test.tsx b/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.test.tsx index 9a27532c57..c33de77ffd 100644 --- a/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.test.tsx +++ b/plugins/catalog-import/src/components/ImportInfoCard/ImportInfoCard.test.tsx @@ -21,6 +21,7 @@ import { TestApiProvider, TestApiRegistry, } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { CatalogImportApi, catalogImportApiRef } from '../../api'; import { ImportInfoCard } from './ImportInfoCard'; @@ -49,7 +50,7 @@ describe('', () => { }); it('renders without exploding', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { , ); - expect(getByText('Register an existing component')).toBeInTheDocument(); + expect( + screen.getByText('Register an existing component'), + ).toBeInTheDocument(); }); it('renders section on GitHub discovery if supported', async () => { catalogImportApi.preparePullRequest = async () => ({ title: '', body: '' }); - const { getByText } = await renderInTestApp( + await renderInTestApp( , ); - expect(getByText(/The wizard discovers all/)).toBeInTheDocument(); + expect(screen.getByText(/The wizard discovers all/)).toBeInTheDocument(); }); it('renders section on pull requests if supported', async () => { catalogImportApi.preparePullRequest = async () => ({ title: '', body: '' }); - const { getByText } = await renderInTestApp( + await renderInTestApp( , ); expect( - getByText(/the wizard will prepare a Pull Request/), + screen.getByText(/the wizard will prepare a Pull Request/), ).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx b/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx index 498e786eb3..a38b801607 100644 --- a/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx +++ b/plugins/catalog-import/src/components/ImportPage/ImportPage.test.tsx @@ -19,6 +19,7 @@ import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; import { configApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { useOutlet } from 'react-router'; import { catalogImportApiRef, CatalogImportClient } from '../../api'; @@ -71,26 +72,26 @@ describe('', () => { afterEach(() => jest.resetAllMocks()); it('renders without exploding', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( , ); expect( - getByText('Start tracking your component in Backstage'), + screen.getByText('Start tracking your component in Backstage'), ).toBeInTheDocument(); }); it('renders with custom children', async () => { (useOutlet as jest.Mock).mockReturnValue(
Hello World
); - const { getByText } = await renderInTestApp( + await renderInTestApp( , ); - expect(getByText('Hello World')).toBeInTheDocument(); + expect(screen.getByText('Hello World')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx index 5a8110eb6c..a9d662cab0 100644 --- a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx +++ b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx @@ -16,7 +16,7 @@ import { errorApiRef } from '@backstage/core-plugin-api'; import { TestApiProvider } from '@backstage/test-utils'; -import { act, render } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { AnalyzeResult, catalogImportApiRef } from '../../api/'; @@ -60,19 +60,20 @@ describe('', () => { }); it('renders without exploding', async () => { - const { getByRole } = render( - undefined} />, - { - wrapper: Wrapper, - }, - ); + render( undefined} />, { + wrapper: Wrapper, + }); - expect(getByRole('textbox', { name: /Repository/i })).toBeInTheDocument(); - expect(getByRole('textbox', { name: /Repository/i })).toHaveValue(''); + expect( + screen.getByRole('textbox', { name: /Repository/i }), + ).toBeInTheDocument(); + expect(screen.getByRole('textbox', { name: /Repository/i })).toHaveValue( + '', + ); }); it('should use default analysis url', async () => { - const { getByRole } = render( + render( undefined} analysisUrl="https://default" @@ -82,8 +83,10 @@ describe('', () => { }, ); - expect(getByRole('textbox', { name: /Repository/i })).toBeInTheDocument(); - expect(getByRole('textbox', { name: /Repository/i })).toHaveValue( + expect( + screen.getByRole('textbox', { name: /Repository/i }), + ).toBeInTheDocument(); + expect(screen.getByRole('textbox', { name: /Repository/i })).toHaveValue( 'https://default', ); }); @@ -91,16 +94,13 @@ describe('', () => { it('should not analyze without url', async () => { const onAnalysisFn = jest.fn(); - const { getByRole } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); await act(async () => { try { - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); } catch { return; } @@ -114,26 +114,23 @@ describe('', () => { it('should not analyze invalid value', async () => { const onAnalysisFn = jest.fn(); - const { getByRole, getByText } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'http:/', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(catalogImportApi.analyzeUrl).toHaveBeenCalledTimes(0); expect(onAnalysisFn).toHaveBeenCalledTimes(0); expect(errorApi.post).toHaveBeenCalledTimes(0); expect( - getByText('Must start with http:// or https://.'), + screen.getByText('Must start with http:// or https://.'), ).toBeInTheDocument(); }); @@ -145,12 +142,9 @@ describe('', () => { locations: [location], } as AnalyzeResult; - const { getByRole } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve(analyzeResult), @@ -158,10 +152,10 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(1); @@ -182,12 +176,9 @@ describe('', () => { locations: [location, location], } as AnalyzeResult; - const { getByRole } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve(analyzeResult), @@ -195,10 +186,10 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-1', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(1); @@ -218,12 +209,9 @@ describe('', () => { locations: [], } as AnalyzeResult; - const { getByRole, getByText } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve(analyzeResult), @@ -231,15 +219,15 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-1', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(0); expect( - getByText('There are no entities at this location'), + screen.getByText('There are no entities at this location'), ).toBeInTheDocument(); expect(errorApi.post).toHaveBeenCalledTimes(0); }); @@ -262,12 +250,9 @@ describe('', () => { ], } as AnalyzeResult; - const { getByRole } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve(analyzeResult), @@ -275,10 +260,10 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-2', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(1); @@ -300,12 +285,9 @@ describe('', () => { generatedEntities: [], } as AnalyzeResult; - const { getByRole, getByText } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve(analyzeResult), @@ -313,15 +295,15 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-2', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(0); expect( - getByText("Couldn't generate entities for your repository"), + screen.getByText("Couldn't generate entities for your repository"), ).toBeInTheDocument(); expect(errorApi.post).toHaveBeenCalledTimes(0); }); @@ -344,7 +326,7 @@ describe('', () => { ], } as AnalyzeResult; - const { getByRole, getByText } = render( + render( , { wrapper: Wrapper, @@ -357,15 +339,15 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-2', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(0); expect( - getByText("Couldn't generate entities for your repository"), + screen.getByText("Couldn't generate entities for your repository"), ).toBeInTheDocument(); expect(errorApi.post).toHaveBeenCalledTimes(0); }); @@ -373,12 +355,9 @@ describe('', () => { it('should report unknown type to the errorapi', async () => { const onAnalysisFn = jest.fn(); - const { getByRole, getByText } = render( - , - { - wrapper: Wrapper, - }, - ); + render(, { + wrapper: Wrapper, + }); catalogImportApi.analyzeUrl.mockReturnValueOnce( Promise.resolve({ type: 'unknown' } as any as AnalyzeResult), @@ -386,15 +365,15 @@ describe('', () => { await act(async () => { await userEvent.type( - getByRole('textbox', { name: /Repository/i }), + screen.getByRole('textbox', { name: /Repository/i }), 'https://my-repository-2', ); - await userEvent.click(getByRole('button', { name: /Analyze/i })); + await userEvent.click(screen.getByRole('button', { name: /Analyze/i })); }); expect(onAnalysisFn).toHaveBeenCalledTimes(0); expect( - getByText( + screen.getByText( 'Received unknown analysis result of type unknown. Please contact the support team.', ), ).toBeInTheDocument(); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx index 3acb7390a9..02b67090fa 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreparePullRequestForm.test.tsx @@ -15,7 +15,7 @@ */ import { FormHelperText, TextField } from '@material-ui/core'; -import { act, render } from '@testing-library/react'; +import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { asInputRef } from '../helpers'; @@ -25,7 +25,7 @@ describe('', () => { it('renders without exploding', async () => { const onSubmitFn = jest.fn(); - const { getByRole } = render( + render( defaultValues={{ main: 'default' }} render={({ register }) => ( @@ -39,7 +39,7 @@ describe('', () => { ); await act(async () => { - await userEvent.click(getByRole('button', { name: /submit/i })); + await userEvent.click(screen.getByRole('button', { name: /submit/i })); }); expect(onSubmitFn).toHaveBeenCalledTimes(1); @@ -49,7 +49,7 @@ describe('', () => { it('should register a text field', async () => { const onSubmitFn = jest.fn(); - const { getByRole, getByLabelText } = render( + render( defaultValues={{ main: 'default' }} render={({ register }) => ( @@ -67,9 +67,9 @@ describe('', () => { ); await act(async () => { - await userEvent.clear(getByLabelText('Main Field')); - await userEvent.type(getByLabelText('Main Field'), 'My Text'); - await userEvent.click(getByRole('button', { name: /submit/i })); + await userEvent.clear(screen.getByLabelText('Main Field')); + await userEvent.type(screen.getByLabelText('Main Field'), 'My Text'); + await userEvent.click(screen.getByRole('button', { name: /submit/i })); }); expect(onSubmitFn).toHaveBeenCalledTimes(1); @@ -79,7 +79,7 @@ describe('', () => { it('registers required attribute', async () => { const onSubmitFn = jest.fn(); - const { queryByText, getByRole } = render( + render( defaultValues={{}} render={({ formState, register }) => ( @@ -100,13 +100,17 @@ describe('', () => { />, ); - expect(queryByText('Error in required main field')).not.toBeInTheDocument(); + expect( + screen.queryByText('Error in required main field'), + ).not.toBeInTheDocument(); await act(async () => { - await userEvent.click(getByRole('button', { name: /submit/i })); + await userEvent.click(screen.getByRole('button', { name: /submit/i })); }); expect(onSubmitFn).not.toHaveBeenCalled(); - expect(queryByText('Error in required main field')).toBeInTheDocument(); + expect( + screen.queryByText('Error in required main field'), + ).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx index 8d0d085b8a..d983b6d359 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx @@ -15,7 +15,7 @@ */ import { makeStyles } from '@material-ui/core'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; import React from 'react'; import { PreviewPullRequestComponent } from './PreviewPullRequestComponent'; @@ -28,15 +28,15 @@ const useStyles = makeStyles({ describe('', () => { it('renders without exploding', async () => { - const { getByText } = render( + render( , ); - const title = getByText('My Title'); - const description = getByText('description', { selector: 'strong' }); + const title = screen.getByText('My Title'); + const description = screen.getByText('description', { selector: 'strong' }); expect(title).toBeInTheDocument(); expect(title).toBeVisible(); expect(description).toBeInTheDocument(); @@ -46,7 +46,7 @@ describe('', () => { it('renders card with custom styles', async () => { const { result } = renderHook(() => useStyles()); - const { getByText } = render( + render( ', () => { />, ); - const title = getByText('My Title'); - const description = getByText('description', { selector: 'strong' }); + const title = screen.getByText('My Title'); + const description = screen.getByText('description', { selector: 'strong' }); expect(title).toBeInTheDocument(); expect(title).not.toBeVisible(); expect(description).toBeInTheDocument(); @@ -65,7 +65,7 @@ describe('', () => { it('renders with custom styles', async () => { const { result } = renderHook(() => useStyles()); - const { getByText } = render( + render( ', () => { />, ); - const title = getByText('My Title'); - const description = getByText('description', { selector: 'strong' }); + const title = screen.getByText('My Title'); + const description = screen.getByText('description', { selector: 'strong' }); expect(title).toBeInTheDocument(); expect(title).toBeVisible(); expect(description).toBeInTheDocument(); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx index 5ad7e27c4b..36f1217c37 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx @@ -35,7 +35,7 @@ describe('', () => { preparePullRequest: jest.fn(), }; - const catalogApi: jest.Mocked = { + const catalogApi = { getEntities: jest.fn(), addLocation: jest.fn(), getEntityByRef: jest.fn(), @@ -102,7 +102,7 @@ describe('', () => { catalogApi.getEntities.mockReturnValue(Promise.resolve({ items: [] })); await act(async () => { - const { findByText } = render( + render( ', () => { }, ); - const title = await findByText('My title'); - const description = await findByText('body', { selector: 'strong' }); + const title = await screen.findByText('My title'); + const description = await screen.findByText('body', { + selector: 'strong', + }); expect(title).toBeInTheDocument(); expect(title).toBeVisible(); expect(description).toBeInTheDocument(); diff --git a/plugins/catalog-import/src/components/StepPrepareSelectLocations/StepPrepareSelectLocations.test.tsx b/plugins/catalog-import/src/components/StepPrepareSelectLocations/StepPrepareSelectLocations.test.tsx index 1817ece1b8..5a30c7735a 100644 --- a/plugins/catalog-import/src/components/StepPrepareSelectLocations/StepPrepareSelectLocations.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareSelectLocations/StepPrepareSelectLocations.test.tsx @@ -15,7 +15,7 @@ */ import { renderInTestApp } from '@backstage/test-utils'; -import { act } from '@testing-library/react'; +import { act, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { AnalyzeResult } from '../../api'; @@ -58,7 +58,7 @@ describe('', () => { }); it('renders display locations to be added', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( undefined} @@ -66,15 +66,15 @@ describe('', () => { />, ); - expect(rendered.getByText('url-1')).toBeInTheDocument(); - expect(rendered.getByText('url-2')).toBeInTheDocument(); + expect(screen.getByText('url-1')).toBeInTheDocument(); + expect(screen.getByText('url-2')).toBeInTheDocument(); expect( - rendered.queryByText(/Select one or more locations/), + screen.queryByText(/Select one or more locations/), ).toBeInTheDocument(); expect( - rendered.queryByText(/locations already exist/), + screen.queryByText(/locations already exist/), ).not.toBeInTheDocument(); - expect(rendered.getByRole('button', { name: /Review/i })).toBeDisabled(); + expect(screen.getByRole('button', { name: /Review/i })).toBeDisabled(); }); it('should display existing locations only', async () => { @@ -95,7 +95,7 @@ describe('', () => { ], } as Extract; - const rendered = await renderInTestApp( + await renderInTestApp( undefined} @@ -103,15 +103,15 @@ describe('', () => { />, ); - expect(rendered.getByText(/my-target/)).toBeInTheDocument(); - expect(rendered.queryByText(/locations already exist/)).toBeInTheDocument(); + expect(screen.getByText(/my-target/)).toBeInTheDocument(); + expect(screen.queryByText(/locations already exist/)).toBeInTheDocument(); expect( - rendered.queryByText(/Select one or more locations/), + screen.queryByText(/Select one or more locations/), ).not.toBeInTheDocument(); }); it('should select and deselect all', async () => { - const { getByRole, getAllByRole } = await renderInTestApp( + await renderInTestApp( undefined} @@ -119,27 +119,31 @@ describe('', () => { />, ); - const checkboxes = getAllByRole('checkbox'); + const checkboxes = screen.getAllByRole('checkbox'); checkboxes.forEach(c => expect(c).not.toBeChecked()); - expect(getByRole('button', { name: /Review/i })).toBeDisabled(); + expect(screen.getByRole('button', { name: /Review/i })).toBeDisabled(); await act(async () => { - await userEvent.click(getByRole('button', { name: /Select All/i })); + await userEvent.click( + screen.getByRole('button', { name: /Select All/i }), + ); }); checkboxes.forEach(c => expect(c).toBeChecked()); - expect(getByRole('button', { name: /Review/i })).not.toBeDisabled(); + expect(screen.getByRole('button', { name: /Review/i })).not.toBeDisabled(); await act(async () => { - await userEvent.click(getByRole('button', { name: /Select All/i })); + await userEvent.click( + screen.getByRole('button', { name: /Select All/i }), + ); }); checkboxes.forEach(c => expect(c).not.toBeChecked()); - expect(getByRole('button', { name: /Review/i })).toBeDisabled(); + expect(screen.getByRole('button', { name: /Review/i })).toBeDisabled(); }); it('should preselect prepared locations', async () => { - const { getAllByRole } = await renderInTestApp( + await renderInTestApp( ', () => { />, ); - const checkboxes = getAllByRole('checkbox'); + const checkboxes = screen.getAllByRole('checkbox'); expect(checkboxes[0]).not.toBeChecked(); expect(checkboxes[1]).toBeChecked(); @@ -159,7 +163,7 @@ describe('', () => { }); it('should select items', async () => { - const { getAllByRole } = await renderInTestApp( + await renderInTestApp( undefined} @@ -167,7 +171,7 @@ describe('', () => { />, ); - const checkboxes = getAllByRole('checkbox'); + const checkboxes = screen.getAllByRole('checkbox'); checkboxes.forEach(c => expect(c).not.toBeChecked()); await act(async () => { @@ -188,7 +192,7 @@ describe('', () => { it('should go back', async () => { const onGoBack = jest.fn(); - const { getByRole } = await renderInTestApp( + await renderInTestApp( undefined} @@ -197,7 +201,7 @@ describe('', () => { ); await act(async () => { - await userEvent.click(getByRole('button', { name: /Back/i })); + await userEvent.click(screen.getByRole('button', { name: /Back/i })); }); expect(onGoBack).toHaveBeenCalledTimes(1); @@ -206,7 +210,7 @@ describe('', () => { it('should submit', async () => { const onPrepare = jest.fn(); - const { getAllByRole, getByRole } = await renderInTestApp( + await renderInTestApp( ', () => { />, ); - const checkboxes = getAllByRole('checkbox'); + const checkboxes = screen.getAllByRole('checkbox'); await act(async () => { await userEvent.click(checkboxes[1]); }); await act(async () => { - await userEvent.click(getByRole('button', { name: /Review/i })); + await userEvent.click(screen.getByRole('button', { name: /Review/i })); }); expect(onPrepare).toHaveBeenCalledTimes(1); diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index ffbd18cd8e..e263ff5e87 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-node +## 1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 320f372249..09dbdd3d79 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-node", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", - "version": "1.2.1-next.0", + "version": "1.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-react/.eslintrc.js b/plugins/catalog-react/.eslintrc.js index e2a53a6ad2..45bb6db521 100644 --- a/plugins/catalog-react/.eslintrc.js +++ b/plugins/catalog-react/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + 'testing-library/prefer-screen-queries': 'error', + }, +}); diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 3019049086..8eda35598f 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-catalog-react +## 1.2.1 + +### Patch Changes + +- a889314692: Both `EntityProvider` and `AsyncEntityProvider` contexts now wrap all children with an `AnalyticsContext` containing the corresponding `entityRef`; this opens up the possibility for all events underneath these contexts to be associated with and aggregated by the corresponding entity. +- e47f466f80: Removed forced capitalization for Entity types in the catalog sidebar. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index c2363fdc76..b4e40d8546 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.2.1-next.0", + "version": "1.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "qs": "^6.9.4", "react-use": "^17.2.4", "yaml": "^2.0.0", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx index 65ad3f227a..8a6b7206c6 100644 --- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.test.tsx @@ -19,7 +19,7 @@ import { Entity } from '@backstage/catalog-model'; import { ApiProvider } from '@backstage/core-app-api'; import { alertApiRef } from '@backstage/core-plugin-api'; import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils'; -import { fireEvent, waitFor } from '@testing-library/react'; +import { fireEvent, waitFor, screen } from '@testing-library/react'; import { capitalize } from 'lodash'; import { default as React } from 'react'; import { catalogApiRef } from '../../api'; @@ -75,7 +75,7 @@ describe('', () => { ); it('renders available entity kinds', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - expect(rendered.getByText('Kind')).toBeInTheDocument(); + expect(screen.getByText('Kind')).toBeInTheDocument(); - const input = rendered.getByTestId('select'); + const input = screen.getByTestId('select'); fireEvent.click(input); - await waitFor(() => rendered.getByText('Domain')); + await waitFor(() => screen.getByText('Domain')); entities.forEach(entity => { expect( - rendered.getByRole('option', { + screen.getByRole('option', { name: capitalize(entity.kind as string), }), ).toBeInTheDocument(); @@ -102,7 +102,7 @@ describe('', () => { it('sets the selected kind filter', async () => { const updateFilters = jest.fn(); - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - const input = rendered.getByTestId('select'); + const input = screen.getByTestId('select'); fireEvent.click(input); - await waitFor(() => rendered.getByText('Domain')); - fireEvent.click(rendered.getByText('Domain')); + await waitFor(() => screen.getByText('Domain')); + fireEvent.click(screen.getByText('Domain')); expect(updateFilters).toHaveBeenLastCalledWith({ kind: new EntityKindFilter('domain'), diff --git a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx index 47e85292e2..f925625b23 100644 --- a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { MockEntityListContextProvider } from '../../testUtils/providers'; import { EntityLifecycleFilter } from '../../filters'; @@ -56,36 +56,36 @@ const sampleEntities: Entity[] = [ describe('', () => { it('renders all lifecycles', () => { - const rendered = render( + render( , ); - expect(rendered.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); - fireEvent.click(rendered.getByTestId('lifecycle-picker-expand')); + fireEvent.click(screen.getByTestId('lifecycle-picker-expand')); sampleEntities .map(e => e.spec?.lifecycle!) .forEach(lifecycle => { - expect(rendered.getByText(lifecycle as string)).toBeInTheDocument(); + expect(screen.getByText(lifecycle as string)).toBeInTheDocument(); }); }); it('renders unique lifecycles in alphabetical order', () => { - const rendered = render( + render( , ); - expect(rendered.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); - fireEvent.click(rendered.getByTestId('lifecycle-picker-expand')); + fireEvent.click(screen.getByTestId('lifecycle-picker-expand')); - expect(rendered.getAllByRole('option').map(o => o.textContent)).toEqual([ + expect(screen.getAllByRole('option').map(o => o.textContent)).toEqual([ 'experimental', 'production', ]); @@ -114,7 +114,7 @@ describe('', () => { it('adds lifecycles to filters', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { lifecycles: undefined, }); - fireEvent.click(rendered.getByTestId('lifecycle-picker-expand')); - fireEvent.click(rendered.getByText('production')); + fireEvent.click(screen.getByTestId('lifecycle-picker-expand')); + fireEvent.click(screen.getByText('production')); expect(updateFilters).toHaveBeenLastCalledWith({ lifecycles: new EntityLifecycleFilter(['production']), }); @@ -138,7 +138,7 @@ describe('', () => { it('removes lifecycles from filters', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { expect(updateFilters).toHaveBeenLastCalledWith({ lifecycles: new EntityLifecycleFilter(['production']), }); - fireEvent.click(rendered.getByTestId('lifecycle-picker-expand')); - expect(rendered.getByLabelText('production')).toBeChecked(); + fireEvent.click(screen.getByTestId('lifecycle-picker-expand')); + expect(screen.getByLabelText('production')).toBeChecked(); - fireEvent.click(rendered.getByLabelText('production')); + fireEvent.click(screen.getByLabelText('production')); expect(updateFilters).toHaveBeenLastCalledWith({ lifecycles: undefined, }); diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx index f648b51456..c816810b10 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx @@ -15,7 +15,7 @@ */ import { Entity, parseEntityRef } from '@backstage/catalog-model'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { MockEntityListContextProvider } from '../../testUtils/providers'; import { EntityOwnerFilter } from '../../filters'; @@ -69,36 +69,36 @@ const sampleEntities: Entity[] = [ describe('', () => { it('renders all owners', () => { - const rendered = render( + render( , ); - expect(rendered.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner')).toBeInTheDocument(); - fireEvent.click(rendered.getByTestId('owner-picker-expand')); + fireEvent.click(screen.getByTestId('owner-picker-expand')); sampleEntities .flatMap(e => e.relations?.map(r => parseEntityRef(r.targetRef).name)) .forEach(owner => { - expect(rendered.getByText(owner as string)).toBeInTheDocument(); + expect(screen.getByText(owner as string)).toBeInTheDocument(); }); }); it('renders unique owners in alphabetical order', () => { - const rendered = render( + render( , ); - expect(rendered.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner')).toBeInTheDocument(); - fireEvent.click(rendered.getByTestId('owner-picker-expand')); + fireEvent.click(screen.getByTestId('owner-picker-expand')); - expect(rendered.getAllByRole('option').map(o => o.textContent)).toEqual([ + expect(screen.getAllByRole('option').map(o => o.textContent)).toEqual([ 'another-owner', 'some-owner', 'some-owner-2', @@ -128,7 +128,7 @@ describe('', () => { it('adds owners to filters', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { owners: undefined, }); - fireEvent.click(rendered.getByTestId('owner-picker-expand')); - fireEvent.click(rendered.getByText('some-owner')); + fireEvent.click(screen.getByTestId('owner-picker-expand')); + fireEvent.click(screen.getByText('some-owner')); expect(updateFilters).toHaveBeenLastCalledWith({ owners: new EntityOwnerFilter(['some-owner']), }); @@ -152,7 +152,7 @@ describe('', () => { it('removes owners from filters', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { expect(updateFilters).toHaveBeenLastCalledWith({ owners: new EntityOwnerFilter(['some-owner']), }); - fireEvent.click(rendered.getByTestId('owner-picker-expand')); - expect(rendered.getByLabelText('some-owner')).toBeChecked(); + fireEvent.click(screen.getByTestId('owner-picker-expand')); + expect(screen.getByLabelText('some-owner')).toBeChecked(); - fireEvent.click(rendered.getByLabelText('some-owner')); + fireEvent.click(screen.getByLabelText('some-owner')); expect(updateFilters).toHaveBeenLastCalledWith({ owner: undefined, }); diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx index 8e90e04148..00d36e5e13 100644 --- a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.test.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { EntityErrorFilter, EntityOrphanFilter } from '../../filters'; import { MockEntityListContextProvider } from '../../testUtils/providers'; @@ -52,23 +52,23 @@ const sampleEntities: Entity[] = [ describe('', () => { it('renders all processing status options', () => { - const rendered = render( + render( , ); - expect(rendered.getByText('Processing Status')).toBeInTheDocument(); + expect(screen.getByText('Processing Status')).toBeInTheDocument(); - fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); - expect(rendered.getByText('Is Orphan')).toBeInTheDocument(); - expect(rendered.getByText('Has Error')).toBeInTheDocument(); + fireEvent.click(screen.getByTestId('processing-status-picker-expand')); + expect(screen.getByText('Is Orphan')).toBeInTheDocument(); + expect(screen.getByText('Has Error')).toBeInTheDocument(); }); it('adds orphan to orphan filter', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { , ); - fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); - fireEvent.click(rendered.getByText('Is Orphan')); + fireEvent.click(screen.getByTestId('processing-status-picker-expand')); + fireEvent.click(screen.getByText('Is Orphan')); expect(updateFilters).toHaveBeenCalledWith({ orphan: new EntityOrphanFilter(true), }); @@ -89,7 +89,7 @@ describe('', () => { it('adds error to error filter', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { , ); - fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); - fireEvent.click(rendered.getByText('Has Error')); + fireEvent.click(screen.getByTestId('processing-status-picker-expand')); + fireEvent.click(screen.getByText('Has Error')); expect(updateFilters).toHaveBeenCalledWith({ error: new EntityErrorFilter(true), }); @@ -110,7 +110,7 @@ describe('', () => { it('remove orphan from orphan filter', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { , ); - fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); - fireEvent.click(rendered.getByText('Is Orphan')); + fireEvent.click(screen.getByTestId('processing-status-picker-expand')); + fireEvent.click(screen.getByText('Is Orphan')); expect(updateFilters).toHaveBeenCalledWith({ orphan: undefined, }); @@ -131,7 +131,7 @@ describe('', () => { it('remove error from error filter', () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { , ); - fireEvent.click(rendered.getByTestId('processing-status-picker-expand')); - fireEvent.click(rendered.getByText('Has Error')); + fireEvent.click(screen.getByTestId('processing-status-picker-expand')); + fireEvent.click(screen.getByText('Has Error')); expect(updateFilters).toHaveBeenCalledWith({ error: undefined, }); diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.test.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.test.tsx index eaaaab39bc..b0a6b46bf5 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.test.tsx +++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.test.tsx @@ -15,6 +15,7 @@ */ import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { entityRouteRef } from '../../routes'; import { EntityRefLink } from './EntityRefLink'; @@ -33,16 +34,13 @@ describe('', () => { lifecycle: 'production', }, }; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); + }); - expect(getByText('component:software')).toHaveAttribute( + expect(screen.getByText('component:software')).toHaveAttribute( 'href', '/catalog/default/component/software', ); @@ -62,15 +60,12 @@ describe('', () => { lifecycle: 'production', }, }; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); - expect(getByText('component:test/software')).toHaveAttribute( + }); + expect(screen.getByText('component:test/software')).toHaveAttribute( 'href', '/catalog/test/component/software', ); @@ -90,7 +85,7 @@ describe('', () => { lifecycle: 'production', }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( , { mountedRoutes: { @@ -98,7 +93,7 @@ describe('', () => { }, }, ); - expect(getByText('test/software')).toHaveAttribute( + expect(screen.getByText('test/software')).toHaveAttribute( 'href', '/catalog/test/component/software', ); @@ -110,15 +105,12 @@ describe('', () => { namespace: 'default', name: 'software', }; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); - expect(getByText('component:software')).toHaveAttribute( + }); + expect(screen.getByText('component:software')).toHaveAttribute( 'href', '/catalog/default/component/software', ); @@ -130,15 +122,12 @@ describe('', () => { namespace: 'test', name: 'software', }; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); - expect(getByText('component:test/software')).toHaveAttribute( + }); + expect(screen.getByText('component:test/software')).toHaveAttribute( 'href', '/catalog/test/component/software', ); @@ -150,7 +139,7 @@ describe('', () => { namespace: 'test', name: 'software', }; - const { getByText } = await renderInTestApp( + await renderInTestApp( , { mountedRoutes: { @@ -158,7 +147,7 @@ describe('', () => { }, }, ); - expect(getByText('test/software')).toHaveAttribute( + expect(screen.getByText('test/software')).toHaveAttribute( 'href', '/catalog/test/component/software', ); @@ -170,7 +159,7 @@ describe('', () => { namespace: 'test', name: 'software', }; - const { getByText } = await renderInTestApp( + await renderInTestApp( Custom Children , @@ -180,7 +169,7 @@ describe('', () => { }, }, ); - expect(getByText('Custom Children')).toHaveAttribute( + expect(screen.getByText('Custom Children')).toHaveAttribute( 'href', '/catalog/test/component/software', ); diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.test.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.test.tsx index 147e139749..4e0d52ef4e 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.test.tsx +++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.test.tsx @@ -15,6 +15,7 @@ */ import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { entityRouteRef } from '../../routes'; import { EntityRefLinks } from './EntityRefLinks'; @@ -28,15 +29,12 @@ describe('', () => { name: 'software', }, ]; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); - expect(getByText('component:software')).toHaveAttribute( + }); + expect(screen.getByText('component:software')).toHaveAttribute( 'href', '/catalog/default/component/software', ); @@ -55,20 +53,17 @@ describe('', () => { name: 'interface', }, ]; - const { getByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, }, - ); - expect(getByText(',')).toBeInTheDocument(); - expect(getByText('component:software')).toHaveAttribute( + }); + expect(screen.getByText(',')).toBeInTheDocument(); + expect(screen.getByText('component:software')).toHaveAttribute( 'href', '/catalog/default/component/software', ); - expect(getByText('api:interface')).toHaveAttribute( + expect(screen.getByText('api:interface')).toHaveAttribute( 'href', '/catalog/default/api/interface', ); diff --git a/plugins/catalog-react/src/components/EntityRefLink/FetchedEntityRefLinks.test.tsx b/plugins/catalog-react/src/components/EntityRefLink/FetchedEntityRefLinks.test.tsx index 36e2c0450d..9db6511662 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/FetchedEntityRefLinks.test.tsx +++ b/plugins/catalog-react/src/components/EntityRefLink/FetchedEntityRefLinks.test.tsx @@ -16,6 +16,7 @@ import { FetchedEntityRefLinks } from './FetchedEntityRefLinks'; import { entityRouteRef } from '../../routes'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import { Entity } from '@backstage/catalog-model'; import React from 'react'; import { JsonObject } from '@backstage/types'; @@ -60,7 +61,7 @@ describe('', () => { }), }; - const rendered = await renderInTestApp( + await renderInTestApp( , @@ -71,12 +72,12 @@ describe('', () => { }, ); - expect(rendered.getByText('SOFTWARE')).toHaveAttribute( + expect(screen.getByText('SOFTWARE')).toHaveAttribute( 'href', '/catalog/default/component/software', ); - expect(rendered.getByText('INTERFACE')).toHaveAttribute( + expect(screen.getByText('INTERFACE')).toHaveAttribute( 'href', '/catalog/default/api/interface', ); @@ -111,7 +112,7 @@ describe('', () => { const catalogApi: Partial = {}; - const rendered = await renderInTestApp( + await renderInTestApp( , @@ -122,12 +123,12 @@ describe('', () => { }, ); - expect(rendered.getByText('TOOL')).toHaveAttribute( + expect(screen.getByText('TOOL')).toHaveAttribute( 'href', '/catalog/default/component/tool', ); - expect(rendered.getByText('IMPLEMENTATION')).toHaveAttribute( + expect(screen.getByText('IMPLEMENTATION')).toHaveAttribute( 'href', '/catalog/default/api/implementation', ); @@ -189,7 +190,7 @@ describe('', () => { }), }; - const rendered = await renderInTestApp( + await renderInTestApp( , @@ -200,17 +201,17 @@ describe('', () => { }, ); - expect(rendered.getByText('TOOL')).toHaveAttribute( + expect(screen.getByText('TOOL')).toHaveAttribute( 'href', '/catalog/default/component/tool', ); - expect(rendered.getByText('IMPLEMENTATION')).toHaveAttribute( + expect(screen.getByText('IMPLEMENTATION')).toHaveAttribute( 'href', '/catalog/default/api/implementation', ); - expect(rendered.getByText('INTERFACE')).toHaveAttribute( + expect(screen.getByText('INTERFACE')).toHaveAttribute( 'href', '/catalog/default/component/interface', ); diff --git a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx index 0b9ea9cb98..94db377e26 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx +++ b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render, waitFor, screen } from '@testing-library/react'; import { EntitySearchBar } from './EntitySearchBar'; import { DefaultEntityFilters } from '../../hooks/useEntityListProvider'; import { EntityTextFilter } from '../../filters'; @@ -29,13 +29,13 @@ describe('EntitySearchBar', () => { text: new EntityTextFilter('hello'), }; - const { getByDisplayValue } = render( + render( , ); - const searchInput = getByDisplayValue('hello'); + const searchInput = screen.getByDisplayValue('hello'); expect(searchInput).toBeInTheDocument(); fireEvent.change(searchInput, { target: { value: 'world' } }); diff --git a/plugins/catalog-react/src/components/EntityTable/EntityTable.test.tsx b/plugins/catalog-react/src/components/EntityTable/EntityTable.test.tsx index 99f998118f..d5f1dc20d3 100644 --- a/plugins/catalog-react/src/components/EntityTable/EntityTable.test.tsx +++ b/plugins/catalog-react/src/components/EntityTable/EntityTable.test.tsx @@ -16,13 +16,13 @@ import { Entity } from '@backstage/catalog-model'; import { renderInTestApp } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { EntityTable } from './EntityTable'; describe('', () => { it('shows empty table', async () => { - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { />, ); - expect(getByText('Entities')).toBeInTheDocument(); - expect(getByText('EMPTY')).toBeInTheDocument(); + expect(screen.getByText('Entities')).toBeInTheDocument(); + expect(screen.getByText('EMPTY')).toBeInTheDocument(); }); it('shows entities', async () => { @@ -47,7 +47,7 @@ describe('', () => { }, ]; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { ); await waitFor(() => { - expect(getByText('my-entity')).toBeInTheDocument(); + expect(screen.getByText('my-entity')).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog-react/src/components/EntityTable/presets.test.tsx b/plugins/catalog-react/src/components/EntityTable/presets.test.tsx index cca9c7d494..82075df5e9 100644 --- a/plugins/catalog-react/src/components/EntityTable/presets.test.tsx +++ b/plugins/catalog-react/src/components/EntityTable/presets.test.tsx @@ -21,7 +21,7 @@ import { SystemEntity, } from '@backstage/catalog-model'; import { renderInTestApp } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { entityRouteRef } from '../../routes'; import { EntityTable } from './EntityTable'; @@ -54,7 +54,7 @@ describe('systemEntityColumns', () => { }, ]; - const { getByText } = await renderInTestApp( + await renderInTestApp( { ); await waitFor(() => { - expect(getByText('my-namespace/my-system')).toBeInTheDocument(); - expect(getByText('my-namespace/my-domain')).toBeInTheDocument(); - expect(getByText('test')).toBeInTheDocument(); - expect(getByText(/Some/)).toBeInTheDocument(); + expect(screen.getByText('my-namespace/my-system')).toBeInTheDocument(); + expect(screen.getByText('my-namespace/my-domain')).toBeInTheDocument(); + expect(screen.getByText('test')).toBeInTheDocument(); + expect(screen.getByText(/Some/)).toBeInTheDocument(); }); }); }); @@ -106,7 +106,7 @@ describe('componentEntityColumns', () => { }, ]; - const { getByText } = await renderInTestApp( + await renderInTestApp( { ); await waitFor(() => { - expect(getByText('my-namespace/my-component')).toBeInTheDocument(); - expect(getByText('my-namespace/my-system')).toBeInTheDocument(); - expect(getByText('test')).toBeInTheDocument(); - expect(getByText('production')).toBeInTheDocument(); - expect(getByText('service')).toBeInTheDocument(); - expect(getByText(/Some/)).toBeInTheDocument(); + expect(screen.getByText('my-namespace/my-component')).toBeInTheDocument(); + expect(screen.getByText('my-namespace/my-system')).toBeInTheDocument(); + expect(screen.getByText('test')).toBeInTheDocument(); + expect(screen.getByText('production')).toBeInTheDocument(); + expect(screen.getByText('service')).toBeInTheDocument(); + expect(screen.getByText(/Some/)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx index 78bdde1994..7da357d806 100644 --- a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render, waitFor, screen } from '@testing-library/react'; import React from 'react'; import { MockEntityListContextProvider } from '../../testUtils/providers'; import { EntityTagFilter } from '../../filters'; @@ -35,34 +35,34 @@ describe('', () => { } as unknown as CatalogApi; it('renders all tags', async () => { - const rendered = render( + render( , ); - await waitFor(() => expect(rendered.getByText('Tags')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByText('Tags')).toBeInTheDocument()); - fireEvent.click(rendered.getByTestId('tag-picker-expand')); + fireEvent.click(screen.getByTestId('tag-picker-expand')); tags.forEach(tag => { - expect(rendered.getByText(tag)).toBeInTheDocument(); + expect(screen.getByText(tag)).toBeInTheDocument(); }); }); it('renders unique tags in alphabetical order', async () => { - const rendered = render( + render( , ); - await waitFor(() => expect(rendered.getByText('Tags')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByText('Tags')).toBeInTheDocument()); - fireEvent.click(rendered.getByTestId('tag-picker-expand')); + fireEvent.click(screen.getByTestId('tag-picker-expand')); - expect(rendered.getAllByRole('option').map(o => o.textContent)).toEqual([ + expect(screen.getAllByRole('option').map(o => o.textContent)).toEqual([ 'tag1', 'tag2', 'tag3', @@ -71,18 +71,18 @@ describe('', () => { }); it('renders tags with counts', async () => { - const rendered = render( + render( , ); - await waitFor(() => expect(rendered.getByText('Tags')).toBeInTheDocument()); + await waitFor(() => expect(screen.getByText('Tags')).toBeInTheDocument()); - fireEvent.click(rendered.getByTestId('tag-picker-expand')); + fireEvent.click(screen.getByTestId('tag-picker-expand')); - expect(rendered.getAllByRole('option').map(o => o.textContent)).toEqual([ + expect(screen.getAllByRole('option').map(o => o.textContent)).toEqual([ 'tag1 (0)', 'tag2 (1)', 'tag3 (2)', @@ -115,7 +115,7 @@ describe('', () => { it('adds tags to filters', async () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { }), ); - fireEvent.click(rendered.getByTestId('tag-picker-expand')); - fireEvent.click(rendered.getByText('tag1')); + fireEvent.click(screen.getByTestId('tag-picker-expand')); + fireEvent.click(screen.getByText('tag1')); expect(updateFilters).toHaveBeenLastCalledWith({ tags: new EntityTagFilter(['tag1']), }); @@ -141,7 +141,7 @@ describe('', () => { it('removes tags from filters', async () => { const updateFilters = jest.fn(); - const rendered = render( + render( ', () => { tags: new EntityTagFilter(['tag1']), }), ); - fireEvent.click(rendered.getByTestId('tag-picker-expand')); - expect(rendered.getByLabelText('tag1')).toBeChecked(); + fireEvent.click(screen.getByTestId('tag-picker-expand')); + expect(screen.getByLabelText('tag1')).toBeChecked(); - fireEvent.click(rendered.getByLabelText('tag1')); + fireEvent.click(screen.getByLabelText('tag1')); expect(updateFilters).toHaveBeenLastCalledWith({ tags: undefined, }); diff --git a/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx b/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx index 525c757dea..d61a6c480f 100644 --- a/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx @@ -15,13 +15,12 @@ */ import React from 'react'; -import { fireEvent, waitFor } from '@testing-library/react'; +import { fireEvent, waitFor, screen } from '@testing-library/react'; import { Entity } from '@backstage/catalog-model'; import { EntityTypePicker } from './EntityTypePicker'; import { MockEntityListContextProvider } from '../../testUtils/providers'; import { catalogApiRef } from '../../api'; import { EntityKindFilter, EntityTypeFilter } from '../../filters'; - import { alertApiRef } from '@backstage/core-plugin-api'; import { ApiProvider } from '@backstage/core-app-api'; import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils'; @@ -84,7 +83,7 @@ const apis = TestApiRegistry.from( describe('', () => { it('renders available entity types', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - expect(rendered.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); - const input = rendered.getByTestId('select'); + const input = screen.getByTestId('select'); fireEvent.click(input); - await waitFor(() => rendered.getByText('service')); + await waitFor(() => screen.getByText('service')); entities.forEach(entity => { - expect( - rendered.getByText(entity.spec!.type as string), - ).toBeInTheDocument(); + expect(screen.getByText(entity.spec!.type as string)).toBeInTheDocument(); }); }); it('sets the selected type filter', async () => { const updateFilters = jest.fn(); - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - const input = rendered.getByTestId('select'); + const input = screen.getByTestId('select'); fireEvent.click(input); - await waitFor(() => rendered.getByText('service')); - fireEvent.click(rendered.getByText('service')); + await waitFor(() => screen.getByText('service')); + fireEvent.click(screen.getByText('service')); expect(updateFilters).toHaveBeenLastCalledWith({ type: new EntityTypeFilter(['service']), }); fireEvent.click(input); - fireEvent.click(rendered.getByText('all')); + fireEvent.click(screen.getByText('all')); expect(updateFilters).toHaveBeenLastCalledWith({ type: undefined }); }); diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx index 3db2fab0fb..d5309a383d 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render, waitFor, screen } from '@testing-library/react'; import { Entity, RELATION_OWNED_BY, @@ -27,7 +27,6 @@ import { EntityTagFilter, UserListFilter } from '../../filters'; import { CatalogApi } from '@backstage/catalog-client'; import { catalogApiRef } from '../../api'; import { MockStorageApi, TestApiRegistry } from '@backstage/test-utils'; - import { ApiProvider } from '@backstage/core-app-api'; import { ConfigApi, @@ -144,7 +143,7 @@ const backendEntities: Entity[] = [ describe('', () => { it('renders filter groups', () => { - const { queryByText } = render( + render( @@ -152,12 +151,12 @@ describe('', () => { , ); - expect(queryByText('Personal')).toBeInTheDocument(); - expect(queryByText('Test Company')).toBeInTheDocument(); + expect(screen.queryByText('Personal')).toBeInTheDocument(); + expect(screen.queryByText('Test Company')).toBeInTheDocument(); }); it('renders filters', () => { - const { getAllByRole } = render( + render( @@ -166,12 +165,12 @@ describe('', () => { ); expect( - getAllByRole('menuitem').map(({ textContent }) => textContent), + screen.getAllByRole('menuitem').map(({ textContent }) => textContent), ).toEqual(['Owned 1', 'Starred 1', 'All 4']); }); it('includes counts alongside each filter', async () => { - const { getAllByRole } = render( + render( @@ -183,13 +182,13 @@ describe('', () => { // menuitem itself, so we pick off the next sibling. await waitFor(() => { expect( - getAllByRole('menuitem').map(({ textContent }) => textContent), + screen.getAllByRole('menuitem').map(({ textContent }) => textContent), ).toEqual(['Owned 1', 'Starred 1', 'All 4']); }); }); it('respects other frontend filters in counts', async () => { - const { getAllByRole } = render( + render( ', () => { await waitFor(() => { expect( - getAllByRole('menuitem').map(({ textContent }) => textContent), + screen.getAllByRole('menuitem').map(({ textContent }) => textContent), ).toEqual(['Owned 1', 'Starred 0', 'All 2']); }); }); @@ -229,7 +228,7 @@ describe('', () => { it('updates user filter when a menuitem is selected', () => { const updateFilters = jest.fn(); - const { getByText } = render( + render( ', () => { , ); - fireEvent.click(getByText('Starred')); + fireEvent.click(screen.getByText('Starred')); expect(updateFilters).toHaveBeenLastCalledWith({ user: new UserListFilter( diff --git a/plugins/catalog/.eslintrc.js b/plugins/catalog/.eslintrc.js index e2a53a6ad2..45bb6db521 100644 --- a/plugins/catalog/.eslintrc.js +++ b/plugins/catalog/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + 'testing-library/prefer-screen-queries': 'error', + }, +}); diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index e95afd8617..99ece53655 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog +## 1.6.1 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-search-common@1.1.1 + +## 1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 1.6.1-next.0 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index de2833c470..1528737aac 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.6.1-next.0", + "version": "1.6.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "lodash": "^4.17.21", "react-helmet": "6.1.0", "react-use": "^17.2.4", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index c77787f717..869d6f1757 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -28,6 +28,7 @@ import { } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import userEvent from '@testing-library/user-event'; +import { screen } from '@testing-library/react'; import React from 'react'; import { viewTechDocRouteRef } from '../../routes'; import { AboutCard } from './AboutCard'; @@ -73,7 +74,7 @@ describe('', () => { ], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - expect(getByText('service')).toBeInTheDocument(); - expect(getByText('user:guest')).toBeInTheDocument(); - expect(getByText('production')).toBeInTheDocument(); - expect(getByText('This is the description')).toBeInTheDocument(); + expect(screen.getByText('service')).toBeInTheDocument(); + expect(screen.getByText('user:guest')).toBeInTheDocument(); + expect(screen.getByText('production')).toBeInTheDocument(); + expect(screen.getByText('This is the description')).toBeInTheDocument(); }); it('renders "view source" link', async () => { @@ -122,7 +123,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, }, ); - expect(getByText('View Source').closest('a')).toHaveAttribute( + expect(screen.getByText('View Source').closest('a')).toHaveAttribute( 'href', 'https://github.com/backstage/backstage/blob/master/software.yaml', ); @@ -177,7 +178,7 @@ describe('', () => { }, }; - const { getByTitle } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - const editLink = getByTitle('Edit Metadata').closest('a'); + const editLink = screen.getByTitle('Edit Metadata').closest('a'); expect(editLink).toHaveAttribute( 'href', 'https://github.com/backstage/backstage/edit/master/software.yaml', @@ -230,7 +231,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, }, ); - expect(getByText('View Source')).toBeVisible(); - expect(getByText('View Source').closest('a')).toBeNull(); + expect(screen.getByText('View Source')).toBeVisible(); + expect(screen.getByText('View Source').closest('a')).toBeNull(); }); it.each([ @@ -274,7 +275,7 @@ describe('', () => { }, }; - const { getByTitle } = await renderInTestApp( + await renderInTestApp( ', () => { 'component:default/software', ); - await userEvent.click(getByTitle('Schedule entity refresh')); + await userEvent.click(screen.getByTitle('Schedule entity refresh')); expect(catalogApi.refreshEntity).toHaveBeenCalledWith( 'component:default/software', @@ -320,7 +321,7 @@ describe('', () => { }, }; - const { queryByTitle } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - expect(queryByTitle('Schedule entity refresh')).not.toBeInTheDocument(); + expect( + screen.queryByTitle('Schedule entity refresh'), + ).not.toBeInTheDocument(); }); it('renders techdocs link', async () => { @@ -361,7 +364,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - expect(getByText('View TechDocs').closest('a')).toHaveAttribute( + expect(screen.getByText('View TechDocs').closest('a')).toHaveAttribute( 'href', '/docs/default/Component/software', ); @@ -414,7 +417,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - expect(getByText('View TechDocs')).toBeVisible(); - expect(getByText('View TechDocs').closest('a')).toBeNull(); + expect(screen.getByText('View TechDocs')).toBeVisible(); + expect(screen.getByText('View TechDocs').closest('a')).toBeNull(); }); it('renders disabled techdocs link when route is not bound', async () => { @@ -467,7 +470,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); - expect(getByText('View TechDocs')).toBeVisible(); - expect(getByText('View TechDocs').closest('a')).toBeNull(); + expect(screen.getByText('View TechDocs')).toBeVisible(); + expect(screen.getByText('View TechDocs').closest('a')).toBeNull(); }); }); diff --git a/plugins/catalog/src/components/AboutCard/AboutContent.test.tsx b/plugins/catalog/src/components/AboutCard/AboutContent.test.tsx index f4dbb73b45..2a89f2fd92 100644 --- a/plugins/catalog/src/components/AboutCard/AboutContent.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutContent.test.tsx @@ -21,6 +21,7 @@ import { } from '@backstage/catalog-model'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { AboutContent } from './AboutContent'; @@ -62,32 +63,29 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:o'); - expect(getByText('Domain')).toBeInTheDocument(); - expect(getByText('Domain').nextSibling).toHaveTextContent('d'); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('s'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('t'); - expect(getByText('Lifecycle')).toBeInTheDocument(); - expect(getByText('Lifecycle').nextSibling).toHaveTextContent('l'); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent('user:o'); + expect(screen.getByText('Domain')).toBeInTheDocument(); + expect(screen.getByText('Domain').nextSibling).toHaveTextContent('d'); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent('s'); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('t'); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle').nextSibling).toHaveTextContent('l'); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { @@ -95,26 +93,25 @@ describe('', () => { entity.spec = {}; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(queryByText('Type')).not.toBeInTheDocument(); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.queryByText('Type')).not.toBeInTheDocument(); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); }); }); @@ -151,33 +148,34 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:guest'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('system'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('openapi'); - expect(getByText('Lifecycle')).toBeInTheDocument(); - expect(getByText('Lifecycle').nextSibling).toHaveTextContent( + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'user:guest', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'system', + ); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('openapi'); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle').nextSibling).toHaveTextContent( 'production', ); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { @@ -187,31 +185,34 @@ describe('', () => { delete entity.spec!.system; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('No System'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('unknown'); - expect(getByText('Lifecycle')).toBeInTheDocument(); - expect(getByText('Lifecycle').nextSibling).toHaveTextContent('unknown'); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'No System', + ); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('unknown'); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle').nextSibling).toHaveTextContent( + 'unknown', + ); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); @@ -252,36 +253,37 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:guest'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('system'); - expect(getByText('Parent Component')).toBeInTheDocument(); - expect(getByText('Parent Component').nextSibling).toHaveTextContent( - 'parent-software', + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'user:guest', ); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('service'); - expect(getByText('Lifecycle')).toBeInTheDocument(); - expect(getByText('Lifecycle').nextSibling).toHaveTextContent( + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'system', + ); + expect(screen.getByText('Parent Component')).toBeInTheDocument(); + expect( + screen.getByText('Parent Component').nextSibling, + ).toHaveTextContent('parent-software'); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('service'); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle').nextSibling).toHaveTextContent( 'production', ); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { @@ -291,31 +293,34 @@ describe('', () => { delete entity.spec!.system; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('No System'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('unknown'); - expect(getByText('Lifecycle')).toBeInTheDocument(); - expect(getByText('Lifecycle').nextSibling).toHaveTextContent('unknown'); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'No System', + ); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('unknown'); + expect(screen.getByText('Lifecycle')).toBeInTheDocument(); + expect(screen.getByText('Lifecycle').nextSibling).toHaveTextContent( + 'unknown', + ); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); @@ -344,56 +349,54 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:guest'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(queryByText('Type')).not.toBeInTheDocument(); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'user:guest', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.queryByText('Type')).not.toBeInTheDocument(); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { delete entity.metadata.tags; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(queryByText('Type')).not.toBeInTheDocument(); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.queryByText('Type')).not.toBeInTheDocument(); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); @@ -418,31 +421,30 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('root'); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); - expect(getByText('Targets')).toBeInTheDocument(); - expect(getByText('Targets').nextSibling).toHaveTextContent( + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('root'); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Targets')).toBeInTheDocument(); + expect(screen.getByText('Targets').nextSibling).toHaveTextContent( 'https://backstage.io', ); }); @@ -451,29 +453,28 @@ describe('', () => { delete entity.metadata.tags; delete entity.spec!.type; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('unknown'); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('unknown'); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); @@ -508,30 +509,31 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:guest'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('system'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('s3'); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'user:guest', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'system', + ); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('s3'); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { @@ -540,30 +542,31 @@ describe('', () => { delete entity.spec!.system; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(queryByText('Domain')).not.toBeInTheDocument(); - expect(getByText('System')).toBeInTheDocument(); - expect(getByText('System').nextSibling).toHaveTextContent('No System'); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(getByText('Type')).toBeInTheDocument(); - expect(getByText('Type').nextSibling).toHaveTextContent('unknown'); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.queryByText('Domain')).not.toBeInTheDocument(); + expect(screen.getByText('System')).toBeInTheDocument(); + expect(screen.getByText('System').nextSibling).toHaveTextContent( + 'No System', + ); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.getByText('Type')).toBeInTheDocument(); + expect(screen.getByText('Type').nextSibling).toHaveTextContent('unknown'); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); @@ -597,29 +600,30 @@ describe('', () => { }); it('renders info', async () => { - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('user:guest'); - expect(getByText('Domain')).toBeInTheDocument(); - expect(getByText('Domain').nextSibling).toHaveTextContent('domain'); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(queryByText('Type')).not.toBeInTheDocument(); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('tag-1'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'user:guest', + ); + expect(screen.getByText('Domain')).toBeInTheDocument(); + expect(screen.getByText('Domain').nextSibling).toHaveTextContent( + 'domain', + ); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.queryByText('Type')).not.toBeInTheDocument(); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('tag-1'); }); it('highlights missing required fields', async () => { @@ -627,29 +631,30 @@ describe('', () => { delete entity.spec!.domain; entity.relations = []; - const { getByText, queryByText } = await renderInTestApp( - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, + await renderInTestApp(, { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, }, - ); + }); - expect(getByText('Description')).toBeInTheDocument(); - expect(getByText('Description').nextSibling).toHaveTextContent( + expect(screen.getByText('Description')).toBeInTheDocument(); + expect(screen.getByText('Description').nextSibling).toHaveTextContent( 'This is the description', ); - expect(getByText('Owner')).toBeInTheDocument(); - expect(getByText('Owner').nextSibling).toHaveTextContent('No Owner'); - expect(getByText('Domain')).toBeInTheDocument(); - expect(getByText('Domain').nextSibling).toHaveTextContent('No Domain'); - expect(queryByText('System')).not.toBeInTheDocument(); - expect(queryByText('Parent Component')).not.toBeInTheDocument(); - expect(queryByText('Type')).not.toBeInTheDocument(); - expect(queryByText('Lifecycle')).not.toBeInTheDocument(); - expect(getByText('Tags')).toBeInTheDocument(); - expect(getByText('Tags').nextSibling).toHaveTextContent('No Tags'); + expect(screen.getByText('Owner')).toBeInTheDocument(); + expect(screen.getByText('Owner').nextSibling).toHaveTextContent( + 'No Owner', + ); + expect(screen.getByText('Domain')).toBeInTheDocument(); + expect(screen.getByText('Domain').nextSibling).toHaveTextContent( + 'No Domain', + ); + expect(screen.queryByText('System')).not.toBeInTheDocument(); + expect(screen.queryByText('Parent Component')).not.toBeInTheDocument(); + expect(screen.queryByText('Type')).not.toBeInTheDocument(); + expect(screen.queryByText('Lifecycle')).not.toBeInTheDocument(); + expect(screen.getByText('Tags')).toBeInTheDocument(); + expect(screen.getByText('Tags').nextSibling).toHaveTextContent('No Tags'); }); }); }); diff --git a/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.test.tsx b/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.test.tsx index 15d41f3ab3..9f68252ca7 100644 --- a/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.test.tsx +++ b/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { fireEvent } from '@testing-library/react'; +import { fireEvent, screen } from '@testing-library/react'; import { GetEntityFacetsResponse } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { @@ -83,7 +83,7 @@ const apis = TestApiRegistry.from( describe('', () => { it('renders available kinds', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( @@ -91,18 +91,18 @@ describe('', () => { , ); - const input = rendered.getByText('Components'); + const input = screen.getByText('Components'); fireEvent.mouseDown(input); entities.map(entity => { expect( - rendered.getByRole('option', { name: `${entity.kind}s` }), + screen.getByRole('option', { name: `${entity.kind}s` }), ).toBeInTheDocument(); }); }); it('renders unknown kinds provided in query parameters', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - expect(rendered.getByText('Frobs')).toBeInTheDocument(); + expect(screen.getByText('Frobs')).toBeInTheDocument(); }); it('updates the kind filter', async () => { const updateFilters = jest.fn(); - const rendered = await renderWithEffects( + await renderWithEffects( @@ -125,10 +125,10 @@ describe('', () => { , ); - const input = rendered.getByText('Components'); + const input = screen.getByText('Components'); fireEvent.mouseDown(input); - const option = rendered.getByRole('option', { name: 'Templates' }); + const option = screen.getByRole('option', { name: 'Templates' }); fireEvent.click(option); expect(updateFilters).toHaveBeenCalledWith({ @@ -171,7 +171,7 @@ describe('', () => { }); it('limits kinds when allowedKinds is set', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( @@ -179,22 +179,20 @@ describe('', () => { , ); - const input = rendered.getByText('Components'); + const input = screen.getByText('Components'); fireEvent.mouseDown(input); expect( - rendered.getByRole('option', { name: 'Components' }), + screen.getByRole('option', { name: 'Components' }), ).toBeInTheDocument(); + expect(screen.getByRole('option', { name: 'Systems' })).toBeInTheDocument(); expect( - rendered.getByRole('option', { name: 'Systems' }), - ).toBeInTheDocument(); - expect( - rendered.queryByRole('option', { name: 'Templates' }), + screen.queryByRole('option', { name: 'Templates' }), ).not.toBeInTheDocument(); }); it('renders kind from the query parameter even when not in allowedKinds', async () => { - const rendered = await renderWithEffects( + await renderWithEffects( ', () => { , ); - expect(rendered.getByText('Frobs')).toBeInTheDocument(); - const input = rendered.getByText('Frobs'); + expect(screen.getByText('Frobs')).toBeInTheDocument(); + const input = screen.getByText('Frobs'); fireEvent.mouseDown(input); - expect( - rendered.getByRole('option', { name: 'Systems' }), - ).toBeInTheDocument(); + expect(screen.getByRole('option', { name: 'Systems' })).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx index 6fbdcf40a2..5b80f5976c 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import { useOutlet } from 'react-router'; import { CatalogPage } from './CatalogPage'; @@ -30,15 +31,15 @@ jest.mock('./DefaultCatalogPage', () => ({ describe('CatalogPage', () => { it('renders provided router element', async () => { - const { getByText } = await renderInTestApp(); + await renderInTestApp(); - expect(getByText('Route Children')).toBeInTheDocument(); + expect(screen.getByText('Route Children')).toBeInTheDocument(); }); it('renders DefaultCatalogPage home when no router children are provided', async () => { (useOutlet as jest.Mock).mockReturnValueOnce(null); - const { getByText } = await renderInTestApp(); + await renderInTestApp(); - expect(getByText('DefaultCatalogPage')).toBeInTheDocument(); + expect(screen.getByText('DefaultCatalogPage')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index cc00a57314..969992bd4e 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -178,11 +178,11 @@ describe('DefaultCatalogPage', () => { // limit. We should investigate why these timeouts happen. it('should render the default column of the grid', async () => { - const { getAllByRole } = await renderWrapped(); + await renderWrapped(); - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); const columnHeaderLabels = columnHeader.map(c => c.textContent); expect(columnHeaderLabels).toEqual([ @@ -203,26 +203,22 @@ describe('DefaultCatalogPage', () => { { title: 'Bar', field: 'entity.bar' }, { title: 'Baz', field: 'entity.spec.lifecycle' }, ]; - const { getAllByRole } = await renderWrapped( - , - ); + await renderWrapped(); - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); const columnHeaderLabels = columnHeader.map(c => c.textContent); expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); }, 20_000); it('should render the default actions of an item in the grid', async () => { - const { getByTestId, findByTitle, findByText } = await renderWrapped( - , - ); - fireEvent.click(getByTestId('user-picker-owned')); - expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/View/)).toBeInTheDocument(); - expect(await findByTitle(/Edit/)).toBeInTheDocument(); - expect(await findByTitle(/Add to favorites/)).toBeInTheDocument(); + await renderWrapped(); + fireEvent.click(screen.getByTestId('user-picker-owned')); + expect(await screen.findByText(/Owned \(1\)/)).toBeInTheDocument(); + expect(await screen.findByTitle(/View/)).toBeInTheDocument(); + expect(await screen.findByTitle(/Edit/)).toBeInTheDocument(); + expect(await screen.findByTitle(/Add to favorites/)).toBeInTheDocument(); }, 20_000); it('should render the custom actions of an item passed as prop', async () => { @@ -245,41 +241,35 @@ describe('DefaultCatalogPage', () => { }, ]; - const { getByTestId, findByTitle, findByText } = await renderWrapped( - , - ); - fireEvent.click(getByTestId('user-picker-owned')); - expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/Foo Action/)).toBeInTheDocument(); - expect(await findByTitle(/Bar Action/)).toBeInTheDocument(); - expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled(); + await renderWrapped(); + fireEvent.click(screen.getByTestId('user-picker-owned')); + expect(await screen.findByText(/Owned \(1\)/)).toBeInTheDocument(); + expect(await screen.findByTitle(/Foo Action/)).toBeInTheDocument(); + expect(await screen.findByTitle(/Bar Action/)).toBeInTheDocument(); + expect((await screen.findByTitle(/Bar Action/)).firstChild).toBeDisabled(); }, 20_000); // this test right now causes some red lines in the log output when running tests // related to some theme issues in mui-table // https://github.com/mbrn/material-table/issues/1293 it('should render', async () => { - const { findByText, getByTestId } = await renderWrapped( - , - ); - fireEvent.click(getByTestId('user-picker-owned')); - await expect(findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); - fireEvent.click(getByTestId('user-picker-all')); - await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + await renderWrapped(); + fireEvent.click(screen.getByTestId('user-picker-owned')); + await expect(screen.findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); + fireEvent.click(screen.getByTestId('user-picker-all')); + await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); }, 20_000); it('should set initial filter correctly', async () => { - const { findByText } = await renderWrapped( - , - ); - await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + await renderWrapped(); + await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); }, 20_000); // this test is for fixing the bug after favoriting an entity, the matching // entities defaulting to "owned" filter and not based on the selected filter it('should render the correct entities filtered on the selected filter', async () => { - const { getByTestId } = await renderWrapped(); - fireEvent.click(getByTestId('user-picker-owned')); + await renderWrapped(); + fireEvent.click(screen.getByTestId('user-picker-owned')); await expect(screen.findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); // The "Starred" menu option should initially be disabled, since there // aren't any starred entities. @@ -308,10 +298,12 @@ describe('DefaultCatalogPage', () => { it('should wrap filter in drawer on smaller screens', async () => { mockBreakpoint({ matches: true }); - const { getByRole } = await renderWrapped(); - const button = getByRole('button', { name: 'Filters' }); - expect(getByRole('presentation', { hidden: true })).toBeInTheDocument(); + await renderWrapped(); + const button = screen.getByRole('button', { name: 'Filters' }); + expect( + screen.getByRole('presentation', { hidden: true }), + ).toBeInTheDocument(); fireEvent.click(button); - expect(getByRole('presentation')).toBeVisible(); + expect(screen.getByRole('presentation')).toBeVisible(); }, 20_000); }); diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index bb2f302a37..652c9f3873 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -29,7 +29,7 @@ import { UserListFilter, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; -import { act, fireEvent } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import * as React from 'react'; import { CatalogTable } from './CatalogTable'; @@ -66,7 +66,7 @@ describe('CatalogTable component', () => { }); it('should render error message', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( @@ -78,14 +78,14 @@ describe('CatalogTable component', () => { }, }, ); - const errorMessage = await rendered.findByText( + const errorMessage = await screen.findByText( /Could not fetch catalog entities./, ); expect(errorMessage).toBeInTheDocument(); }); it('should display entity names when loading has finished and no error occurred', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( { }, }, ); - expect(rendered.getByText(/Owned \(3\)/)).toBeInTheDocument(); - expect(rendered.getByText(/component1/)).toBeInTheDocument(); - expect(rendered.getByText(/component2/)).toBeInTheDocument(); - expect(rendered.getByText(/component3/)).toBeInTheDocument(); + expect(screen.getByText(/Owned \(3\)/)).toBeInTheDocument(); + expect(screen.getByText(/component1/)).toBeInTheDocument(); + expect(screen.getByText(/component2/)).toBeInTheDocument(); + expect(screen.getByText(/component3/)).toBeInTheDocument(); }); it('should use specified edit URL if in annotation', async () => { @@ -124,7 +124,7 @@ describe('CatalogTable component', () => { }, }; - const { getByTitle } = await renderInTestApp( + await renderInTestApp( @@ -137,7 +137,7 @@ describe('CatalogTable component', () => { }, ); - const editButton = getByTitle('Edit'); + const editButton = screen.getByTitle('Edit'); await act(async () => { fireEvent.click(editButton); @@ -156,7 +156,7 @@ describe('CatalogTable component', () => { }, }; - const { getByTitle } = await renderInTestApp( + await renderInTestApp( @@ -169,7 +169,7 @@ describe('CatalogTable component', () => { }, ); - const viewButton = getByTitle('View'); + const viewButton = screen.getByTitle('View'); await act(async () => { fireEvent.click(viewButton); @@ -278,7 +278,7 @@ describe('CatalogTable component', () => { ])( 'should render correct columns with kind filter $kind', async ({ kind, expectedColumns }) => { - const { getAllByRole } = await renderInTestApp( + await renderInTestApp( { }, ); - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); const columnHeaderLabels = columnHeader.map(c => c.textContent); expect(columnHeaderLabels).toEqual(expectedColumns); }, @@ -316,7 +316,7 @@ describe('CatalogTable component', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -329,7 +329,7 @@ describe('CatalogTable component', () => { }, ); - expect(getByText('Should be rendered')).toBeInTheDocument(); + expect(screen.getByText('Should be rendered')).toBeInTheDocument(); }); it('should render the label column with customised title and value as specified', async () => { @@ -347,7 +347,7 @@ describe('CatalogTable component', () => { }; const expectedColumns = ['Name', 'Category', 'Actions']; - const { getAllByRole, getByText } = await renderInTestApp( + await renderInTestApp( @@ -360,13 +360,13 @@ describe('CatalogTable component', () => { }, ); - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); + const columnHeader = screen + .getAllByRole('button') + .filter(c => c.tagName === 'SPAN'); const columnHeaderLabels = columnHeader.map(c => c.textContent); expect(columnHeaderLabels).toEqual(expectedColumns); - const labelCellValue = getByText('generic'); + const labelCellValue = screen.getByText('generic'); expect(labelCellValue).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.test.tsx b/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.test.tsx index b3f8262076..94a9a86b70 100644 --- a/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.test.tsx +++ b/plugins/catalog/src/components/DependencyOfComponentsCard/DependencyOfComponentsCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import React from 'react'; import { DependencyOfComponentsCard } from './DependencyOfComponentsCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,9 +64,9 @@ describe('', () => { }, ); - expect(getByText('Dependency of components')).toBeInTheDocument(); + expect(screen.getByText('Dependency of components')).toBeInTheDocument(); expect( - getByText(/No component depends on this component/i), + screen.getByText(/No component depends on this component/i), ).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -113,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Dependency of components')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Dependency of components')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.test.tsx b/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.test.tsx index 57106015b2..657f95c60f 100644 --- a/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.test.tsx +++ b/plugins/catalog/src/components/DependsOnComponentsCard/DependsOnComponentsCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { DependsOnComponentsCard } from './DependsOnComponentsCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,9 +64,9 @@ describe('', () => { }, ); - expect(getByText('Depends on components')).toBeInTheDocument(); + expect(screen.getByText('Depends on components')).toBeInTheDocument(); expect( - getByText(/No component is a dependency of this component/i), + screen.getByText(/No component is a dependency of this component/i), ).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -113,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Depends on components')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Depends on components')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.test.tsx b/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.test.tsx index bd52bfeeb8..5a77cd6ab4 100644 --- a/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.test.tsx +++ b/plugins/catalog/src/components/DependsOnResourcesCard/DependsOnResourcesCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { DependsOnResourcesCard } from './DependsOnResourcesCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,9 +64,9 @@ describe('', () => { }, ); - expect(getByText('Depends on resources')).toBeInTheDocument(); + expect(screen.getByText('Depends on resources')).toBeInTheDocument(); expect( - getByText(/No resource is a dependency of this component/i), + screen.getByText(/No resource is a dependency of this component/i), ).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -113,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Depends on resources')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Depends on resources')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx index 04cfa1b947..f7220cb1ea 100644 --- a/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/EntityContextMenu.test.tsx @@ -63,7 +63,7 @@ describe('ComponentContextMenu', () => { it('check Unregister entity button is disabled', async () => { const mockCallback = jest.fn(); - const { getByText } = await render( + await render( { expect(button).toBeInTheDocument(); fireEvent.click(button); - const unregister = await screen.getByText('Unregister entity'); + const unregister = screen.getByText('Unregister entity'); expect(unregister).toBeInTheDocument(); - const unregisterSpanItem = getByText(/Unregister entity/); + const unregisterSpanItem = screen.getByText(/Unregister entity/); const unregisterMenuListItem = unregisterSpanItem?.parentElement?.parentElement; expect(unregisterMenuListItem).toHaveAttribute('aria-disabled'); diff --git a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx index 95cb601ea0..fd57b79431 100644 --- a/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx +++ b/plugins/catalog/src/components/EntityContextMenu/UnregisterEntity.test.tsx @@ -60,7 +60,7 @@ describe('ComponentContextMenu', () => { it('check Unregister entity button is disabled', async () => { const mockCallback = jest.fn(); - const { getByText } = await render( + await render( { />, ); - const unregister = await screen.getByText('Unregister entity'); + const unregister = screen.getByText('Unregister entity'); expect(unregister).toBeInTheDocument(); - const unregisterSpanItem = getByText(/Unregister entity/); + const unregisterSpanItem = screen.getByText(/Unregister entity/); const unregisterMenuListItem = unregisterSpanItem?.parentElement?.parentElement; expect(unregisterMenuListItem).toHaveAttribute('aria-disabled'); diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index 548fff3ff1..980ce13109 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -32,7 +32,7 @@ import { renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; -import { act, fireEvent } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import React from 'react'; import { EntityLayout } from './EntityLayout'; @@ -52,7 +52,7 @@ const mockApis = TestApiRegistry.from( describe('EntityLayout', () => { it('renders simplest case', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( @@ -69,9 +69,9 @@ describe('EntityLayout', () => { }, ); - expect(rendered.getByText('my-entity')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); + expect(screen.getByText('my-entity')).toBeInTheDocument(); + expect(screen.getByText('tabbed-test-title')).toBeInTheDocument(); + expect(screen.getByText('tabbed-test-content')).toBeInTheDocument(); }); it('renders the entity title if defined', async () => { @@ -83,7 +83,7 @@ describe('EntityLayout', () => { }, } as Entity; - const rendered = await renderInTestApp( + await renderInTestApp( @@ -100,13 +100,13 @@ describe('EntityLayout', () => { }, ); - expect(rendered.getByText('My Entity')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); + expect(screen.getByText('My Entity')).toBeInTheDocument(); + expect(screen.getByText('tabbed-test-title')).toBeInTheDocument(); + expect(screen.getByText('tabbed-test-content')).toBeInTheDocument(); }); it('renders default error message when entity is not found', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( @@ -123,14 +123,14 @@ describe('EntityLayout', () => { }, ); - expect(rendered.getByText('Warning: Entity not found')).toBeInTheDocument(); - expect(rendered.queryByText('my-entity')).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-title')).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); + expect(screen.getByText('Warning: Entity not found')).toBeInTheDocument(); + expect(screen.queryByText('my-entity')).not.toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-title')).not.toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-content')).not.toBeInTheDocument(); }); it('renders custom message when entity is not found', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( { ); expect( - rendered.getByText('Oppps.. Your entity was not found'), + screen.getByText('Oppps.. Your entity was not found'), ).toBeInTheDocument(); - expect(rendered.queryByText('my-entity')).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-title')).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); + expect(screen.queryByText('my-entity')).not.toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-title')).not.toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-content')).not.toBeInTheDocument(); }); it('navigates when user clicks different tab', async () => { - const rendered = await renderInTestApp( + await renderInTestApp( @@ -181,23 +181,23 @@ describe('EntityLayout', () => { }, ); - const secondTab = rendered.queryAllByRole('tab')[1]; + const secondTab = screen.queryAllByRole('tab')[1]; act(() => { fireEvent.click(secondTab); }); - expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); + expect(screen.getByText('tabbed-test-title')).toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-content')).not.toBeInTheDocument(); - expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument(); + expect(screen.getByText('tabbed-test-title-2')).toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-content-2')).toBeInTheDocument(); }); it('should conditionally render tabs', async () => { const shouldRenderTab = (e: Entity) => e.metadata.name === 'my-entity'; const shouldNotRenderTab = (e: Entity) => e.metadata.name === 'some-entity'; - const rendered = await renderInTestApp( + await renderInTestApp( @@ -228,8 +228,8 @@ describe('EntityLayout', () => { }, ); - expect(rendered.queryByText('tabbed-test-title')).toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-title-2')).not.toBeInTheDocument(); - expect(rendered.queryByText('tabbed-test-title-3')).toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-title')).toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-title-2')).not.toBeInTheDocument(); + expect(screen.queryByText('tabbed-test-title-3')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.test.tsx b/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.test.tsx index 8972cd2f9e..6316bdbc85 100644 --- a/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.test.tsx +++ b/plugins/catalog/src/components/EntityLinksCard/EntityLinksCard.test.tsx @@ -17,6 +17,7 @@ import { Entity, EntityLink } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { EntityLinksCard } from './EntityLinksCard'; @@ -43,7 +44,7 @@ describe('EntityLinksCard', () => { it('should render a link', async () => { const links: EntityLink[] = [createLink()]; - const { queryByText } = await renderWithEffects( + await renderWithEffects( wrapInTestApp( @@ -51,12 +52,12 @@ describe('EntityLinksCard', () => { ), ); - expect(queryByText('admin dashboard')).toBeInTheDocument(); - expect(queryByText('derp')).not.toBeInTheDocument(); + expect(screen.queryByText('admin dashboard')).toBeInTheDocument(); + expect(screen.queryByText('derp')).not.toBeInTheDocument(); }); it('should show empty state', async () => { - const { queryByText } = await renderWithEffects( + await renderWithEffects( wrapInTestApp( @@ -65,8 +66,8 @@ describe('EntityLinksCard', () => { ); expect( - queryByText(/.*No links defined for this entity.*/), + screen.queryByText(/.*No links defined for this entity.*/), ).toBeInTheDocument(); - expect(queryByText('admin dashboard')).not.toBeInTheDocument(); + expect(screen.queryByText('admin dashboard')).not.toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/EntityLinksCard/IconLink.test.tsx b/plugins/catalog/src/components/EntityLinksCard/IconLink.test.tsx index 9c1b021071..164e54a2eb 100644 --- a/plugins/catalog/src/components/EntityLinksCard/IconLink.test.tsx +++ b/plugins/catalog/src/components/EntityLinksCard/IconLink.test.tsx @@ -17,13 +17,13 @@ import { lightTheme } from '@backstage/theme'; import { ThemeProvider } from '@material-ui/core'; import CloudIcon from '@material-ui/icons/Cloud'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { IconLink } from './IconLink'; describe('IconLink', () => { it('should render an icon link', () => { - const rendered = render( + render( { , ); - expect(rendered.queryByText('I am Link')).toBeInTheDocument(); + expect(screen.queryByText('I am Link')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx index 4f16078eb9..6f214dc1e0 100644 --- a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx +++ b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx @@ -16,13 +16,16 @@ import React from 'react'; import { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import { EntityNotFound } from './EntityNotFound'; describe('', () => { it('renders without exploding', async () => { - const { getByText } = await renderInTestApp(); - expect(getByText(/entity was not found/i)).toBeInTheDocument(); - expect(getByText(/getting started documentation/i)).toBeInTheDocument(); - expect(getByText(/docs/i)).toBeInTheDocument(); + await renderInTestApp(); + expect(screen.getByText(/entity was not found/i)).toBeInTheDocument(); + expect( + screen.getByText(/getting started documentation/i), + ).toBeInTheDocument(); + expect(screen.getByText(/docs/i)).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.test.tsx b/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.test.tsx index f00474868f..6071d15166 100644 --- a/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.test.tsx +++ b/plugins/catalog/src/components/EntityOrphanWarning/EntityOrphanWarning.test.tsx @@ -15,8 +15,8 @@ */ import { catalogApiRef, EntityProvider } from '@backstage/plugin-catalog-react'; - import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { rootRouteRef } from '../../routes'; import { EntityOrphanWarning } from './EntityOrphanWarning'; @@ -39,7 +39,7 @@ describe('', () => { }, }; - const { getByText } = await renderInTestApp( + await renderInTestApp( ', () => { }, ); expect( - getByText( + screen.getByText( 'This entity is not referenced by any location and is therefore not receiving updates. Click here to delete.', ), ).toBeInTheDocument(); diff --git a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.test.tsx b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.test.tsx index 2297493a7a..cfe3022261 100644 --- a/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.test.tsx +++ b/plugins/catalog/src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.test.tsx @@ -23,6 +23,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { EntityProcessingErrorsPanel } from './EntityProcessingErrorsPanel'; @@ -100,7 +101,7 @@ describe('', () => { rootEntityRef: stringifyEntityRef(entity), items: [{ entity, parentEntityRefs: [] }], }); - const { getByText, queryByText } = await renderInTestApp( + await renderInTestApp( @@ -109,14 +110,14 @@ describe('', () => { ); expect( - getByText( + screen.getByText( 'Error: Policy check failed; caused by Error: Malformed envelope, /metadata/labels should be object', ), ).toBeInTheDocument(); - expect(getByText('Error: Foo')).toBeInTheDocument(); - expect(queryByText('Error: This should not be rendered')).toBeNull(); + expect(screen.getByText('Error: Foo')).toBeInTheDocument(); + expect(screen.queryByText('Error: This should not be rendered')).toBeNull(); expect( - queryByText('The error below originates from'), + screen.queryByText('The error below originates from'), ).not.toBeInTheDocument(); }); @@ -204,7 +205,7 @@ describe('', () => { { entity: parent, parentEntityRefs: [] }, ], }); - const { getByText, queryByText } = await renderInTestApp( + await renderInTestApp( @@ -218,12 +219,14 @@ describe('', () => { ); expect( - getByText( + screen.getByText( 'Error: Policy check failed; caused by Error: Malformed envelope, /metadata/labels should be object', ), ).toBeInTheDocument(); - expect(getByText('Error: Foo')).toBeInTheDocument(); - expect(queryByText('Error: This should not be rendered')).toBeNull(); - expect(queryByText('The error below originates from')).toBeInTheDocument(); + expect(screen.getByText('Error: Foo')).toBeInTheDocument(); + expect(screen.queryByText('Error: This should not be rendered')).toBeNull(); + expect( + screen.queryByText('The error below originates from'), + ).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx b/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx index 4ee9d9c820..d2c51465b5 100644 --- a/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx +++ b/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx @@ -19,7 +19,7 @@ import { AsyncEntityProvider, EntityProvider, } from '@backstage/plugin-catalog-react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { isKind } from './conditions'; import { EntitySwitch } from './EntitySwitch'; @@ -54,9 +54,9 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); - expect(rendered.queryByText('C')).not.toBeInTheDocument(); + expect(screen.queryByText('A')).toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); + expect(screen.queryByText('C')).not.toBeInTheDocument(); rendered.rerender( @@ -68,9 +68,9 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); - expect(rendered.queryByText('B')).toBeInTheDocument(); - expect(rendered.queryByText('C')).not.toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); + expect(screen.queryByText('B')).toBeInTheDocument(); + expect(screen.queryByText('C')).not.toBeInTheDocument(); rendered.rerender( @@ -82,9 +82,9 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); - expect(rendered.queryByText('C')).toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); + expect(screen.queryByText('C')).toBeInTheDocument(); rendered.rerender( @@ -94,9 +94,9 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); - expect(rendered.queryByText('C')).toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); + expect(screen.queryByText('C')).toBeInTheDocument(); }); it('should switch child when filters switch', () => { @@ -113,8 +113,8 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); + expect(screen.queryByText('A')).toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); rendered.rerender( @@ -127,15 +127,15 @@ describe('EntitySwitch', () => { , ); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); - expect(rendered.queryByText('B')).toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); + expect(screen.queryByText('B')).toBeInTheDocument(); }); it('should switch with async condition that is true', async () => { const entity = { metadata: { name: 'mock' }, kind: 'component' } as Entity; const shouldRender = () => Promise.resolve(true); - const rendered = render( + render( @@ -146,15 +146,15 @@ describe('EntitySwitch', () => { , ); - await expect(rendered.findByText('A')).resolves.toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); + await expect(screen.findByText('A')).resolves.toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); }); it('should switch with sync condition that is false', async () => { const entity = { metadata: { name: 'mock' }, kind: 'component' } as Entity; const shouldRender = () => Promise.resolve(false); - const rendered = render( + render( @@ -165,15 +165,15 @@ describe('EntitySwitch', () => { , ); - await expect(rendered.findByText('B')).resolves.toBeInTheDocument(); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); + await expect(screen.findByText('B')).resolves.toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); }); it('should switch with sync condition that throws', async () => { const entity = { metadata: { name: 'mock' }, kind: 'component' } as Entity; const shouldRender = () => Promise.reject(); - const rendered = render( + render( @@ -185,8 +185,8 @@ describe('EntitySwitch', () => { , ); - await expect(rendered.findByText('C')).resolves.toBeInTheDocument(); - expect(rendered.queryByText('A')).not.toBeInTheDocument(); - expect(rendered.queryByText('B')).not.toBeInTheDocument(); + await expect(screen.findByText('C')).resolves.toBeInTheDocument(); + expect(screen.queryByText('A')).not.toBeInTheDocument(); + expect(screen.queryByText('B')).not.toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.test.tsx b/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.test.tsx index 77fdb74f2f..9d46f2ed42 100644 --- a/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.test.tsx +++ b/plugins/catalog/src/components/HasComponentsCard/HasComponentsCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { HasComponentsCard } from './HasComponentsCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,9 +64,9 @@ describe('', () => { }, ); - expect(getByText('Has components')).toBeInTheDocument(); + expect(screen.getByText('Has components')).toBeInTheDocument(); expect( - getByText(/No component is part of this system/i), + screen.getByText(/No component is part of this system/i), ).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -113,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Has components')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Has components')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.test.tsx b/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.test.tsx index 20830d2ccd..364d503a96 100644 --- a/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.test.tsx +++ b/plugins/catalog/src/components/HasResourcesCard/HasResourcesCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { HasResourcesCard } from './HasResourcesCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -59,9 +59,9 @@ describe('', () => { , ); - expect(getByText('Has resources')).toBeInTheDocument(); + expect(screen.getByText('Has resources')).toBeInTheDocument(); expect( - getByText(/No resource is part of this system/i), + screen.getByText(/No resource is part of this system/i), ).toBeInTheDocument(); }); @@ -94,7 +94,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -108,8 +108,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Has resources')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Has resources')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.test.tsx b/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.test.tsx index 7fd0273939..b76a0a68ec 100644 --- a/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.test.tsx +++ b/plugins/catalog/src/components/HasSubcomponentsCard/HasSubcomponentsCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { HasSubcomponentsCard } from './HasSubcomponentsCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,9 +64,9 @@ describe('', () => { }, ); - expect(getByText('Has subcomponents')).toBeInTheDocument(); + expect(screen.getByText('Has subcomponents')).toBeInTheDocument(); expect( - getByText(/No subcomponent is part of this component/i), + screen.getByText(/No subcomponent is part of this component/i), ).toBeInTheDocument(); }); @@ -99,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -113,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Has subcomponents')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Has subcomponents')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.test.tsx b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.test.tsx index cd11e4d3f3..634fe57e82 100644 --- a/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.test.tsx +++ b/plugins/catalog/src/components/HasSystemsCard/HasSystemsCard.test.tsx @@ -22,7 +22,7 @@ import { entityRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import React from 'react'; import { HasSystemsCard } from './HasSystemsCard'; @@ -51,7 +51,7 @@ describe('', () => { relations: [], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -64,8 +64,10 @@ describe('', () => { }, ); - expect(getByText('Has systems')).toBeInTheDocument(); - expect(getByText(/No system is part of this domain/i)).toBeInTheDocument(); + expect(screen.getByText('Has systems')).toBeInTheDocument(); + expect( + screen.getByText(/No system is part of this domain/i), + ).toBeInTheDocument(); }); it('shows related systems', async () => { @@ -97,7 +99,7 @@ describe('', () => { ], }); - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -111,8 +113,8 @@ describe('', () => { ); await waitFor(() => { - expect(getByText('Has systems')).toBeInTheDocument(); - expect(getByText(/target-name/i)).toBeInTheDocument(); + expect(screen.getByText('Has systems')).toBeInTheDocument(); + expect(screen.getByText(/target-name/i)).toBeInTheDocument(); }); }); }); diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx index 18b45a84d4..dc8d68e2b2 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx @@ -22,6 +22,7 @@ import { } from '@backstage/plugin-catalog-react'; import { Entity, RELATION_PART_OF } from '@backstage/catalog-model'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; import React from 'react'; import { SystemDiagramCard } from './SystemDiagramCard'; @@ -53,7 +54,7 @@ describe('', () => { relations: [], }; - const { queryByText } = await renderInTestApp( + await renderInTestApp( @@ -66,9 +67,9 @@ describe('', () => { }, ); - expect(queryByText(/System Diagram/)).toBeInTheDocument(); - expect(queryByText(/namespace2\/system2/)).toBeInTheDocument(); - expect(queryByText(/namespace\/entity/)).not.toBeInTheDocument(); + expect(screen.queryByText(/System Diagram/)).toBeInTheDocument(); + expect(screen.queryByText(/namespace2\/system2/)).toBeInTheDocument(); + expect(screen.queryByText(/namespace\/entity/)).not.toBeInTheDocument(); }); it('shows related systems', async () => { @@ -108,7 +109,7 @@ describe('', () => { ], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -121,9 +122,9 @@ describe('', () => { }, ); - expect(getByText('System Diagram')).toBeInTheDocument(); - expect(getByText('namespace/system')).toBeInTheDocument(); - expect(getByText('namespace/entity')).toBeInTheDocument(); + expect(screen.getByText('System Diagram')).toBeInTheDocument(); + expect(screen.getByText('namespace/system')).toBeInTheDocument(); + expect(screen.getByText('namespace/entity')).toBeInTheDocument(); }); it('should truncate long domains, systems or entities', async () => { @@ -163,7 +164,7 @@ describe('', () => { ], }; - const { getByText } = await renderInTestApp( + await renderInTestApp( @@ -176,8 +177,8 @@ describe('', () => { }, ); - expect(getByText('namespace/alongdomai...')).toBeInTheDocument(); - expect(getByText('namespace/alongsyste...')).toBeInTheDocument(); - expect(getByText('namespace/alongentit...')).toBeInTheDocument(); + expect(screen.getByText('namespace/alongdomai...')).toBeInTheDocument(); + expect(screen.getByText('namespace/alongsyste...')).toBeInTheDocument(); + expect(screen.getByText('namespace/alongentit...')).toBeInTheDocument(); }); }); diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index e394418c24..f510d1a5e0 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-cicd-statistics@0.1.13 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.13-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 5f6d5039bf..fab5380e3e 100644 --- a/plugins/cicd-statistics-module-gitlab/package.json +++ b/plugins/cicd-statistics-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics-module-gitlab", "description": "CI/CD Statistics plugin module; Gitlab CICD", - "version": "0.1.7-next.0", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 29852c597f..f0df35a027 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-cicd-statistics +## 0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 5cfac4666e..372523e3e0 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics", "description": "A frontend plugin visualizing CI/CD pipeline statistics (build time)", - "version": "0.1.13-next.0", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index b9d916f75a..5f15c999ea 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-circleci +## 0.3.11 + +### Patch Changes + +- 383574c49b: Update screenshots in documentation to match latest CircleCI plugin +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index d5f36ba7d6..1ed7c46c5f 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.3.11-next.0", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -63,7 +63,7 @@ "@types/humanize-duration": "^3.25.1", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index bc83c46375..e4d781ad9e 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-cloudbuild +## 0.3.11 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index ee2cf54177..b314dced56 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.3.11-next.0", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 20965a33a5..38475bbe01 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-code-climate +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 735c5d2c5e..de4584b972 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-code-climate", - "version": "0.1.11-next.0", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 251cfa1b33..f8d3263602 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-code-coverage-backend +## 0.2.4 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/code-coverage-backend/README.md b/plugins/code-coverage-backend/README.md index 4cfc187a3d..ae6021b07c 100644 --- a/plugins/code-coverage-backend/README.md +++ b/plugins/code-coverage-backend/README.md @@ -2,6 +2,68 @@ This is the backend part of the `code-coverage` plugin. It takes care of processing various coverage formats and standardizing them into a single json format, used by the frontend. +## Installation + +`yarn workspace backend add @backstage/plugin-code-coverage-backend` + +First create a `codecoverage.ts` file here: `packages/backend/src/plugins`. Now add the following as its content: + +```diff +diff --git a/packages/backend/src/plugins/codecoverage.ts b/packages/backend/src/plugins/codecoverage.ts +--- /dev/null ++++ b/packages/backend/src/plugins/codecoverage.ts +@@ -0,0 +1,15 @@ ++import { createRouter } from '@backstage/plugin-code-coverage-backend'; ++import { Router } from 'express'; ++import { PluginEnvironment } from '../types'; ++ ++export default async function createPlugin( ++ env: PluginEnvironment, ++): Promise { ++ return await createRouter({ ++ config: env.config, ++ discovery: env.discovery, ++ database: env.database, ++ urlReader: env.reader, ++ logger: env.logger, ++ }); ++} + +``` + +Finally we need to load the plugin in `packages/backend/src/index.ts`, make the following edits: + +```diff +diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts +--- a/packages/backend/src/index.ts ++++ b/packages/backend/src/index.ts +@@ -28,6 +28,7 @@ import scaffolder from './plugins/scaffolder'; + import proxy from './plugins/proxy'; + import techdocs from './plugins/techdocs'; + import search from './plugins/search'; ++import codeCoverage from './plugins/codecoverage'; + import { PluginEnvironment } from './types'; + import { ServerPermissionClient } from '@backstage/plugin-permission-node'; + import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; +@@ -85,6 +86,9 @@ async function main() { + const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const searchEnv = useHotMemoize(module, () => createEnv('search')); + const appEnv = useHotMemoize(module, () => createEnv('app')); ++ const codeCoverageEnv = useHotMemoize(module, () => ++ createEnv('code-coverage'), ++ ); + + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)); +@@ -93,6 +97,7 @@ async function main() { + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv)); + apiRouter.use('/search', await search(searchEnv)); ++ apiRouter.use('/code-coverage', await codeCoverage(codeCoverageEnv)); + + apiRouter.use(notFoundHandler()); +``` + ## Configuring your entity In order to use this plugin, you must set the `backstage.io/code-coverage` annotation. diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 70be7268cf..0f0fff44eb 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.2.4-next.0", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/cli": "workspace:^", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6", "xml2js": "^0.4.23" }, diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 5ccbf4eed0..883657fa3a 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-code-coverage +## 0.2.4 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/code-coverage/README.md b/plugins/code-coverage/README.md index 8903668507..ce793a78d3 100644 --- a/plugins/code-coverage/README.md +++ b/plugins/code-coverage/README.md @@ -2,6 +2,31 @@ This is the frontend part of the code-coverage plugin. It displays code coverage summaries for your entities. +## Installation + +`yarn workspace app add @backstage/plugin-code-coverage` + +Finally you need to import and render the code coverage entity, in `packages/app/src/components/catalog/EntityPage.tsx` add the following: + +```diff +@@ -70,6 +70,7 @@ import { + + import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; + import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; ++import { EntityCodeCoverageContent } from '@backstage/plugin-code-coverage'; + +@@ -226,6 +227,10 @@ const defaultEntityPage = ( + + {techdocsContent} + ++ ++ ++ ++ + + ); +``` + ## Configuring your entity In order to use this plugin, you must set the `backstage.io/code-coverage` annotation on entities for which coverage ingestion has been enabled. diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 647c7d2fb0..5e4807021b 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.2.4-next.0", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index d21ec8c71d..1c2257a73f 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-codescene +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index ffd297e8ed..f18267e5bc 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.6-next.0", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 6d62429875..54b71795d3 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-config-schema +## 0.1.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.1.34-next.0 ### Patch Changes diff --git a/plugins/config-schema/dev/example-schema.json b/plugins/config-schema/dev/example-schema.json index bb90595340..0b96fdbe0a 100644 --- a/plugins/config-schema/dev/example-schema.json +++ b/plugins/config-schema/dev/example-schema.json @@ -19,12 +19,6 @@ "visibility": "frontend", "description": "The title of the app." }, - "googleAnalyticsTrackingId": { - "type": "string", - "visibility": "frontend", - "description": "Tracking ID for Google Analytics", - "examples": ["UA-000000-0"] - }, "listen": { "type": "object", "description": "Listening configuration for local development", @@ -665,7 +659,7 @@ "type": "object", "properties": { "rules": { - "description": "Rules to apply to all catalog entities, from any location.\n\nAn undefined list of matchers means match all, an empty list of\nmatchers means match none.\n\nThis is commonly used to put in what amounts to a whitelist of kinds\nthat regular users of Backstage are permitted to register locations\nfor. This can be used to stop them from registering yaml files\ndescribing for example a Group entity called \"admin\" that they make\nthemselves members of, or similar.", + "description": "Rules to apply to all catalog entities, from any location.\n\nAn undefined list of matchers means match all, an empty list of\nmatchers means match none.\n\nThis is commonly used to put in what amounts to an allowlist of kinds\nthat regular users of Backstage are permitted to register locations\nfor. This can be used to stop them from registering yaml files\ndescribing for example a Group entity called \"admin\" that they make\nthemselves members of, or similar.", "type": "array", "items": { "type": "object", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index b111738405..c2ed4e49f7 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.34-next.0", + "version": "0.1.34", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "@material-ui/lab": "4.0.0-alpha.57", "jsonschema": "^1.2.6", "react-use": "^17.2.4", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" @@ -49,7 +49,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index ce062fa7e1..b57115bf77 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-cost-insights +## 0.12.0 + +### Minor Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- cbe11d1e23: Tweak README +- 745e0e2228: Added support for displaying entity cost insights by implementing the new `getCatalogEntityDailyCost` that's part of the `CostInsightsApi`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + +## 0.12.0-next.1 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + ## 0.12.0-next.0 ### Minor Changes diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index f50f0b0c81..dd4e404450 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -267,6 +267,10 @@ export type CostInsightsApi = { getLastCompleteBillingDate(): Promise; getUserGroups(userId: string): Promise; getGroupProjects(group: string): Promise; + getCatalogEntityDailyCost?( + catalogEntityRef: string, + intervals: string, + ): Promise; getGroupDailyCost(group: string, intervals: string): Promise; getProjectDailyCost(project: string, intervals: string): Promise; getDailyMetricData(metric: string, intervals: string): Promise; @@ -404,11 +408,19 @@ export const EngineerThreshold = 0.5; // @public @deprecated (undocumented) export type Entity = common.Entity; +// @public +export const EntityCostInsightsContent: () => JSX.Element; + // @public (undocumented) export class ExampleCostInsightsClient implements CostInsightsApi { // (undocumented) getAlerts(group: string): Promise; // (undocumented) + getCatalogEntityDailyCost( + entityRef: string, + intervals: string, + ): Promise; + // (undocumented) getDailyMetricData(metric: string, intervals: string): Promise; // (undocumented) getGroupDailyCost(group: string, intervals: string): Promise; diff --git a/plugins/cost-insights/dev/index.tsx b/plugins/cost-insights/dev/index.tsx index 4be788427a..622abaffc9 100644 --- a/plugins/cost-insights/dev/index.tsx +++ b/plugins/cost-insights/dev/index.tsx @@ -23,7 +23,26 @@ import { CostInsightsPage, CostInsightsProjectGrowthInstructionsPage, CostInsightsLabelDataflowInstructionsPage, + EntityCostInsightsContent, } from '../src/plugin'; +import { Content, Header, Page } from '@backstage/core-components'; +import { Grid } from '@material-ui/core'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; + +const mockEntity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + }, + spec: { + lifecycle: 'production', + type: 'service', + owner: 'user:guest', + }, +}; createDevApp() .registerPlugin(costInsightsPlugin) @@ -44,4 +63,22 @@ createDevApp() title: 'Labelling', element: , }) + .addPage({ + title: 'Entity', + element: ( + +
+ + + + + + + + + + + + ), + }) .render(); diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index b5859fa886..3ef57bf70b 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.12.0-next.0", + "version": "0.12.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,6 +36,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-cost-insights-common": "workspace:^", "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", @@ -71,9 +72,9 @@ "@types/recharts": "^1.8.14", "@types/regression": "^2.0.0", "@types/yup": "^0.29.13", - "canvas": "^2.6.1", + "canvas": "^2.10.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/cost-insights/src/api/CostInsightsApi.ts b/plugins/cost-insights/src/api/CostInsightsApi.ts index 3c97407f08..a7065a04aa 100644 --- a/plugins/cost-insights/src/api/CostInsightsApi.ts +++ b/plugins/cost-insights/src/api/CostInsightsApi.ts @@ -77,6 +77,29 @@ export type CostInsightsApi = { */ getGroupProjects(group: string): Promise; + /** + * Get daily cost aggregations for a given catalog entity and interval time frame. + * + * The return type includes an array of daily cost aggregations as well as statistics about the + * change in cost over the intervals. Calculating these statistics requires us to bucket costs + * into two or more time periods, hence a repeating interval format rather than just a start and + * end date. + * + * The rate of change in this comparison allows teams to reason about their cost growth (or + * reduction) and compare it to metrics important to the business. + * + * Note: implementing this is only required when using the `EntityCostInsightsContent` extension. + * + * @param catalogEntityRef - A reference to the catalog entity, as described in + * https://backstage.io/docs/features/software-catalog/references + * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01 + * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals + */ + getCatalogEntityDailyCost?( + catalogEntityRef: string, + intervals: string, + ): Promise; + /** * Get daily cost aggregations for a given group and interval time frame. * diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx index f6463b65ed..962dc6b332 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx @@ -54,12 +54,14 @@ import { TooltipRenderer } from '../../types/Tooltip'; export type CostOverviewBreakdownChartProps = { costBreakdown: Cost[]; + responsive?: boolean; }; const LOW_COST_THRESHOLD = 0.1; export const CostOverviewBreakdownChart = ({ costBreakdown, + responsive = true, }: CostOverviewBreakdownChartProps) => { const theme = useTheme(); const classes = useStyles(theme); @@ -228,7 +230,7 @@ export const CostOverviewBreakdownChart = ({ /> diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx new file mode 100644 index 0000000000..53e1a13ebf --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { + changeOf, + MockAggregatedDailyCosts, + MockBillingDateProvider, + MockConfigProvider, + MockFilterProvider, + MockScrollProvider, + trendlineOf, +} from '../../testUtils'; +import { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider'; +import { EntityCostsCard } from './EntityCosts'; +import { TestApiProvider } from '@backstage/test-utils'; +import { CostInsightsApi, costInsightsApiRef } from '../../api'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; +import { LoadingProvider } from '../../hooks'; +import { Cost } from '@backstage/plugin-cost-insights-common'; + +function renderInContext(children: JSX.Element) { + const mockEntity = { + metadata: { name: 'mock' }, + kind: 'MockKind', + } as Entity; + const mockGroupDailyCost: Cost = { + id: 'test-group', + aggregation: MockAggregatedDailyCosts, + change: changeOf(MockAggregatedDailyCosts), + trendline: trendlineOf(MockAggregatedDailyCosts), + }; + const mockApi: jest.Mocked = { + getLastCompleteBillingDate: jest.fn().mockResolvedValue('2022-10-30'), + getUserGroups: jest.fn().mockResolvedValue(['team-a']), + getGroupProjects: jest.fn().mockResolvedValue(['project-a', 'project-b']), + getCatalogEntityDailyCost: jest.fn().mockResolvedValue(mockGroupDailyCost), + getGroupDailyCost: jest.fn().mockResolvedValue({}), + getProjectDailyCost: jest.fn().mockResolvedValue({}), + getDailyMetricData: jest.fn().mockResolvedValue({}), + getProductInsights: jest.fn().mockResolvedValue({}), + getAlerts: jest.fn().mockResolvedValue({}), + }; + + return renderInTestApp( + + + + + + + + {children} + + + + + + + , + ); +} + +describe('', () => { + beforeEach(() => { + // @ts-expect-error: Since we have strictNullChecks enabled, this will throw an error as window.ResizeObserver + // it's not an optional operand + delete window.ResizeObserver; + window.ResizeObserver = jest.fn().mockImplementation(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), + })); + }); + + afterEach(() => { + window.ResizeObserver = ResizeObserver; + jest.restoreAllMocks(); + }); + + it('Renders without exploding', async () => { + const { getByText } = await renderInContext(); + expect(getByText('Cloud Cost')).toBeInTheDocument(); + }); +}); diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx new file mode 100644 index 0000000000..9dda1c65e3 --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx @@ -0,0 +1,161 @@ +/* + * Copyright 2022 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, { useCallback, useEffect, useState } from 'react'; +import { CostOverviewCard } from '../CostOverviewCard'; +import { + BillingDateProvider, + ConfigProvider, + CurrencyProvider, + FilterProvider, + GroupsProvider, + LoadingProvider, + ScrollProvider, + useFilters, + useLastCompleteBillingDate, + useLoading, +} from '../../hooks'; +import { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider'; +import { Progress, WarningPanel } from '@backstage/core-components'; +import { default as MaterialAlert } from '@material-ui/lab/Alert'; +import { mapLoadingToProps } from '../CostInsightsPage/selector'; +import { intervalsOf } from '../../utils/duration'; +import { costInsightsApiRef } from '../../api'; +import { useApi } from '@backstage/core-plugin-api'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { Cost, Maybe } from '@backstage/plugin-cost-insights-common'; +import { stringifyEntityRef } from '@backstage/catalog-model'; + +export const EntityCostsCard = () => { + const client = useApi(costInsightsApiRef); + const { entity } = useEntity(); + + const { + loadingActions, + loadingGroups, + loadingBillingDate, + loadingInitial, + dispatchInitial, + dispatchInsights, + dispatchNone, + } = useLoading(mapLoadingToProps); + + /* eslint-disable react-hooks/exhaustive-deps */ + // The dispatchLoading functions are derived from loading state using mapLoadingToProps, to + // provide nicer props for the component. These are re-derived whenever loading state changes, + // which causes an infinite loop as product panels load and re-trigger the useEffect below. + // Since the functions don't change, we can memoize - but we trigger the same loop if we satisfy + // exhaustive-deps by including the function itself in dependencies. + + const dispatchLoadingInitial = useCallback(dispatchInitial, []); + const dispatchLoadingInsights = useCallback(dispatchInsights, []); + const dispatchLoadingNone = useCallback(dispatchNone, []); + /* eslint-enable react-hooks/exhaustive-deps */ + + const lastCompleteBillingDate = useLastCompleteBillingDate(); + const [dailyCost, setDailyCost] = useState>(null); + const [error, setError] = useState>(null); + const { pageFilters } = useFilters(p => p); + + useEffect(() => { + async function getInsights() { + setError(null); + try { + dispatchLoadingInsights(true); + const intervals = intervalsOf( + pageFilters.duration, + lastCompleteBillingDate, + ); + + const fetchedDailyCost = await client.getCatalogEntityDailyCost!( + stringifyEntityRef(entity), + intervals, + ); + setDailyCost(fetchedDailyCost); + } catch (e) { + setError(e); + dispatchLoadingNone(loadingActions); + } finally { + dispatchLoadingNone(loadingActions); + dispatchLoadingInitial(false); + dispatchLoadingInsights(false); + } + } + + // Wait for metadata to finish loading + if (!loadingBillingDate) { + getInsights(); + } + }, [ + client, + entity, + pageFilters, + loadingActions, + loadingGroups, + loadingBillingDate, + dispatchLoadingInsights, + dispatchLoadingInitial, + dispatchLoadingNone, + lastCompleteBillingDate, + ]); + + if (loadingInitial) { + return ; + } + + if (error) { + return {error.message}; + } + + if (!dailyCost) { + return No daily costs; + } + + return ; +}; + +export const EntityCosts = () => { + const client = useApi(costInsightsApiRef); + + if (!client.getCatalogEntityDailyCost) { + return ( + + ); + } + + return ( + + + + + + + + + + + + + + + + + + ); +}; diff --git a/plugins/cost-insights/src/components/EntityCosts/index.ts b/plugins/cost-insights/src/components/EntityCosts/index.ts new file mode 100644 index 0000000000..b8d5106090 --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { EntityCosts } from './EntityCosts'; diff --git a/plugins/cost-insights/src/example/client.ts b/plugins/cost-insights/src/example/client.ts index 9c3e20c2b3..e2a183b682 100644 --- a/plugins/cost-insights/src/example/client.ts +++ b/plugins/cost-insights/src/example/client.ts @@ -92,6 +92,29 @@ export class ExampleCostInsightsClient implements CostInsightsApi { return cost; } + async getCatalogEntityDailyCost( + entityRef: string, + intervals: string, + ): Promise { + const aggregation = aggregationFor(intervals, 8_000); + const groupDailyCost: Cost = await this.request( + { entityRef, intervals }, + { + aggregation: aggregation, + change: changeOf(aggregation), + trendline: trendlineOf(aggregation), + // Optional field providing cost groupings / breakdowns keyed by the type. In this example, + // daily cost grouped by cloud product OR by project / billing account. + groupedCosts: { + product: getGroupedProducts(intervals), + project: getGroupedProjects(intervals), + }, + }, + ); + + return groupDailyCost; + } + async getGroupDailyCost(group: string, intervals: string): Promise { const aggregation = aggregationFor(intervals, 8_000); const groupDailyCost: Cost = await this.request( diff --git a/plugins/cost-insights/src/example/templates/CostInsightsClient.ts b/plugins/cost-insights/src/example/templates/CostInsightsClient.ts index fc68eb62c7..50c3bb1470 100644 --- a/plugins/cost-insights/src/example/templates/CostInsightsClient.ts +++ b/plugins/cost-insights/src/example/templates/CostInsightsClient.ts @@ -87,6 +87,17 @@ export class CostInsightsClient implements CostInsightsApi { } } + async getCatalogEntityDailyCost(catalogEntityRef: string, intervals: string): Promise { + return { + id: 'remove-me', + aggregation: [], + change: { + ratio: 0, + amount: 0 + } + } + } + async getProductInsights(options: ProductInsightsOptions): Promise { return { id: 'remove-me', diff --git a/plugins/cost-insights/src/index.ts b/plugins/cost-insights/src/index.ts index 2c46156005..8a17b1bf43 100644 --- a/plugins/cost-insights/src/index.ts +++ b/plugins/cost-insights/src/index.ts @@ -24,6 +24,7 @@ export { costInsightsPlugin, costInsightsPlugin as plugin, CostInsightsPage, + EntityCostInsightsContent, CostInsightsProjectGrowthInstructionsPage, CostInsightsLabelDataflowInstructionsPage, } from './plugin'; diff --git a/plugins/cost-insights/src/plugin.ts b/plugins/cost-insights/src/plugin.ts index 789d803438..04d58d1877 100644 --- a/plugins/cost-insights/src/plugin.ts +++ b/plugins/cost-insights/src/plugin.ts @@ -53,6 +53,20 @@ export const CostInsightsPage = costInsightsPlugin.provide( }), ); +/** + * An extension for displaying costs on an entity page. + * + * @public + */ +export const EntityCostInsightsContent = costInsightsPlugin.provide( + createRoutableExtension({ + name: 'EntityCostInsightsContent', + component: () => + import('./components/EntityCosts').then(m => m.EntityCosts), + mountPoint: rootRouteRef, + }), +); + /** @public */ export const CostInsightsProjectGrowthInstructionsPage = costInsightsPlugin.provide( diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 4ab45e9df6..4d4b9a232b 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-dynatrace +## 1.0.1 + +### Patch Changes + +- cbe11d1e23: Tweak README +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 1.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 1.0.1-next.0 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index bdd54bf865..b5b3af417a 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "1.0.1-next.0", + "version": "1.0.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "express": "^4.18.1", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/dynatrace/src/components/Synthetics/SyntheticsLocation/SyntheticsLocation.test.tsx b/plugins/dynatrace/src/components/Synthetics/SyntheticsLocation/SyntheticsLocation.test.tsx index de04f73e36..6d772efc9b 100644 --- a/plugins/dynatrace/src/components/Synthetics/SyntheticsLocation/SyntheticsLocation.test.tsx +++ b/plugins/dynatrace/src/components/Synthetics/SyntheticsLocation/SyntheticsLocation.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React from 'react'; import { SyntheticsLocation } from './SyntheticsLocation'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; @@ -60,6 +61,6 @@ describe('SyntheticsLocation', () => { , ); expect(await rendered.findByText(/__location__/)).toBeInTheDocument(); - expect(await rendered.queryByText(/failed/)).not.toBeInTheDocument(); + expect(rendered.queryByText(/failed/)).not.toBeInTheDocument(); }); }); diff --git a/plugins/events-backend-module-aws-sqs/.eslintrc.js b/plugins/events-backend-module-aws-sqs/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md new file mode 100644 index 0000000000..8dfa896528 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -0,0 +1,23 @@ +# @backstage/plugin-events-backend-module-aws-sqs + +## 0.1.0 + +### Minor Changes + +- d3ecb2382d: Adds a new module `aws-sqs` for plugin-events-backend. + + The module provides an event publisher `AwsSqsConsumingEventPublisher` + which will allow you to receive events from + an AWS SQS queue and will publish these to the used event broker. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-events-node@0.1.0 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 diff --git a/plugins/events-backend-module-aws-sqs/README.md b/plugins/events-backend-module-aws-sqs/README.md new file mode 100644 index 0000000000..cb3a5045c0 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/README.md @@ -0,0 +1,42 @@ +# events-backend-module-aws-sqs + +Welcome to the `events-backend-module-aws-sqs` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `AwsSqsConsumingEventPublisher`. + +This event publisher will allow you to receive events from +an AWS SQS queue and will publish these to the used event broker. + +## Configuration + +The polled AWS SQS queues depend on your configuration: + +```yaml +events: + modules: + awsSqs: + awsSqsConsumingEventPublisher: + topics: + topicName1: # replace with actual topic name as expected by subscribers + queue: + url: 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue' + region: us-east-2 + # visibilityTimeout - as HumanDuration; defaults to queue-based config + # waitTime - as HumanDuration; defaults to max of 20 seconds (long polling) + # timeout - as HumanDuration; timeout for the task execution + # waitTimeAfterEmptyReceive - as HumanDuration; time to wait before a retry when there was no message. + topicName2: + # [...] +``` + +## Installation + +1. Install the [`events-backend` plugin](../events-backend/README.md). +2. Install this module +3. Add your configuration. + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-aws-sqs +``` diff --git a/plugins/events-backend-module-aws-sqs/api-report.md b/plugins/events-backend-module-aws-sqs/api-report.md new file mode 100644 index 0000000000..79a422c9f3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/api-report.md @@ -0,0 +1,29 @@ +## API Report File for "@backstage/plugin-events-backend-module-aws-sqs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { EventBroker } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; + +// @public +export class AwsSqsConsumingEventPublisher implements EventPublisher { + // (undocumented) + static fromConfig(env: { + config: Config; + logger: Logger; + scheduler: PluginTaskScheduler; + }): AwsSqsConsumingEventPublisher[]; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @alpha +export const awsSqsConsumingEventPublisherEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-aws-sqs/config.d.ts b/plugins/events-backend-module-aws-sqs/config.d.ts new file mode 100644 index 0000000000..dfef35bf22 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/config.d.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2022 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 { HumanDuration } from '@backstage/types'; + +export interface Config { + events?: { + modules?: { + /** + * events-backend-module-aws-sqs plugin configuration. + */ + awsSqs?: { + /** + * Configuration for AwsSqsConsumingEventPublisher. + */ + awsSqsConsumingEventPublisher?: { + /** + * Contains a record per topic for which an AWS SQS queue + * should be used as source of events. + */ + topics: Record< + string, + { + /** + * (Required) Queue-related configuration. + */ + queue: { + /** + * (Required) The region of the AWS SQS queue. + */ + region: string; + /** + * (Required) The absolute URL for the AWS SQS queue to be used. + */ + url: string; + /** + * (Optional) Visibility timeout for messages in flight. + */ + visibilityTimeout: HumanDuration; + /** + * (Optional) Wait time when polling for available messages. + * Default: 20 seconds. + */ + waitTime: HumanDuration; + }; + /** + * (Optional) Timeout for the task execution which includes polling for messages + * and publishing the events to the event broker + * and the wait time after empty receives. + * + * Must be greater than `queue.waitTime` + `waitTimeAfterEmptyReceive`. + */ + timeout: HumanDuration; + /** + * (Optional) Wait time before polling again if no message was received. + * Default: 1 minute. + */ + waitTimeAfterEmptyReceive: HumanDuration; + } + >; + }; + }; + }; + }; +} diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json new file mode 100644 index 0000000000..096e77b66c --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-events-backend-module-aws-sqs", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@aws-sdk/client-sqs": "^3.0.0", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/types": "workspace:^", + "luxon": "^3.0.0", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "aws-sdk-client-mock": "^2.0.0" + }, + "files": [ + "alpha", + "config.d.ts", + "dist" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/events-backend-module-aws-sqs/src/index.ts b/plugins/events-backend-module-aws-sqs/src/index.ts new file mode 100644 index 0000000000..73b950856b --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "sqs" for the Backstage backend plugin "events" + * adding an AWS SQS-based publisher, + * receiving events from an AWS SQS queue and passing it to the + * internal event broker. + * + * @packageDocumentation + */ + +export { AwsSqsConsumingEventPublisher } from './publisher/AwsSqsConsumingEventPublisher'; +export { awsSqsConsumingEventPublisherEventsModule } from './service/AwsSqsConsumingEventPublisherEventsModule'; diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts new file mode 100644 index 0000000000..e32245b483 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts @@ -0,0 +1,227 @@ +/* + * Copyright 2022 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 { + DeleteMessageBatchCommand, + ReceiveMessageCommand, + SQSClient, +} from '@aws-sdk/client-sqs'; +import { getVoidLogger } from '@backstage/backend-common'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { ConfigReader } from '@backstage/config'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { mockClient } from 'aws-sdk-client-mock'; +import { AwsSqsConsumingEventPublisher } from './AwsSqsConsumingEventPublisher'; + +describe('AwsSqsConsumingEventPublisher', () => { + it('creates one publisher instance per configured topic', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + const scheduler = { + scheduleTask: jest.fn(), + } as unknown as PluginTaskScheduler; + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(2); + }); + + it('polling will be scheduled after connecting to the EventBroker', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + const scheduler = { + scheduleTask: jest.fn(), + } as unknown as PluginTaskScheduler; + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(1); + + const publisher = publishers[0]; + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + // publisher.connect(..) was causing the polling for events to be scheduled + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'events.awsSqs.publisher:fake1', + frequency: { seconds: 0 }, + timeout: { seconds: 260 }, + scope: 'local', + }), + ); + }); + + it('publishes events for received messages and deletes them in bulk', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + waitTimeAfterEmptyReceive: { seconds: 1 }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + let taskFn: (() => Promise) | undefined = undefined; + const scheduler = { + scheduleTask: (spec: { fn: () => Promise }) => { + taskFn = spec.fn; + }, + } as unknown as PluginTaskScheduler; + + // on the first attempt, we will return 1 message and 0 messages afterwards + const sqsMock = mockClient(SQSClient); + sqsMock + .on(ReceiveMessageCommand, { + MaxNumberOfMessages: 10, + QueueUrl: 'https://fake1.queue.url', + WaitTimeSeconds: 20, + }) + .resolvesOnce({ + Messages: [], + }) + .resolvesOnce({ + Messages: [ + { + Body: '{"event":"payload1"}', + ReceiptHandle: 'fake-handle1', + MessageAttributes: { + 'X-Custom-Attr': { + DataType: 'String', + StringValue: 'value', + }, + }, + }, + { + Body: '{"event":"payload2"}', + ReceiptHandle: 'fake-handle2', + }, + ], + }) + .on(DeleteMessageBatchCommand, { + Entries: [ + { + Id: 'message-0', + ReceiptHandle: 'fake-handle1', + }, + { + Id: 'message-1', + ReceiptHandle: 'fake-handle2', + }, + ], + QueueUrl: 'https://fake1.queue.url', + }) + .resolvesOnce({ + Failed: [ + { + Id: 'message-1', + Message: 'test failure', + SenderFault: true, + Code: '400', + }, + ], + Successful: [{ Id: 'message-0' }], + }); + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(1); + const publisher = publishers[0]; + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + await taskFn!(); + await taskFn!(); + await taskFn!(); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('fake1'); + expect(eventBroker.published[0].eventPayload).toEqual({ + event: 'payload1', + }); + expect(eventBroker.published[0].metadata).toEqual({ + 'X-Custom-Attr': 'value', + }); + + expect(eventBroker.published[1].topic).toEqual('fake1'); + expect(eventBroker.published[1].eventPayload).toEqual({ + event: 'payload2', + }); + expect(eventBroker.published[1].metadata).toEqual({}); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts new file mode 100644 index 0000000000..4638769c45 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -0,0 +1,191 @@ +/* + * Copyright 2022 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 { + DeleteMessageBatchCommand, + Message, + ReceiveMessageCommand, + ReceiveMessageCommandInput, + SQSClient, +} from '@aws-sdk/client-sqs'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { Config } from '@backstage/config'; +import { EventBroker, EventPublisher } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { AwsSqsEventSourceConfig, readConfig } from './config'; + +/** + * Publishes events received from an AWS SQS queue. + * The message payload will be used as event payload and passed to registered subscribers. + * + * @public + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class AwsSqsConsumingEventPublisher implements EventPublisher { + private readonly topic: string; + private readonly receiveParams: ReceiveMessageCommandInput; + private readonly sqs: SQSClient; + private readonly queueUrl: string; + private readonly taskTimeoutSeconds: number; + private readonly waitTimeAfterEmptyReceiveMs; + private eventBroker?: EventBroker; + + static fromConfig(env: { + config: Config; + logger: Logger; + scheduler: PluginTaskScheduler; + }): AwsSqsConsumingEventPublisher[] { + return readConfig(env.config).map( + config => + new AwsSqsConsumingEventPublisher(env.logger, env.scheduler, config), + ); + } + + private constructor( + private readonly logger: Logger, + private readonly scheduler: PluginTaskScheduler, + config: AwsSqsEventSourceConfig, + ) { + this.topic = config.topic; + + this.receiveParams = { + MaxNumberOfMessages: 10, + MessageAttributeNames: ['All'], + QueueUrl: config.queueUrl, + VisibilityTimeout: config.visibilityTimeout?.as('seconds'), + WaitTimeSeconds: config.pollingWaitTime.as('seconds'), + }; + this.sqs = new SQSClient({ region: config.region }); + this.queueUrl = config.queueUrl; + + this.taskTimeoutSeconds = config.timeout.as('seconds'); + this.waitTimeAfterEmptyReceiveMs = + config.waitTimeAfterEmptyReceive.as('milliseconds'); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + return this.start(); + } + + private async start(): Promise { + const id = `events.awsSqs.publisher:${this.topic}`; + const logger = this.logger.child({ + class: AwsSqsConsumingEventPublisher.prototype.constructor.name, + taskId: id, + }); + + await this.scheduler.scheduleTask({ + id: id, + frequency: { seconds: 0 }, + timeout: { seconds: this.taskTimeoutSeconds }, + scope: 'local', + fn: async () => { + try { + const numMessages = await this.consumeMessages(); + if (numMessages === 0) { + await this.sleep(this.waitTimeAfterEmptyReceiveMs); + } + } catch (error) { + logger.error(error); + } + }, + }); + } + + private async deleteMessages(messages?: Message[]): Promise { + if (!messages) { + return; + } + + const deleteParams = { + QueueUrl: this.queueUrl, + Entries: messages.map((message, index) => { + return { + Id: message.MessageId ?? `message-${index}`, + ReceiptHandle: message.ReceiptHandle, + }; + }), + }; + + try { + const result = await this.sqs.send( + new DeleteMessageBatchCommand(deleteParams), + ); + if (result.Failed) { + this.logger.error( + `Failed to delete ${result.Failed!.length} of ${ + messages.length + } messages from AWS SQS ${this.queueUrl}. First: ${ + result.Failed[0].Message + }`, + ); + } + } catch (error) { + this.logger.error( + `Failed to delete message from AWS SQS ${this.queueUrl}`, + error, + ); + } + } + + private async consumeMessages(): Promise { + try { + const data = await this.sqs.send( + new ReceiveMessageCommand(this.receiveParams), + ); + + data.Messages?.forEach(message => { + const eventPayload = JSON.parse(message.Body!); + + const metadata: Record = {}; + Object.keys(message.MessageAttributes ?? {}).forEach(key => { + const attrValue = message.MessageAttributes![key]; + if ( + !attrValue || + !attrValue.DataType || + !['String', 'Number'].includes(attrValue.DataType) + ) { + return; + } + + const value = attrValue.StringListValues ?? attrValue.StringValue; + if (value !== undefined) { + metadata[key] = value; + } + }); + + this.eventBroker!.publish({ + topic: this.topic, + eventPayload, + metadata, + }); + }); + await this.deleteMessages(data.Messages); + return data.Messages?.length ?? 0; + } catch (error) { + this.logger.error( + `Failed to receive events from AWS SQS ${this.queueUrl}`, + error, + ); + return 0; + } + } + + private sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } +} diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts b/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts new file mode 100644 index 0000000000..1fa9df4ce3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts @@ -0,0 +1,222 @@ +/* + * Copyright 2022 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 { ConfigReader } from '@backstage/config'; +import { readConfig } from './config'; + +describe('readConfig', () => { + it('not configured', () => { + const config = new ConfigReader({}); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(0); + }); + + it('only required fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(2); + + expect(publisherConfigs[0].topic).toEqual('fake1'); + expect(publisherConfigs[0].region).toEqual('eu-west-1'); + expect(publisherConfigs[0].queueUrl).toEqual('https://fake1.queue.url'); + expect(publisherConfigs[0].pollingWaitTime.as('seconds')).toBe(20); + expect(publisherConfigs[0].timeout.as('seconds')).toBe(260); + expect(publisherConfigs[0].waitTimeAfterEmptyReceive.as('seconds')).toBe( + 60, + ); + }); + + it('all fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(1); + + expect(publisherConfigs[0].topic).toEqual('fake1'); + expect(publisherConfigs[0].region).toEqual('eu-west-1'); + expect(publisherConfigs[0].queueUrl).toEqual('https://fake1.queue.url'); + expect(publisherConfigs[0].pollingWaitTime.as('seconds')).toBe(10); + expect(publisherConfigs[0].timeout.as('seconds')).toBe(300); + expect(publisherConfigs[0].waitTimeAfterEmptyReceive.as('seconds')).toBe( + 30, + ); + }); + + it('fail on negative queue.waitTime', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: -10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime must be within 0..20 seconds', + ); + }); + + it('fail on too high queue.waitTime', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 30 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime must be within 0..20 seconds', + ); + }); + + it('fail on too low timeout', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { seconds: 10 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'The events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.timeout must be greater than events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime', + ); + }); + + it('fail on negative waitTimeAfterEmptyReceive', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: -30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'The events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.waitTimeAfterEmptyReceive must not be negative', + ); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/config.ts b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts new file mode 100644 index 0000000000..c6b74ea8d3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2022 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 { Config } from '@backstage/config'; +import { HumanDuration, JsonObject } from '@backstage/types'; +import { Duration } from 'luxon'; + +const CONFIG_PREFIX_MODULE = 'events.modules.awsSqs.'; +const CONFIG_PREFIX_PUBLISHER = `${CONFIG_PREFIX_MODULE}awsSqsConsumingEventPublisher.`; +const DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE = { minutes: 1 }; +const MAX_WAIT_SECONDS = 20; + +export interface AwsSqsEventSourceConfig { + pollingWaitTime: Duration; + queueUrl: string; + region: string; + timeout: Duration; + topic: string; + visibilityTimeout?: Duration; + waitTimeAfterEmptyReceive: Duration; +} + +// TODO(pjungermann): validation could be improved similar to `convertToHumanDuration` at @backstage/backend-tasks +function readOptionalHumanDuration( + config: Config, + key: string, +): HumanDuration | undefined { + return config.getOptional(key) as HumanDuration; +} + +function readOptionalDuration( + config: Config, + key: string, +): Duration | undefined { + const duration = readOptionalHumanDuration(config, key); + return duration ? Duration.fromObject(duration) : undefined; +} + +export function readConfig(config: Config): AwsSqsEventSourceConfig[] { + const key = `${CONFIG_PREFIX_PUBLISHER}topics`; + const topics = config.getOptionalConfig(key); + + return ( + topics?.keys()?.map(topic => { + const topicConfig = topics.getConfig(topic); + const keyPrefix = `${key}.${topic}.`; + + // queue config: + const pollingWaitTime = Duration.fromObject( + readOptionalHumanDuration(topicConfig, 'queue.waitTime') ?? { + seconds: MAX_WAIT_SECONDS, + }, + ); + if ( + pollingWaitTime.valueOf() < 0 || + pollingWaitTime.as('seconds') > MAX_WAIT_SECONDS + ) { + throw new Error( + `${keyPrefix}queue.waitTime must be within 0..${MAX_WAIT_SECONDS} seconds.`, + ); + } + const queueUrl = topicConfig.getString('queue.url'); + const region = topicConfig.getString('queue.region'); + const visibilityTimeout = readOptionalDuration( + topicConfig, + 'queue.visibilityTimeout', + ); + + // task: + const waitTimeAfterEmptyReceive = Duration.fromObject( + readOptionalHumanDuration(topicConfig, 'waitTimeAfterEmptyReceive') ?? + DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE, + ); + if (waitTimeAfterEmptyReceive.valueOf() < 0) { + throw new Error( + `The ${keyPrefix}waitTimeAfterEmptyReceive must not be negative.`, + ); + } + const timeout = + readOptionalDuration(topicConfig, 'timeout') ?? + pollingWaitTime + .plus(waitTimeAfterEmptyReceive) + .plus(Duration.fromObject({ seconds: 180 })); + if ( + timeout.valueOf() <= + pollingWaitTime.valueOf() + waitTimeAfterEmptyReceive.valueOf() + ) { + throw new Error( + `The ${keyPrefix}timeout must be greater than ${keyPrefix}queue.waitTime + ${keyPrefix}waitTimeAfterEmptyReceive.`, + ); + } + + return { + pollingWaitTime, + queueUrl, + region, + timeout, + topic, + visibilityTimeout, + waitTimeAfterEmptyReceive, + }; + }) ?? [] + ); +} diff --git a/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts new file mode 100644 index 0000000000..584b62a2c6 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright 2022 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 { getVoidLogger } from '@backstage/backend-common'; +import { + configServiceRef, + loggerServiceRef, + schedulerServiceRef, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { awsSqsConsumingEventPublisherEventsModule } from './AwsSqsConsumingEventPublisherEventsModule'; +import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher'; + +describe('awsSqsEventsModule', () => { + it('should be correctly wired and set up', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + + let addedPublishers: AwsSqsConsumingEventPublisher[] | undefined; + const extensionPoint = { + addPublishers: (publishers: any) => { + addedPublishers = publishers; + }, + }; + + const scheduler = { + scheduleTask: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [ + [configServiceRef, config], + [loggerServiceRef, getVoidLogger()], + [schedulerServiceRef, scheduler], + ], + features: [awsSqsConsumingEventPublisherEventsModule()], + }); + + expect(addedPublishers).not.toBeUndefined(); + expect(addedPublishers!.length).toEqual(2); + + const eventBroker = new TestEventBroker(); + await Promise.all( + addedPublishers!.map(publisher => publisher.setEventBroker(eventBroker)), + ); + + // publisher.connect(..) was causing the polling for events to be scheduled + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ id: 'events.awsSqs.publisher:fake1' }), + ); + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ id: 'events.awsSqs.publisher:fake2' }), + ); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts new file mode 100644 index 0000000000..7c33d7baae --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 { + configServiceRef, + createBackendModule, + loggerServiceRef, + loggerToWinstonLogger, + schedulerServiceRef, +} from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher'; + +/** + * AWS SQS module for the Events plugin. + * + * @alpha + */ +export const awsSqsConsumingEventPublisherEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'awsSqsConsumingEventPublisherEventsModule', + register(env) { + env.registerInit({ + deps: { + config: configServiceRef, + events: eventsExtensionPoint, + logger: loggerServiceRef, + scheduler: schedulerServiceRef, + }, + async init({ config, events, logger, scheduler }) { + const winstonLogger = loggerToWinstonLogger(logger); + const sqs = AwsSqsConsumingEventPublisher.fromConfig({ + config: config, + logger: winstonLogger, + scheduler: scheduler, + }); + + events.addPublishers(sqs); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-aws-sqs/src/setupTests.ts b/plugins/events-backend-module-aws-sqs/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-azure/.eslintrc.js b/plugins/events-backend-module-azure/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-azure/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md new file mode 100644 index 0000000000..14a06976b0 --- /dev/null +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-events-backend-module-azure + +## 0.1.0 + +### Minor Changes + +- 12cd94b7e9: Adds a new module `azure` to plugin-events-backend. + + The module adds a new event router `AzureDevOpsEventRouter`. + + The event router will re-publish events received at topic `azureDevOps` + under a more specific topic depending on their `$.eventType` value + (e.g., `azureDevOps.git.push`). + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-azure/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-backend-module-azure/README.md b/plugins/events-backend-module-azure/README.md new file mode 100644 index 0000000000..d16315b6e7 --- /dev/null +++ b/plugins/events-backend-module-azure/README.md @@ -0,0 +1,43 @@ +# events-backend-module-azure + +Welcome to the `events-backend-module-azure` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `AzureDevOpsEventRouter`. + +The event router will subscribe to the topic `azureDevOps` +and route the events to more concrete topics based on the value +of the provided `$.eventType` payload field. + +Examples: + +| `$.eventType` | topic | +| ------------------------- | ------------------------------------- | +| `git.push` | `azureDevOps.git.push` | +| `git.pullrequest.created` | `azureDevOps.git.pullrequest.created` | + +Please find all possible webhook event types at the +[official documentation of events](https://learn.microsoft.com/en-us/azure/devops/service-hooks/events?source=recommendations&view=azure-devops) +and [webhooks](https://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-azure +``` + +Add the event router to the `EventsBackend`: + +```diff ++const githubEventRouter = new AzureDevOpsEventRouter(); + + EventsBackend ++ .addPublishers(githubEventRouter) ++ .addSubscribers(githubEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-azure/api-report.md b/plugins/events-backend-module-azure/api-report.md new file mode 100644 index 0000000000..510ec91c47 --- /dev/null +++ b/plugins/events-backend-module-azure/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-azure" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class AzureDevOpsEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const azureDevOpsEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json new file mode 100644 index 0000000000..fee8e9117c --- /dev/null +++ b/plugins/events-backend-module-azure/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-azure", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-azure/src/index.ts b/plugins/events-backend-module-azure/src/index.ts new file mode 100644 index 0000000000..9a83f751f6 --- /dev/null +++ b/plugins/events-backend-module-azure/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "azure" for the Backstage backend plugin "events-backend" + * adding an event router for Azure DevOps. + * + * @packageDocumentation + */ + +export { AzureDevOpsEventRouter } from './router/AzureDevOpsEventRouter'; +export { azureDevOpsEventRouterEventsModule } from './service/AzureDevOpsEventRouterEventsModule'; diff --git a/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts new file mode 100644 index 0000000000..56e761a8fc --- /dev/null +++ b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2022 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { AzureDevOpsEventRouter } from './AzureDevOpsEventRouter'; + +describe('AzureDevOpsEventRouter', () => { + const eventRouter = new AzureDevOpsEventRouter(); + const topic = 'azureDevOps'; + const eventPayload = { eventType: 'test.type', test: 'payload' }; + const metadata = {}; + + it('no $.eventType', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.eventType', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('azureDevOps.test.type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts new file mode 100644 index 0000000000..11dd7546dd --- /dev/null +++ b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `azureDevOps` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.eventType` provided. + * + * @public + */ +export class AzureDevOpsEventRouter extends SubTopicEventRouter { + constructor() { + super('azureDevOps'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('eventType' in (params.eventPayload as object)) { + const payload = params.eventPayload as { eventType: string }; + return payload.eventType; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..86ab7ea17d --- /dev/null +++ b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { azureDevOpsEventRouterEventsModule } from './AzureDevOpsEventRouterEventsModule'; +import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; + +describe('azureDevOpsEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: AzureDevOpsEventRouter | undefined; + let addedSubscriber: AzureDevOpsEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [azureDevOpsEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(AzureDevOpsEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(AzureDevOpsEventRouter); + }); +}); diff --git a/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts new file mode 100644 index 0000000000..1219452bd8 --- /dev/null +++ b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Azure DevOps. + * + * Registers the {@link AzureDevOpsEventRouter}. + * + * @alpha + */ +export const azureDevOpsEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'azureDevOpsEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new AzureDevOpsEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-azure/src/setupTests.ts b/plugins/events-backend-module-azure/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-azure/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js b/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md new file mode 100644 index 0000000000..11a2ade858 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-events-backend-module-bitbucket-cloud + +## 0.1.0 + +### Minor Changes + +- 6bc121bf0d: Adds a new module `bitbucket-cloud` to plugin-events-backend. + + The module adds a new event router `BitbucketCloudEventRouter`. + + The event router will re-publish events received at topic `bitbucketCloud` + under a more specific topic depending on their `x-event-key` value + (e.g., `bitbucketCloud.repo:push`). + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-bitbucket-cloud/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-backend-module-bitbucket-cloud/README.md b/plugins/events-backend-module-bitbucket-cloud/README.md new file mode 100644 index 0000000000..c58529ed7a --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/README.md @@ -0,0 +1,43 @@ +# events-backend-module-bitbucket-cloud + +Welcome to the `events-backend-module-bitbucket-cloud` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `BitbucketCloudEventRouter`. + +The event router will subscribe to the topic `bitbucketCloud` +and route the events to more concrete topics based on the value +of the provided `x-event-key` metadata field. + +Examples: + +| x-event-key | topic | +| --------------------- | ------------------------------------ | +| `repo:push` | `bitbucketCloud.repo:push` | +| `repo:updated` | `bitbucketCloud.repo:updated` | +| `pullrequest:created` | `bitbucketCloud.pullrequest:created` | + +Please find all possible webhook event types at the +[official documentation](https://support.atlassian.com/bitbucket-cloud/docs/event-payloads/). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-bitbucket-cloud +``` + +Add the event router to the `EventsBackend`: + +```diff ++const bitbucketCloudEventRouter = new BitbucketCloudEventRouter(); + + EventsBackend ++ .addPublishers(bitbucketCloudEventRouter) ++ .addSubscribers(bitbucketCloudEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-bitbucket-cloud/api-report.md b/plugins/events-backend-module-bitbucket-cloud/api-report.md new file mode 100644 index 0000000000..0e4acfac91 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-bitbucket-cloud" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class BitbucketCloudEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const bitbucketCloudEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json new file mode 100644 index 0000000000..8b431a2453 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-bitbucket-cloud/src/index.ts b/plugins/events-backend-module-bitbucket-cloud/src/index.ts new file mode 100644 index 0000000000..0a58212de2 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "bitbucket-cloud" for the Backstage backend plugin "events-backend" + * adding an event router for Bitbucket Cloud. + * + * @packageDocumentation + */ + +export { BitbucketCloudEventRouter } from './router/BitbucketCloudEventRouter'; +export { bitbucketCloudEventRouterEventsModule } from './service/BitbucketCloudEventRouterEventsModule'; diff --git a/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts new file mode 100644 index 0000000000..b7a47984e4 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { BitbucketCloudEventRouter } from './BitbucketCloudEventRouter'; + +describe('BitbucketCloudEventRouter', () => { + const eventRouter = new BitbucketCloudEventRouter(); + const topic = 'bitbucketCloud'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-event-key': 'test:type' }; + + it('no x-event-key', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with x-event-key', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('bitbucketCloud.test:type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts new file mode 100644 index 0000000000..8350511d65 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2022 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `bitbucketCloud` topic + * and publishes the events under the more concrete sub-topic + * depending on the `x-event-key` provided. + * + * @public + */ +export class BitbucketCloudEventRouter extends SubTopicEventRouter { + constructor() { + super('bitbucketCloud'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-event-key'] as string | undefined; + } +} diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..e456607a2b --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { bitbucketCloudEventRouterEventsModule } from './BitbucketCloudEventRouterEventsModule'; +import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; + +describe('bitbucketCloudEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: BitbucketCloudEventRouter | undefined; + let addedSubscriber: BitbucketCloudEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [bitbucketCloudEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(BitbucketCloudEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(BitbucketCloudEventRouter); + }); +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts new file mode 100644 index 0000000000..7f755a28f4 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Bitbucket Cloud. + * + * Registers the {@link BitbucketCloudEventRouter}. + * + * @alpha + */ +export const bitbucketCloudEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'bitbucketCloudEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new BitbucketCloudEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts b/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-gerrit/.eslintrc.js b/plugins/events-backend-module-gerrit/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-gerrit/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md new file mode 100644 index 0000000000..a97bab9ea4 --- /dev/null +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-events-backend-module-gerrit + +## 0.1.0 + +### Minor Changes + +- 25f6d7bddb: Adds a new module `gerrit` to plugin-events-backend. + + The module adds a new event router `GerritEventRouter`. + + The event router will re-publish events received at topic `gerrit` + under a more specific topic depending on their `$.type` value + (e.g., `gerrit.change-merged`). + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-gerrit/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-backend-module-gerrit/README.md b/plugins/events-backend-module-gerrit/README.md new file mode 100644 index 0000000000..933b7a172f --- /dev/null +++ b/plugins/events-backend-module-gerrit/README.md @@ -0,0 +1,42 @@ +# events-backend-module-gerrit + +Welcome to the `events-backend-module-gerrit` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GerritEventRouter`. + +The event router will subscribe to the topic `gerrit` +and route the events to more concrete topics based on the value +of the provided `$.type` payload field. + +Examples: + +| `$.type` | topic | +| ---------------- | ----------------------- | +| `change-created` | `gerrit.change-created` | +| `change-merged` | `gerrit.change-merged` | + +Please find all possible webhook event types at the +[official documentation](https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-gerrit +``` + +Add the event router to the `EventsBackend`: + +```diff ++const gerritEventRouter = new GerritEventRouter(); + + EventsBackend ++ .addPublishers(gerritEventRouter) ++ .addSubscribers(gerritEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-gerrit/api-report.md b/plugins/events-backend-module-gerrit/api-report.md new file mode 100644 index 0000000000..268e5970fa --- /dev/null +++ b/plugins/events-backend-module-gerrit/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-gerrit" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GerritEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const gerritEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json new file mode 100644 index 0000000000..7ec4eda0ec --- /dev/null +++ b/plugins/events-backend-module-gerrit/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-gerrit", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-gerrit/src/index.ts b/plugins/events-backend-module-gerrit/src/index.ts new file mode 100644 index 0000000000..1a9ebb03ee --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module `gerrit` for the Backstage backend plugin "events-backend" + * adding an event router for Gerrit. + * + * @packageDocumentation + */ + +export { GerritEventRouter } from './router/GerritEventRouter'; +export { gerritEventRouterEventsModule } from './service/GerritEventRouterEventsModule'; diff --git a/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts new file mode 100644 index 0000000000..7302a26012 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2022 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GerritEventRouter } from './GerritEventRouter'; + +describe('GerritEventRouter', () => { + const eventRouter = new GerritEventRouter(); + const topic = 'gerrit'; + const eventPayload = { type: 'test-type', test: 'payload' }; + const metadata = {}; + + it('no $.type', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.type', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('gerrit.test-type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts new file mode 100644 index 0000000000..3d97508b62 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `gerrit` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.type` field provided. + * + * @public + */ +export class GerritEventRouter extends SubTopicEventRouter { + constructor() { + super('gerrit'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('type' in (params.eventPayload as object)) { + const payload = params.eventPayload as { type: string }; + return payload.type; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..b5fd6a80ca --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { gerritEventRouterEventsModule } from './GerritEventRouterEventsModule'; +import { GerritEventRouter } from '../router/GerritEventRouter'; + +describe('gerritEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GerritEventRouter | undefined; + let addedSubscriber: GerritEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [gerritEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GerritEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GerritEventRouter); + }); +}); diff --git a/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts new file mode 100644 index 0000000000..734b574edd --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GerritEventRouter } from '../router/GerritEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Gerrit. + * + * Registers the {@link GerritEventRouter}. + * + * @alpha + */ +export const gerritEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'gerritEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GerritEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-gerrit/src/setupTests.ts b/plugins/events-backend-module-gerrit/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-github/.eslintrc.js b/plugins/events-backend-module-github/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-github/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md new file mode 100644 index 0000000000..2de9725228 --- /dev/null +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-events-backend-module-github + +## 0.1.0 + +### Minor Changes + +- b3a4edb885: Adds a new module `github` to plugin-events-backend. + + The module adds a new event router `GithubEventRouter`. + + The event router will re-publish events received at topic `github` + under a more specific topic depending on their `x-github-event` value + (e.g., `github.push`). + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-backend-module-github/README.md b/plugins/events-backend-module-github/README.md new file mode 100644 index 0000000000..b111b79dd0 --- /dev/null +++ b/plugins/events-backend-module-github/README.md @@ -0,0 +1,43 @@ +# events-backend-module-github + +Welcome to the `events-backend-module-github` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GithubEventRouter`. + +The event router will subscribe to the topic `github` +and route the events to more concrete topics based on the value +of the provided `x-github-event` metadata field. + +Examples: + +| `x-github-event` | topic | +| ---------------- | --------------------- | +| `pull_request` | `github.pull_request` | +| `push` | `github.push` | +| `repository` | `github.repository` | + +Please find all possible webhook event types at the +[official documentation](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-github +``` + +Add the event router to the `EventsBackend`: + +```diff ++const githubEventRouter = new GithubEventRouter(); + + EventsBackend ++ .addPublishers(githubEventRouter) ++ .addSubscribers(githubEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-github/api-report.md b/plugins/events-backend-module-github/api-report.md new file mode 100644 index 0000000000..25ce30523a --- /dev/null +++ b/plugins/events-backend-module-github/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-github" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GithubEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const githubEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json new file mode 100644 index 0000000000..3449a9d9e9 --- /dev/null +++ b/plugins/events-backend-module-github/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-github", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-github/src/index.ts b/plugins/events-backend-module-github/src/index.ts new file mode 100644 index 0000000000..672d82e6dc --- /dev/null +++ b/plugins/events-backend-module-github/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module `github` for the Backstage backend plugin "events-backend" + * adding an event router for GitHub. + * + * @packageDocumentation + */ + +export { GithubEventRouter } from './router/GithubEventRouter'; +export { githubEventRouterEventsModule } from './service/GithubEventRouterEventsModule'; diff --git a/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts b/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts new file mode 100644 index 0000000000..14cf6b9933 --- /dev/null +++ b/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GithubEventRouter } from './GithubEventRouter'; + +describe('GithubEventRouter', () => { + const eventRouter = new GithubEventRouter(); + const topic = 'github'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-github-event': 'test_type' }; + + it('no x-github-event', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with x-github-event', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('github.test_type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-github/src/router/GithubEventRouter.ts b/plugins/events-backend-module-github/src/router/GithubEventRouter.ts new file mode 100644 index 0000000000..10dd1c55c6 --- /dev/null +++ b/plugins/events-backend-module-github/src/router/GithubEventRouter.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2022 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `github` topic + * and publishes the events under the more concrete sub-topic + * depending on the `x-github-event` provided. + * + * @public + */ +export class GithubEventRouter extends SubTopicEventRouter { + constructor() { + super('github'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-github-event'] as string | undefined; + } +} diff --git a/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..694f5e1dbe --- /dev/null +++ b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { githubEventRouterEventsModule } from './GithubEventRouterEventsModule'; +import { GithubEventRouter } from '../router/GithubEventRouter'; + +describe('githubEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GithubEventRouter | undefined; + let addedSubscriber: GithubEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [githubEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GithubEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GithubEventRouter); + }); +}); diff --git a/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts new file mode 100644 index 0000000000..8914d07e71 --- /dev/null +++ b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GithubEventRouter } from '../router/GithubEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for GitHub. + * + * Registers the {@link GithubEventRouter}. + * + * @alpha + */ +export const githubEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'githubEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GithubEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-github/src/setupTests.ts b/plugins/events-backend-module-github/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-github/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-gitlab/.eslintrc.js b/plugins/events-backend-module-gitlab/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-gitlab/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md new file mode 100644 index 0000000000..9f8f4798f6 --- /dev/null +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-events-backend-module-gitlab + +## 0.1.0 + +### Minor Changes + +- 63f7983398: Adds a new module `gitlab` to plugin-events-backend. + + The module adds a new event router `GitlabEventRouter`. + + The event router will re-publish events received at topic `gitlab` + under a more specific topic depending on their `$.event_name` value + (e.g., `gitlab.push`). + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-gitlab/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-backend-module-gitlab/README.md b/plugins/events-backend-module-gitlab/README.md new file mode 100644 index 0000000000..dfbfcd9f4a --- /dev/null +++ b/plugins/events-backend-module-gitlab/README.md @@ -0,0 +1,42 @@ +# events-backend-module-gitlab + +Welcome to the `events-backend-module-gitlab` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GitlabEventRouter`. + +The event router will subscribe to the topic `gitlab` +and route the events to more concrete topics based on the value +of the provided `$.event_name` payload field. + +Examples: + +| `$.event_name` | topic | +| --------------- | ---------------------- | +| `push` | `gitlab.push` | +| `merge_request` | `gitlab.merge_request` | + +Please find all possible webhook event types at the +[official documentation](https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-gitlab +``` + +Add the event router to the `EventsBackend`: + +```diff ++const gitlabEventRouter = new GitlabEventRouter(); + + EventsBackend ++ .addPublishers(gitlabEventRouter) ++ .addSubscribers(gitlabEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-gitlab/api-report.md b/plugins/events-backend-module-gitlab/api-report.md new file mode 100644 index 0000000000..8b5183a8d0 --- /dev/null +++ b/plugins/events-backend-module-gitlab/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-gitlab" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GitlabEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const gitlabEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json new file mode 100644 index 0000000000..c13f9b5289 --- /dev/null +++ b/plugins/events-backend-module-gitlab/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-gitlab", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-gitlab/src/index.ts b/plugins/events-backend-module-gitlab/src/index.ts new file mode 100644 index 0000000000..ea96244df4 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "gitlab" for the Backstage backend plugin "events-backend" + * adding an event router for GitLab. + * + * @packageDocumentation + */ + +export { GitlabEventRouter } from './router/GitlabEventRouter'; +export { gitlabEventRouterEventsModule } from './service/GitlabEventRouterEventsModule'; diff --git a/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts new file mode 100644 index 0000000000..6ced12d3cb --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2022 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GitlabEventRouter } from './GitlabEventRouter'; + +describe('GitlabEventRouter', () => { + const eventRouter = new GitlabEventRouter(); + const topic = 'gitlab'; + const eventPayload = { event_name: 'test_type', test: 'payload' }; + const metadata = {}; + + it('no $.event_name', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.event_name', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('gitlab.test_type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts new file mode 100644 index 0000000000..16324340ee --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `gitlab` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.event_name` field provided. + * + * @public + */ +export class GitlabEventRouter extends SubTopicEventRouter { + constructor() { + super('gitlab'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('event_name' in (params.eventPayload as object)) { + const payload = params.eventPayload as { event_name: string }; + return payload.event_name; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..f0ffca3397 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 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 { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { gitlabEventRouterEventsModule } from './GitlabEventRouterEventsModule'; +import { GitlabEventRouter } from '../router/GitlabEventRouter'; + +describe('gitlabEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GitlabEventRouter | undefined; + let addedSubscriber: GitlabEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [gitlabEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GitlabEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GitlabEventRouter); + }); +}); diff --git a/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts new file mode 100644 index 0000000000..9ab2e1263e --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GitlabEventRouter } from '../router/GitlabEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for GitLab. + * + * Registers the {@link GitlabEventRouter}. + * + * @alpha + */ +export const gitlabEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'gitlabEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GitlabEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-gitlab/src/setupTests.ts b/plugins/events-backend-module-gitlab/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-test-utils/.eslintrc.js b/plugins/events-backend-test-utils/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-test-utils/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md new file mode 100644 index 0000000000..dd881c011c --- /dev/null +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -0,0 +1,19 @@ +# @backstage/plugin-events-backend-test-utils + +## 0.1.0 + +### Minor Changes + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.1.0 diff --git a/plugins/events-backend-test-utils/README.md b/plugins/events-backend-test-utils/README.md new file mode 100644 index 0000000000..c8727b536b --- /dev/null +++ b/plugins/events-backend-test-utils/README.md @@ -0,0 +1,4 @@ +# plugin-events-backend-test-utils + +Houses implementations of plugin-events-node interfaces +which can be useful for test for events-backend and its modules. diff --git a/plugins/events-backend-test-utils/api-report.md b/plugins/events-backend-test-utils/api-report.md new file mode 100644 index 0000000000..46131c4244 --- /dev/null +++ b/plugins/events-backend-test-utils/api-report.md @@ -0,0 +1,47 @@ +## API Report File for "@backstage/plugin-events-backend-test-utils" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { EventBroker } from '@backstage/plugin-events-node'; +import { EventParams } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { EventSubscriber } from '@backstage/plugin-events-node'; + +// @public (undocumented) +export class TestEventBroker implements EventBroker { + // (undocumented) + publish(params: EventParams): Promise; + // (undocumented) + readonly published: EventParams[]; + // (undocumented) + subscribe( + ...subscribers: Array> + ): void; + // (undocumented) + readonly subscribed: EventSubscriber[]; +} + +// @public (undocumented) +export class TestEventPublisher implements EventPublisher { + // (undocumented) + get eventBroker(): EventBroker | undefined; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @public (undocumented) +export class TestEventSubscriber implements EventSubscriber { + constructor(name: string, topics: string[]); + // (undocumented) + readonly name: string; + // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + readonly receivedEvents: Record; + // (undocumented) + supportsEventTopics(): string[]; + // (undocumented) + readonly topics: string[]; +} +``` diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json new file mode 100644 index 0000000000..3265426ffd --- /dev/null +++ b/plugins/events-backend-test-utils/package.json @@ -0,0 +1,34 @@ +{ + "name": "@backstage/plugin-events-backend-test-utils", + "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "node-library" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/plugin-events-node": "workspace:^" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/events-backend-test-utils/src/index.ts b/plugins/events-backend-test-utils/src/index.ts new file mode 100644 index 0000000000..efba5be0d0 --- /dev/null +++ b/plugins/events-backend-test-utils/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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. + */ + +/** + * The events-test-utils module for `@backstage/plugin-events-node`. + * + * @packageDocumentation + */ + +export * from './testUtils'; diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts new file mode 100644 index 0000000000..c697a6506f --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2022 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 { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventBroker implements EventBroker { + readonly published: EventParams[] = []; + readonly subscribed: EventSubscriber[] = []; + + async publish(params: EventParams): Promise { + this.published.push(params); + } + + subscribe( + ...subscribers: Array> + ): void { + this.subscribed.push(...subscribers.flat()); + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts new file mode 100644 index 0000000000..c1b2038afb --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2022 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 { EventBroker, EventPublisher } from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventPublisher implements EventPublisher { + #eventBroker?: EventBroker; + + async setEventBroker(eventBroker: EventBroker): Promise { + this.#eventBroker = eventBroker; + } + + get eventBroker() { + return this.#eventBroker; + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts new file mode 100644 index 0000000000..ef5758b804 --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2022 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 { EventParams, EventSubscriber } from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventSubscriber implements EventSubscriber { + readonly name: string; + readonly topics: string[]; + + readonly receivedEvents: Record = {}; + + constructor(name: string, topics: string[]) { + this.name = name; + this.topics = topics; + } + + supportsEventTopics(): string[] { + return this.topics; + } + + async onEvent(params: EventParams): Promise { + this.receivedEvents[params.topic] = this.receivedEvents[params.topic] ?? []; + this.receivedEvents[params.topic].push(params); + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/index.ts b/plugins/events-backend-test-utils/src/testUtils/index.ts new file mode 100644 index 0000000000..a571ba3075 --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { TestEventBroker } from './TestEventBroker'; +export { TestEventPublisher } from './TestEventPublisher'; +export { TestEventSubscriber } from './TestEventSubscriber'; diff --git a/plugins/events-backend/.eslintrc.js b/plugins/events-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md new file mode 100644 index 0000000000..a86bf34d03 --- /dev/null +++ b/plugins/events-backend/CHANGELOG.md @@ -0,0 +1,35 @@ +# @backstage/plugin-events-backend + +## 0.1.0 + +### Minor Changes + +- dc9da28abd: Support events received via HTTP endpoints at plugin-events-backend. + + The plugin provides an event publisher `HttpPostIngressEventPublisher` + which will allow you to receive events via + HTTP endpoints `POST /api/events/http/{topic}` + and will publish these to the used event broker. + + Using a provided custom validator, you can participate in the decision + which events are accepted, e.g. by verifying the source of the request. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-events-node@0.1.0 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/config@1.0.4 diff --git a/plugins/events-backend/README.md b/plugins/events-backend/README.md new file mode 100644 index 0000000000..f71df21517 --- /dev/null +++ b/plugins/events-backend/README.md @@ -0,0 +1,210 @@ +# events-backend + +Welcome to the events-backend backend plugin! + +This plugin provides the wiring of all extension points +for managing events as defined by [plugin-events-node](../events-node) +including backend plugin `EventsPlugin` and `EventsBackend`. + +Additionally, it uses a simple in-memory implementation for +the `EventBroker` by default which you can replace with a more sophisticated +implementation of your choice as you need (e.g., via module). + +Some of these (non-exhaustive) may provide added persistence, +or use external systems like AWS EventBridge, AWS SNS, Kafka, etc. + +By default, the plugin ships with support to receive events via HTTP endpoints +`POST /api/events/http/{topic}` and will publish these +to the used event broker. + +## Installation + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend +``` + +Add a file [`packages/backend/src/plugins/events.ts`](../../packages/backend/src/plugins/events.ts) +to your Backstage project. + +There, you can add all publishers, subscribers, etc. you want. + +Additionally, add the events plugin to your backend. + +```diff +// packages/backend/src/index.ts +// [...] ++import events from './plugins/events'; +// [...] ++ const eventsEnv = useHotMemoize(module, () => createEnv('events')); +// [...] ++ apiRouter.use('/events', await events(eventsEnv, [])); +// [...] +``` + +### With Event-based Entity Providers + +In case you use event-based `EntityProviders`, +you may need something like the following: + +```diff +// packages/backend/src/index.ts +- apiRouter.use('/events', await events(eventsEnv, [])); ++ apiRouter.use('/events', await events(eventsEnv, eventBasedEntityProviders)); +``` + +as well as a file +[`packages/backend/src/plugins/catalogEventBasedProviders.ts`](../../packages/backend/src/plugins/catalogEventBasedProviders.ts) +which contains event-based entity providers. + +In case you don't have this dependency added yet: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend +``` + +```diff +// packages/backend/src/plugins/catalog.ts + import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; ++import { EntityProvider } from '@backstage/plugin-catalog-node'; + import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; + + export default async function createPlugin( + env: PluginEnvironment, ++ providers?: Array, + ): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); ++ builder.addEntityProvider(providers ?? []); + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; + } +``` + +## Configuration + +In order to create HTTP endpoints to receive events for a certain +topic, you need to add them at your configuration: + +```yaml +events: + http: + topics: + - bitbucketCloud + - github + - whatever +``` + +Only those topics added to the configuration will result in +available endpoints. + +The example above would result in the following endpoints: + +``` +POST /api/events/http/bitbucketCloud +POST /api/events/http/github +POST /api/events/http/whatever +``` + +You may want to use these for webhooks by SCM providers +in combination with suitable event subscribers. + +However, it is not limited to these use cases. + +## Use Cases + +### Custom Event Broker + +Example using the `EventsBackend`: + +```ts +new EventsBackend(env.logger) + .setEventBroker(yourEventBroker) + // [...] + .start(); +``` + +Example using a module: + +```ts +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; + +// [...] + +export const yourModuleEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'yourModule', + register(env) { + // [...] + env.registerInit({ + deps: { + // [...] + events: eventsExtensionPoint, + // [...] + }, + async init({ /* ... */ events /*, ... */ }) { + // [...] + const yourEventBroker = new YourEventBroker(); + // [...] + events.setEventBroker(yourEventBroker); + }, + }); + }, +}); +``` + +### Request Validator + +Example using the `EventsBackend`: + +```ts +const http = HttpPostIngressEventPublisher.fromConfig({ + config: env.config, + ingresses: { + yourTopic: { + validator: yourValidator, + }, + }, + logger: env.logger, + router: httpRouter, +}); + +await new EventsBackend(env.logger) + .addPublishers(http) + // [...] + .start(); +``` + +Example using a module: + +```ts +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; + +// [...] + +export const yourModuleEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'yourModule', + register(env) { + // [...] + env.registerInit({ + deps: { + // [...] + events: eventsExtensionPoint, + // [...] + }, + async init({ /* ... */ events /*, ... */ }) { + // [...] + events.addHttpPostIngress({ + topic: 'your-topic', + validator: yourValidator, + }); + }, + }); + }, +}); +``` diff --git a/plugins/events-backend/api-report.md b/plugins/events-backend/api-report.md new file mode 100644 index 0000000000..4154168fa1 --- /dev/null +++ b/plugins/events-backend/api-report.md @@ -0,0 +1,48 @@ +## API Report File for "@backstage/plugin-events-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { Config } from '@backstage/config'; +import { EventBroker } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { EventSubscriber } from '@backstage/plugin-events-node'; +import express from 'express'; +import { HttpPostIngressOptions } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; + +// @public +export class EventsBackend { + constructor(logger: Logger); + // (undocumented) + addPublishers( + ...publishers: Array> + ): EventsBackend; + // (undocumented) + addSubscribers( + ...subscribers: Array> + ): EventsBackend; + // (undocumented) + setEventBroker(eventBroker: EventBroker): EventsBackend; + start(): Promise; +} + +// @alpha +export const eventsPlugin: (options?: undefined) => BackendFeature; + +// @public +export class HttpPostIngressEventPublisher implements EventPublisher { + // (undocumented) + static fromConfig(env: { + config: Config; + ingresses?: { + [topic: string]: Omit; + }; + logger: Logger; + router: express.Router; + }): HttpPostIngressEventPublisher; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} +``` diff --git a/plugins/events-backend/config.d.ts b/plugins/events-backend/config.d.ts new file mode 100644 index 0000000000..3d26661855 --- /dev/null +++ b/plugins/events-backend/config.d.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + events?: { + http?: { + /** + * Topics for which a route has to be registered + * at which we can receive events via HTTP POST requests + * (i.e. received from webhooks). + */ + topics?: string[]; + }; + }; +} diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json new file mode 100644 index 0000000000..48f02667d9 --- /dev/null +++ b/plugins/events-backend/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-events-backend", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@types/express": "^4.17.6", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "config.d.ts", + "dist" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/events-backend/src/index.ts b/plugins/events-backend/src/index.ts new file mode 100644 index 0000000000..5026729015 --- /dev/null +++ b/plugins/events-backend/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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. + */ + +/** + * The Backstage backend plugin "events" that provides the event management. + * + * @packageDocumentation + */ + +export { EventsBackend } from './service/EventsBackend'; +export { eventsPlugin } from './service/EventsPlugin'; +export { HttpPostIngressEventPublisher } from './service/http'; diff --git a/plugins/events-backend/src/service/EventsBackend.test.ts b/plugins/events-backend/src/service/EventsBackend.test.ts new file mode 100644 index 0000000000..c2041b57ac --- /dev/null +++ b/plugins/events-backend/src/service/EventsBackend.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2022 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 { getVoidLogger } from '@backstage/backend-common'; +import { + TestEventBroker, + TestEventPublisher, + TestEventSubscriber, +} from '@backstage/plugin-events-backend-test-utils'; +import { EventsBackend } from './EventsBackend'; + +const logger = getVoidLogger(); + +describe('EventsBackend', () => { + it('wires up all components', async () => { + const eventBroker = new TestEventBroker(); + const publisher1 = new TestEventPublisher(); + const publisher2 = new TestEventPublisher(); + + await new EventsBackend(logger) + .setEventBroker(eventBroker) + .addPublishers(publisher1, [publisher2]) + .addSubscribers(new TestEventSubscriber('one', ['topicA']), [ + new TestEventSubscriber('two', ['topicA', 'topicB']), + ]) + .start(); + + await eventBroker.publish({ + topic: 'topicA', + eventPayload: { test: 'payload' }, + }); + + expect(eventBroker.published.length).toEqual(1); + expect(eventBroker.published[0].topic).toEqual('topicA'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'payload' }); + + expect(eventBroker.subscribed.length).toEqual(2); + expect( + eventBroker.subscribed.map( + sub => (sub as unknown as TestEventSubscriber).name, + ), + ).toEqual(['one', 'two']); + + expect(publisher1.eventBroker).toBe(eventBroker); + expect(publisher2.eventBroker).toBe(eventBroker); + }); +}); diff --git a/plugins/events-backend/src/service/EventsBackend.ts b/plugins/events-backend/src/service/EventsBackend.ts new file mode 100644 index 0000000000..77b1b538f7 --- /dev/null +++ b/plugins/events-backend/src/service/EventsBackend.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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 { + EventBroker, + EventPublisher, + EventSubscriber, +} from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; + +/** + * A builder that helps wire up all component parts of the event management. + * + * @public + */ +export class EventsBackend { + private eventBroker: EventBroker; + private publishers: EventPublisher[] = []; + private subscribers: EventSubscriber[] = []; + + constructor(logger: Logger) { + this.eventBroker = new InMemoryEventBroker(logger); + } + + setEventBroker(eventBroker: EventBroker): EventsBackend { + this.eventBroker = eventBroker; + return this; + } + + addPublishers( + ...publishers: Array> + ): EventsBackend { + this.publishers.push(...publishers.flat()); + return this; + } + + addSubscribers( + ...subscribers: Array> + ): EventsBackend { + this.subscribers.push(...subscribers.flat()); + return this; + } + + /** + * Wires up and returns all component parts of the event management. + */ + async start(): Promise { + this.eventBroker.subscribe(this.subscribers); + this.publishers.forEach(publisher => + publisher.setEventBroker(this.eventBroker), + ); + } +} diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts new file mode 100644 index 0000000000..f58f081742 --- /dev/null +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright 2022 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 { errorHandler, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + configServiceRef, + createBackendModule, + httpRouterServiceRef, + loggerServiceRef, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { + TestEventBroker, + TestEventPublisher, + TestEventSubscriber, +} from '@backstage/plugin-events-backend-test-utils'; +import express from 'express'; +import Router from 'express-promise-router'; +import request from 'supertest'; +import { eventsPlugin } from './EventsPlugin'; + +describe('eventPlugin', () => { + it('should be initialized properly', async () => { + const eventBroker = new TestEventBroker(); + const publisher = new TestEventPublisher(); + const subscriber = new TestEventSubscriber('sub', ['fake']); + + const config = new ConfigReader({ + events: { + http: { + topics: ['fake'], + }, + }, + }); + + const httpRouter = Router(); + httpRouter.use(express.json()); + httpRouter.use(errorHandler()); + const app = express().use(httpRouter); + + const testModule = createBackendModule({ + pluginId: 'events', + moduleId: 'test', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + events.setEventBroker(eventBroker); + events.addPublishers(publisher); + events.addSubscribers(subscriber); + }, + }); + }, + }); + + await startTestBackend({ + extensionPoints: [], + services: [ + [configServiceRef, config], + [httpRouterServiceRef, httpRouter], + [loggerServiceRef, getVoidLogger()], + ], + features: [eventsPlugin(), testModule()], + }); + + expect(publisher.eventBroker).toBe(eventBroker); + expect(eventBroker.subscribed.length).toEqual(1); + expect(eventBroker.subscribed[0]).toBe(subscriber); + + const response = await request(app) + .post('/http/fake') + .timeout(100) + .send({ test: 'fake' }); + expect(response.status).toBe(202); + + expect(eventBroker.published.length).toEqual(1); + expect(eventBroker.published[0].topic).toEqual('fake'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'fake' }); + }); +}); diff --git a/plugins/events-backend/src/service/EventsPlugin.ts b/plugins/events-backend/src/service/EventsPlugin.ts new file mode 100644 index 0000000000..d5a38a7fd7 --- /dev/null +++ b/plugins/events-backend/src/service/EventsPlugin.ts @@ -0,0 +1,131 @@ +/* + * Copyright 2022 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 { + configServiceRef, + createBackendPlugin, + httpRouterServiceRef, + loggerServiceRef, + loggerToWinstonLogger, +} from '@backstage/backend-plugin-api'; +import { + EventBroker, + EventPublisher, + EventSubscriber, + eventsExtensionPoint, + EventsExtensionPoint, + HttpPostIngressOptions, +} from '@backstage/plugin-events-node'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; +import Router from 'express-promise-router'; +import { HttpPostIngressEventPublisher } from './http'; + +class EventsExtensionPointImpl implements EventsExtensionPoint { + #eventBroker: EventBroker | undefined; + #httpPostIngresses: HttpPostIngressOptions[] = []; + #publishers: EventPublisher[] = []; + #subscribers: EventSubscriber[] = []; + + setEventBroker(eventBroker: EventBroker): void { + this.#eventBroker = eventBroker; + } + + addPublishers( + ...publishers: Array> + ): void { + this.#publishers.push(...publishers.flat()); + } + + addSubscribers( + ...subscribers: Array> + ): void { + this.#subscribers.push(...subscribers.flat()); + } + + addHttpPostIngress(options: HttpPostIngressOptions) { + this.#httpPostIngresses.push(options); + } + + get eventBroker() { + return this.#eventBroker; + } + + get publishers() { + return this.#publishers; + } + + get subscribers() { + return this.#subscribers; + } + + get httpPostIngresses() { + return this.#httpPostIngresses; + } +} + +/** + * Events plugin + * + * @alpha + */ +export const eventsPlugin = createBackendPlugin({ + id: 'events', + register(env) { + const extensionPoint = new EventsExtensionPointImpl(); + env.registerExtensionPoint(eventsExtensionPoint, extensionPoint); + + env.registerInit({ + deps: { + config: configServiceRef, + httpRouter: httpRouterServiceRef, + logger: loggerServiceRef, + }, + async init({ config, httpRouter, logger }) { + const winstonLogger = loggerToWinstonLogger(logger); + const eventsRouter = Router(); + const router = Router(); + eventsRouter.use('/http', router); + + const ingresses = Object.fromEntries( + extensionPoint.httpPostIngresses.map(ingress => [ + ingress.topic, + ingress as Omit, + ]), + ); + + const http = HttpPostIngressEventPublisher.fromConfig({ + config, + logger: winstonLogger, + router, + ingresses, + }); + + if (!extensionPoint.eventBroker) { + extensionPoint.setEventBroker(new InMemoryEventBroker(winstonLogger)); + } + + extensionPoint.eventBroker!.subscribe(extensionPoint.subscribers); + [extensionPoint.publishers, http] + .flat() + .forEach(publisher => + publisher.setEventBroker(extensionPoint.eventBroker!), + ); + + httpRouter.use(eventsRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend/src/service/InMemoryEventBroker.test.ts b/plugins/events-backend/src/service/InMemoryEventBroker.test.ts new file mode 100644 index 0000000000..68a6f63a72 --- /dev/null +++ b/plugins/events-backend/src/service/InMemoryEventBroker.test.ts @@ -0,0 +1,66 @@ +/* + * Copyright 2022 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 { getVoidLogger } from '@backstage/backend-common'; +import { TestEventSubscriber } from '@backstage/plugin-events-backend-test-utils'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; + +const logger = getVoidLogger(); + +describe('InMemoryEventBroker', () => { + it('passes events to interested subscribers', () => { + const subscriber1 = new TestEventSubscriber('test1', ['topicA', 'topicB']); + const subscriber2 = new TestEventSubscriber('test2', ['topicB', 'topicC']); + const eventBroker = new InMemoryEventBroker(logger); + + eventBroker.subscribe(subscriber1); + eventBroker.subscribe(subscriber2); + eventBroker.publish({ topic: 'topicA', eventPayload: { test: 'topicA' } }); + eventBroker.publish({ topic: 'topicB', eventPayload: { test: 'topicB' } }); + eventBroker.publish({ topic: 'topicC', eventPayload: { test: 'topicC' } }); + eventBroker.publish({ topic: 'topicD', eventPayload: { test: 'topicD' } }); + + expect(Object.keys(subscriber1.receivedEvents)).toEqual([ + 'topicA', + 'topicB', + ]); + expect(subscriber1.receivedEvents.topicA.length).toEqual(1); + expect(subscriber1.receivedEvents.topicA[0]).toEqual({ + topic: 'topicA', + eventPayload: { test: 'topicA' }, + }); + expect(subscriber1.receivedEvents.topicB.length).toEqual(1); + expect(subscriber1.receivedEvents.topicB[0]).toEqual({ + topic: 'topicB', + eventPayload: { test: 'topicB' }, + }); + + expect(Object.keys(subscriber2.receivedEvents)).toEqual([ + 'topicB', + 'topicC', + ]); + expect(subscriber2.receivedEvents.topicB.length).toEqual(1); + expect(subscriber2.receivedEvents.topicB[0]).toEqual({ + topic: 'topicB', + eventPayload: { test: 'topicB' }, + }); + expect(subscriber2.receivedEvents.topicC.length).toEqual(1); + expect(subscriber2.receivedEvents.topicC[0]).toEqual({ + topic: 'topicC', + eventPayload: { test: 'topicC' }, + }); + }); +}); diff --git a/plugins/events-backend/src/service/InMemoryEventBroker.ts b/plugins/events-backend/src/service/InMemoryEventBroker.ts new file mode 100644 index 0000000000..90c7d912fe --- /dev/null +++ b/plugins/events-backend/src/service/InMemoryEventBroker.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2022 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 { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; + +/** + * In-memory event broker which will pass the event to all registered subscribers + * interested in it. + * Events will not be persisted in any form. + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class InMemoryEventBroker implements EventBroker { + constructor(private readonly logger: Logger) {} + + private readonly subscribers: { + [topic: string]: EventSubscriber[]; + } = {}; + + async publish(params: EventParams): Promise { + this.logger.debug( + `Event received: topic=${params.topic}, metadata=${JSON.stringify( + params.metadata, + )}, payload=${JSON.stringify(params.eventPayload)}`, + ); + + const subscribed = this.subscribers[params.topic] ?? []; + subscribed.forEach(subscriber => subscriber.onEvent(params)); + } + + subscribe( + ...subscribers: Array> + ): void { + subscribers.flat().forEach(subscriber => { + subscriber.supportsEventTopics().forEach(topic => { + this.subscribers[topic] = this.subscribers[topic] ?? []; + this.subscribers[topic].push(subscriber); + }); + }); + } +} diff --git a/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts new file mode 100644 index 0000000000..3d93e347b3 --- /dev/null +++ b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts @@ -0,0 +1,225 @@ +/* + * Copyright 2022 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 { errorHandler, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import express from 'express'; +import Router from 'express-promise-router'; +import request from 'supertest'; +import { HttpPostIngressEventPublisher } from './HttpPostIngressEventPublisher'; + +describe('HttpPostIngressEventPublisher', () => { + const logger = getVoidLogger(); + + it('should set up routes correctly', async () => { + const config = new ConfigReader({ + events: { + http: { + topics: ['testA'], + }, + }, + }); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + const app = express().use(router); + + const publisher = HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + ingresses: { + testB: {}, + }, + }); + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + const notFoundResponse = await request(app) + .post('/unknown') + .timeout(100) + .send({ test: 'data' }); + expect(notFoundResponse.status).toBe(404); + + const response1 = await request(app) + .post('/testA') + .set('X-Custom-Header', 'test-value') + .timeout(100) + .send({ testA: 'data' }); + expect(response1.status).toBe(202); + + const response2 = await request(app) + .post('/testB') + .set('X-Custom-Header', 'test-value') + .timeout(100) + .send({ testB: 'data' }); + expect(response2.status).toBe(202); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('testA'); + expect(eventBroker.published[0].eventPayload).toEqual({ testA: 'data' }); + expect(eventBroker.published[0].metadata).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-custom-header': 'test-value', + }), + ); + expect(eventBroker.published[1].topic).toEqual('testB'); + expect(eventBroker.published[1].eventPayload).toEqual({ testB: 'data' }); + expect(eventBroker.published[1].metadata).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-custom-header': 'test-value', + }), + ); + }); + + it('with validator', async () => { + const config = new ConfigReader({ + events: { + http: { + topics: ['testA'], + }, + }, + }); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + const app = express().use(router); + + const publisher = HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + ingresses: { + testB: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testB-signature') { + return; + } + + context.reject({ + status: 400, + payload: { + message: 'wrong signature', + }, + }); + }, + }, + testC: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testC-signature') { + return; + } + + context.reject({ + status: 404, + // payload: {}, + }); + }, + }, + testD: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testD-signature') { + return; + } + + context.reject({ + // status: 403, + // payload: {}, + }); + }, + }, + }, + }); + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + const response1 = await request(app) + .post('/testA') + .timeout(100) + .send({ test: 'data' }); + expect(response1.status).toBe(202); + + const response2 = await request(app) + .post('/testB') + .timeout(100) + .send({ test: 'data' }); + expect(response2.status).toBe(400); + expect(response2.body).toEqual({ message: 'wrong signature' }); + + const response3 = await request(app) + .post('/testB') + .set('X-Test-Signature', 'wrong') + .timeout(100) + .send({ test: 'data' }); + expect(response3.status).toBe(400); + expect(response3.body).toEqual({ message: 'wrong signature' }); + + const response4 = await request(app) + .post('/testB') + .set('X-Test-Signature', 'testB-signature') + .timeout(100) + .send({ test: 'data' }); + expect(response4.status).toBe(202); + + const response5 = await request(app) + .post('/testC') + .timeout(100) + .send({ test: 'data' }); + expect(response5.status).toBe(404); + expect(response5.body).toEqual({}); + + const response6 = await request(app) + .post('/testD') + .timeout(100) + .send({ test: 'data' }); + expect(response6.status).toBe(403); + expect(response6.body).toEqual({}); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('testA'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'data' }); + expect(eventBroker.published[1].topic).toEqual('testB'); + expect(eventBroker.published[1].eventPayload).toEqual({ test: 'data' }); + expect(eventBroker.published[1].metadata).toEqual( + expect.objectContaining({ + 'x-test-signature': 'testB-signature', + }), + ); + }); + + it('without configuration', async () => { + const config = new ConfigReader({}); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + + expect(() => + HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + }), + ).not.toThrow(); + }); +}); diff --git a/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts new file mode 100644 index 0000000000..64b7140b54 --- /dev/null +++ b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts @@ -0,0 +1,118 @@ +/* + * Copyright 2022 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 { errorHandler } from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { + EventBroker, + EventPublisher, + HttpPostIngressOptions, + RequestValidator, +} from '@backstage/plugin-events-node'; +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; +import { RequestValidationContextImpl } from './validation'; + +/** + * Publishes events received from their origin (e.g., webhook events from an SCM system) + * via HTTP POST endpoint and passes the request body as event payload to the registered subscribers. + * + * @public + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class HttpPostIngressEventPublisher implements EventPublisher { + private eventBroker?: EventBroker; + + static fromConfig(env: { + config: Config; + ingresses?: { [topic: string]: Omit }; + logger: Logger; + router: express.Router; + }): HttpPostIngressEventPublisher { + const topics = + env.config.getOptionalStringArray('events.http.topics') ?? []; + + const ingresses = env.ingresses ?? {}; + topics.forEach(topic => { + // don't overwrite topic settings + // (e.g., added at the config as well as argument) + if (!ingresses[topic]) { + ingresses[topic] = {}; + } + }); + + return new HttpPostIngressEventPublisher(env.logger, env.router, ingresses); + } + + private constructor( + private logger: Logger, + router: express.Router, + ingresses: { [topic: string]: Omit }, + ) { + router.use(this.createRouter(ingresses)); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + } + + private createRouter(ingresses: { + [topic: string]: Omit; + }): express.Router { + const router = Router(); + router.use(express.json()); + + Object.keys(ingresses).forEach(topic => + this.addRouteForTopic(router, topic, ingresses[topic].validator), + ); + + router.use(errorHandler()); + return router; + } + + private addRouteForTopic( + router: express.Router, + topic: string, + validator?: RequestValidator, + ): void { + const path = `/${topic}`; + + router.post(path, async (request, response) => { + const context = new RequestValidationContextImpl(); + await validator?.(request, context); + if (context.wasRejected()) { + response + .status(context.rejectionDetails!.status) + .json(context.rejectionDetails!.payload); + return; + } + + const eventPayload = request.body; + await this.eventBroker!.publish({ + topic, + eventPayload, + metadata: request.headers, + }); + + response.status(202).json({ status: 'accepted' }); + }); + + // TODO(pjungermann): We don't really know the externally defined path prefix here, + // however it is more useful for users to have it. Is there a better way? + this.logger.info(`Registered /api/events/http${path} to receive events`); + } +} diff --git a/plugins/events-backend/src/service/http/index.ts b/plugins/events-backend/src/service/http/index.ts new file mode 100644 index 0000000000..fe71e49dfa --- /dev/null +++ b/plugins/events-backend/src/service/http/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { HttpPostIngressEventPublisher } from './HttpPostIngressEventPublisher'; +export * from './validation'; diff --git a/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts new file mode 100644 index 0000000000..b2f1485f65 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2022 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 { RequestValidationContextImpl } from './RequestValidationContextImpl'; + +describe('RequestValidationContextImpl', () => { + it('not rejected', () => { + const context = new RequestValidationContextImpl(); + + expect(context.wasRejected()).toBe(false); + expect(context.rejectionDetails).toBeUndefined(); + }); + + it('reject without details', () => { + const context = new RequestValidationContextImpl(); + + context.reject(); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(403); + expect(context.rejectionDetails!.payload).toEqual({}); + }); + + it('reject with partial details', () => { + const context = new RequestValidationContextImpl(); + + context.reject({ status: 404 }); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(404); + expect(context.rejectionDetails!.payload).toEqual({}); + }); + + it('reject with details', () => { + const context = new RequestValidationContextImpl(); + + context.reject({ + status: 403, + payload: { message: 'invalid signature' }, + }); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(403); + expect(context.rejectionDetails!.payload).toEqual({ + message: 'invalid signature', + }); + }); +}); diff --git a/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts new file mode 100644 index 0000000000..3dc607a683 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2022 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 { + RequestRejectionDetails, + RequestValidationContext, +} from '@backstage/plugin-events-node'; + +export class RequestValidationContextImpl implements RequestValidationContext { + #rejectionDetails: RequestRejectionDetails | undefined; + + reject(details?: Partial): void { + this.#rejectionDetails = { + status: details?.status ?? 403, + payload: details?.payload ?? {}, + }; + } + + wasRejected(): boolean { + return this.#rejectionDetails !== undefined; + } + + get rejectionDetails() { + return this.#rejectionDetails; + } +} diff --git a/plugins/events-backend/src/service/http/validation/index.ts b/plugins/events-backend/src/service/http/validation/index.ts new file mode 100644 index 0000000000..7513014906 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { RequestValidationContextImpl } from './RequestValidationContextImpl'; diff --git a/plugins/events-backend/src/setupTests.ts b/plugins/events-backend/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-node/.eslintrc.js b/plugins/events-node/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-node/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md new file mode 100644 index 0000000000..25899c739e --- /dev/null +++ b/plugins/events-node/CHANGELOG.md @@ -0,0 +1,32 @@ +# @backstage/plugin-events-node + +## 0.1.0 + +### Minor Changes + +- dc9da28abd: Support events received via HTTP endpoints at plugin-events-backend. + + The plugin provides an event publisher `HttpPostIngressEventPublisher` + which will allow you to receive events via + HTTP endpoints `POST /api/events/http/{topic}` + and will publish these to the used event broker. + + Using a provided custom validator, you can participate in the decision + which events are accepted, e.g. by verifying the source of the request. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. + +- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events. + + plugin-events-node exposes interfaces which can be used by modules. + + plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + + Please find more information at + https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4 diff --git a/plugins/events-node/README.md b/plugins/events-node/README.md new file mode 100644 index 0000000000..44738222bc --- /dev/null +++ b/plugins/events-node/README.md @@ -0,0 +1,3 @@ +# plugin-events-node + +Houses types and utilities for building events-related modules. diff --git a/plugins/events-node/api-report.md b/plugins/events-node/api-report.md new file mode 100644 index 0000000000..1054211cbc --- /dev/null +++ b/plugins/events-node/api-report.md @@ -0,0 +1,106 @@ +## API Report File for "@backstage/plugin-events-node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { Request as Request_2 } from 'express'; + +// @public +export interface EventBroker { + publish(params: EventParams): Promise; + subscribe( + ...subscribers: Array> + ): void; +} + +// @public (undocumented) +export interface EventParams { + eventPayload: unknown; + metadata?: Record; + topic: string; +} + +// @public +export interface EventPublisher { + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @public +export abstract class EventRouter implements EventPublisher, EventSubscriber { + // (undocumented) + protected abstract determineDestinationTopic( + params: EventParams, + ): string | undefined; + // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; + // (undocumented) + abstract supportsEventTopics(): string[]; +} + +// @alpha (undocumented) +export interface EventsExtensionPoint { + // (undocumented) + addHttpPostIngress(options: HttpPostIngressOptions): void; + // (undocumented) + addPublishers( + ...publishers: Array> + ): void; + // (undocumented) + addSubscribers( + ...subscribers: Array> + ): void; + // (undocumented) + setEventBroker(eventBroker: EventBroker): void; +} + +// @alpha (undocumented) +export const eventsExtensionPoint: ExtensionPoint; + +// @public +export interface EventSubscriber { + onEvent(params: EventParams): Promise; + supportsEventTopics(): string[]; +} + +// @public (undocumented) +export interface HttpPostIngressOptions { + // (undocumented) + topic: string; + // (undocumented) + validator?: RequestValidator; +} + +// @public +export interface RequestRejectionDetails { + // (undocumented) + payload: unknown; + // (undocumented) + status: number; +} + +// @public +export interface RequestValidationContext { + reject(details?: Partial): void; +} + +// @public +export type RequestValidator = ( + request: Request_2, + context: RequestValidationContext, +) => Promise; + +// @public +export abstract class SubTopicEventRouter extends EventRouter { + protected constructor(topic: string); + // (undocumented) + protected determineDestinationTopic(params: EventParams): string | undefined; + // (undocumented) + protected abstract determineSubTopic(params: EventParams): string | undefined; + // (undocumented) + supportsEventTopics(): string[]; +} +``` diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json new file mode 100644 index 0000000000..d193f33b00 --- /dev/null +++ b/plugins/events-node/package.json @@ -0,0 +1,38 @@ +{ + "name": "@backstage/plugin-events-node", + "description": "The plugin-events-node module for @backstage/plugin-events-backend", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "node-library" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@types/express": "^4.17.6", + "express": "^4.17.1" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-node/src/api/EventBroker.ts b/plugins/events-node/src/api/EventBroker.ts new file mode 100644 index 0000000000..736c2a2bf0 --- /dev/null +++ b/plugins/events-node/src/api/EventBroker.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2022 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 { EventParams } from './EventParams'; +import { EventSubscriber } from './EventSubscriber'; + +/** + * Allows a decoupled and asynchronous communication between components. + * Components can publish events for a given topic and + * others can subscribe for future events for topics they are interested in. + * + * @public + */ +export interface EventBroker { + /** + * Publishes an event for the topic. + * + * @param params - parameters for the to be published event. + */ + publish(params: EventParams): Promise; + + /** + * Adds new subscribers for {@link EventSubscriber#supportsEventTopics | interested topics}. + * + * @param subscribers - interested in events of specified topics. + */ + subscribe( + ...subscribers: Array> + ): void; +} diff --git a/plugins/events-node/src/api/EventParams.ts b/plugins/events-node/src/api/EventParams.ts new file mode 100644 index 0000000000..6912827281 --- /dev/null +++ b/plugins/events-node/src/api/EventParams.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2022 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. + */ + +/** + * @public + */ +export interface EventParams { + /** + * Topic for which this event should be published. + */ + topic: string; + /** + * Event payload. + */ + eventPayload: unknown; + /** + * Metadata (e.g., HTTP headers and similar for events received from external). + */ + metadata?: Record; +} diff --git a/plugins/events-node/src/api/EventPublisher.ts b/plugins/events-node/src/api/EventPublisher.ts new file mode 100644 index 0000000000..285f427804 --- /dev/null +++ b/plugins/events-node/src/api/EventPublisher.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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 { EventBroker } from './EventBroker'; + +/** + * Publishes events to be consumed by subscribers for their topic. + * The events can come from different (external) sources + * like emitted themselves, received via HTTP endpoint (i.e. webhook) + * or from event brokers, queues, etc. + * + * @public + */ +export interface EventPublisher { + setEventBroker(eventBroker: EventBroker): Promise; +} diff --git a/plugins/events-node/src/api/EventRouter.test.ts b/plugins/events-node/src/api/EventRouter.test.ts new file mode 100644 index 0000000000..551c5ea67d --- /dev/null +++ b/plugins/events-node/src/api/EventRouter.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2022 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { EventRouter } from './EventRouter'; + +class TestEventRouter extends EventRouter { + protected determineDestinationTopic(params: EventParams): string | undefined { + const payload = params.eventPayload as { value?: number }; + if (payload.value === undefined) { + return undefined; + } + + return payload.value % 2 === 0 ? 'even' : 'odd'; + } + + supportsEventTopics(): string[] { + return ['my-topic']; + } +} + +describe('EventRouter', () => { + const eventRouter = new TestEventRouter(); + const topic = 'my-topic'; + const metadata = { random: 'metadata' }; + + it('no destination topic', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ + topic, + eventPayload: { discarded: 'event' }, + metadata, + }); + + expect(published).toEqual([]); + }); + + it('with destination topic', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + const payloadEven = { value: 2 }; + const payloadOdd = { value: 3 }; + await eventRouter.onEvent({ topic, eventPayload: payloadEven, metadata }); + await eventRouter.onEvent({ topic, eventPayload: payloadOdd, metadata }); + + expect(published.length).toBe(2); + expect(published[0].topic).toEqual('even'); + expect(published[0].eventPayload).toEqual(payloadEven); + expect(published[0].metadata).toEqual(metadata); + expect(published[1].topic).toEqual('odd'); + expect(published[1].eventPayload).toEqual(payloadOdd); + expect(published[1].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-node/src/api/EventRouter.ts b/plugins/events-node/src/api/EventRouter.ts new file mode 100644 index 0000000000..b435ef15f4 --- /dev/null +++ b/plugins/events-node/src/api/EventRouter.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { EventPublisher } from './EventPublisher'; +import { EventSubscriber } from './EventSubscriber'; + +/** + * Subscribes to a topic and - depending on a set of conditions - + * republishes the event to another topic. + * + * @see {@link https://www.enterpriseintegrationpatterns.com/MessageRouter.html | Message Router pattern}. + * @public + */ +export abstract class EventRouter implements EventPublisher, EventSubscriber { + private eventBroker?: EventBroker; + + protected abstract determineDestinationTopic( + params: EventParams, + ): string | undefined; + + async onEvent(params: EventParams): Promise { + const topic = this.determineDestinationTopic(params); + + if (!topic) { + return; + } + + // republish to different topic + this.eventBroker?.publish({ + ...params, + topic, + }); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + } + + abstract supportsEventTopics(): string[]; +} diff --git a/plugins/events-node/src/api/EventSubscriber.ts b/plugins/events-node/src/api/EventSubscriber.ts new file mode 100644 index 0000000000..439f49b890 --- /dev/null +++ b/plugins/events-node/src/api/EventSubscriber.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2022 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 { EventParams } from './EventParams'; + +/** + * Handles received events. + * This may include triggering refreshes of catalog entities + * or other actions to react on events. + * + * @public + */ +export interface EventSubscriber { + /** + * Supported event topics like "github", "bitbucketCloud", etc. + */ + supportsEventTopics(): string[]; + + /** + * React on a received event. + * + * @param params - parameters for the to be received event. + */ + onEvent(params: EventParams): Promise; +} diff --git a/plugins/events-node/src/api/SubTopicEventRouter.test.ts b/plugins/events-node/src/api/SubTopicEventRouter.test.ts new file mode 100644 index 0000000000..d5c79895a5 --- /dev/null +++ b/plugins/events-node/src/api/SubTopicEventRouter.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { SubTopicEventRouter } from './SubTopicEventRouter'; + +class TestSubTopicEventRouter extends SubTopicEventRouter { + constructor() { + super('my-topic'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-my-event'] as string | undefined; + } +} + +describe('SubTopicEventRouter', () => { + const eventRouter = new TestSubTopicEventRouter(); + const topic = 'my-topic'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-my-event': 'test.type' }; + + it('no x-my-event', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ topic, eventPayload }); + + expect(published).toEqual([]); + }); + + it('with x-my-event', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(published.length).toBe(1); + expect(published[0].topic).toEqual('my-topic.test.type'); + expect(published[0].eventPayload).toEqual(eventPayload); + expect(published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-node/src/api/SubTopicEventRouter.ts b/plugins/events-node/src/api/SubTopicEventRouter.ts new file mode 100644 index 0000000000..04abe14009 --- /dev/null +++ b/plugins/events-node/src/api/SubTopicEventRouter.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 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 { EventParams } from './EventParams'; +import { EventRouter } from './EventRouter'; + +/** + * Subscribes to the provided (generic) topic + * and publishes the events under the more concrete sub-topic + * depending on the implemented logic for determining it. + * Implementing classes might use information from `metadata` + * and/or properties within the payload. + * + * @public + */ +export abstract class SubTopicEventRouter extends EventRouter { + protected constructor(private readonly topic: string) { + super(); + } + + protected abstract determineSubTopic(params: EventParams): string | undefined; + + protected determineDestinationTopic(params: EventParams): string | undefined { + const subTopic = this.determineSubTopic(params); + return subTopic ? `${params.topic}.${subTopic}` : undefined; + } + + supportsEventTopics(): string[] { + return [this.topic]; + } +} diff --git a/plugins/events-node/src/api/http/HttpPostIngressOptions.ts b/plugins/events-node/src/api/http/HttpPostIngressOptions.ts new file mode 100644 index 0000000000..d9f005d84d --- /dev/null +++ b/plugins/events-node/src/api/http/HttpPostIngressOptions.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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 { RequestValidator } from './validation'; + +/** + * @public + */ +export interface HttpPostIngressOptions { + topic: string; + validator?: RequestValidator; +} diff --git a/plugins/events-node/src/api/http/index.ts b/plugins/events-node/src/api/http/index.ts new file mode 100644 index 0000000000..9206819a4a --- /dev/null +++ b/plugins/events-node/src/api/http/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { HttpPostIngressOptions } from './HttpPostIngressOptions'; +export * from './validation'; diff --git a/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts b/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts new file mode 100644 index 0000000000..1eca094367 --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2022 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. + */ + +/** + * Details for how to respond to the rejection + * of the received HTTP request transmitting an event payload. + * + * @public + */ +export interface RequestRejectionDetails { + status: number; + payload: unknown; +} diff --git a/plugins/events-node/src/api/http/validation/RequestValidationContext.ts b/plugins/events-node/src/api/http/validation/RequestValidationContext.ts new file mode 100644 index 0000000000..eedb6f1f96 --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestValidationContext.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2022 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 { RequestRejectionDetails } from './RequestRejectionDetails'; + +/** + * Passed context for the validation + * at which rejections can be expressed. + * + * @public + */ +export interface RequestValidationContext { + /** + * Rejects the validated request + * + * @param details - Optional details about the rejection which will be provided to the sender. + */ + reject(details?: Partial): void; +} diff --git a/plugins/events-node/src/api/http/validation/RequestValidator.ts b/plugins/events-node/src/api/http/validation/RequestValidator.ts new file mode 100644 index 0000000000..b419b855cf --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestValidator.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2022 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 { Request } from 'express'; +import { RequestValidationContext } from './RequestValidationContext'; + +/** + * Validator used to check the received HTTP request + * transmitting an event payload. + * + * E.g., it can be used for signature verification like + * for GitHub webhook events + * (https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#secret) + * or other kinds of checks. + * + * @public + */ +export type RequestValidator = ( + request: Request, + context: RequestValidationContext, +) => Promise; diff --git a/plugins/events-node/src/api/http/validation/index.ts b/plugins/events-node/src/api/http/validation/index.ts new file mode 100644 index 0000000000..95f2d474eb --- /dev/null +++ b/plugins/events-node/src/api/http/validation/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { RequestRejectionDetails } from './RequestRejectionDetails'; +export type { RequestValidationContext } from './RequestValidationContext'; +export type { RequestValidator } from './RequestValidator'; diff --git a/plugins/events-node/src/api/index.ts b/plugins/events-node/src/api/index.ts new file mode 100644 index 0000000000..91711c0e38 --- /dev/null +++ b/plugins/events-node/src/api/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { EventBroker } from './EventBroker'; +export type { EventParams } from './EventParams'; +export type { EventPublisher } from './EventPublisher'; +export { EventRouter } from './EventRouter'; +export type { EventSubscriber } from './EventSubscriber'; +export * from './http'; +export { SubTopicEventRouter } from './SubTopicEventRouter'; diff --git a/plugins/events-node/src/extensions.ts b/plugins/events-node/src/extensions.ts new file mode 100644 index 0000000000..945d86b49c --- /dev/null +++ b/plugins/events-node/src/extensions.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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 { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { + EventBroker, + EventPublisher, + EventSubscriber, + HttpPostIngressOptions, +} from './api'; + +/** + * @alpha + */ +export interface EventsExtensionPoint { + setEventBroker(eventBroker: EventBroker): void; + + addPublishers( + ...publishers: Array> + ): void; + + addSubscribers( + ...subscribers: Array> + ): void; + + addHttpPostIngress(options: HttpPostIngressOptions): void; +} + +/** + * @alpha + */ +export const eventsExtensionPoint = createExtensionPoint({ + id: 'events', +}); diff --git a/plugins/events-node/src/index.ts b/plugins/events-node/src/index.ts new file mode 100644 index 0000000000..422eeb169e --- /dev/null +++ b/plugins/events-node/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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. + */ + +/** + * The events-node module for `@backstage/plugin-events-backend`. + * + * @packageDocumentation + */ + +export * from './api'; +export type { EventsExtensionPoint } from './extensions'; +export { eventsExtensionPoint } from './extensions'; diff --git a/plugins/events-node/src/setupTests.ts b/plugins/events-node/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-node/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index df0c013892..a255135f9b 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @internal/plugin-todo-list-backend +## 1.0.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 1.0.7-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 9d6419a76d..010fcb3e88 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.7-next.0", + "version": "1.0.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 747dd912c0..b90ea73e78 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-common +## 1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 23a16e10c7..b52ceb9a26 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.6-next.0", + "version": "1.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "@backstage/test-utils": "workspace:^", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index f08094181d..685e92acdb 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,23 @@ # @internal/plugin-todo-list +## 1.0.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 1.0.7-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 0b12ae6208..c1e66b88c1 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.7-next.0", + "version": "1.0.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index c139c37348..22850a9523 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-explore-react +## 0.0.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + ## 0.0.23-next.0 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 27ee4c23df..4d1d623c90 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.23-next.0", + "version": "0.0.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index bc31cd1ec6..af08b68965 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-explore +## 0.3.42 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-explore-react@0.0.23 + +## 0.3.42-next.1 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-explore-react@0.0.23-next.0 + ## 0.3.42-next.0 ### Patch Changes diff --git a/plugins/explore/README.md b/plugins/explore/README.md index 8e1cbaed02..94ab0984a0 100644 --- a/plugins/explore/README.md +++ b/plugins/explore/README.md @@ -79,3 +79,39 @@ const routes = ( ); ``` + +## ToolExplorer Content Customization + +Override the `exploreToolsConfigRef` API in `/packages/app/src/apis.ts`. + +```tsx +import { exploreToolsConfigRef } from '@backstage/plugin-explore-react'; + +export const apis: AnyApiFactory[] = [ + ... + + createApiFactory({ + api: exploreToolsConfigRef, + deps: {}, + factory: () => ({ + async getTools() { + return tools; + }, + /* e.g. tools = [ + { + title: 'New Relic', + description:'new relic plugin, + url: '/newrelic', + image: 'https://i.imgur.com/L37ikrX.jpg', + tags: ['newrelic', 'proxy', 'nerdGraph'], + }, + ] + */ + }), + }), + + .... + +]; + +``` diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 7ff382b9ce..835d7cf39d 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.3.42-next.0", + "version": "0.3.42", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx index 399112fac6..62d197803f 100644 --- a/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx +++ b/plugins/explore/src/components/DefaultExplorePage/DefaultExplorePage.test.tsx @@ -21,8 +21,8 @@ import React from 'react'; import { DefaultExplorePage } from './DefaultExplorePage'; describe('', () => { - const catalogApi: jest.Mocked = { - addLocation: jest.fn(_a => new Promise(() => {})), + const catalogApi = { + addLocation: jest.fn(), getEntities: jest.fn(), getLocationByRef: jest.fn(), getLocationById: jest.fn(), diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx index c84363f5c6..a62083f66f 100644 --- a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx @@ -22,8 +22,8 @@ import React from 'react'; import { DomainExplorerContent } from './DomainExplorerContent'; describe('', () => { - const catalogApi: jest.Mocked = { - addLocation: jest.fn(_a => new Promise(() => {})), + const catalogApi = { + addLocation: jest.fn(), getEntities: jest.fn(), getLocationByRef: jest.fn(), getLocationById: jest.fn(), diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx index a4769e8f4f..9b461fba7d 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsExplorerContent.test.tsx @@ -22,8 +22,8 @@ import React from 'react'; import { GroupsExplorerContent } from '../GroupsExplorerContent'; describe('', () => { - const catalogApi: jest.Mocked = { - addLocation: jest.fn(_a => new Promise(() => {})), + const catalogApi = { + addLocation: jest.fn(), getEntities: jest.fn(), getLocationByRef: jest.fn(), getLocationById: jest.fn(), diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index cd01270cbe..28eff9ba0a 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-firehydrant +## 0.1.28 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.28-next.0 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 2c455fbd82..9303e50b99 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.1.28-next.0", + "version": "0.1.28", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index bd43f4d7b8..94ca0b60a1 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-fossa +## 0.2.43 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.43-next.0 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 32d9da5146..0ad056bcd9 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.43-next.0", + "version": "0.2.43", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx b/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx index 676a3cff3c..be07b4707f 100644 --- a/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx +++ b/plugins/fossa/src/components/FossaPage/FossaPage.test.tsx @@ -15,21 +15,16 @@ */ import { Entity } from '@backstage/catalog-model'; -import { - CatalogApi, - catalogApiRef, - entityRouteRef, -} from '@backstage/plugin-catalog-react'; +import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import React from 'react'; import { FossaApi, fossaApiRef } from '../../api'; import { FossaPage } from './FossaPage'; describe('', () => { - const catalogApi: jest.Mocked = { + const catalogApi = { addLocation: jest.fn(), getEntities: jest.fn(), - getEntityByRef: jest.fn(), getLocationByRef: jest.fn(), getLocationById: jest.fn(), removeEntityByUid: jest.fn(), diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index 3e4cc2473c..316a35f4c8 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-gcalendar +## 0.3.7 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.3.7-next.0 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index c6f748c6a2..c682be6e79 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.7-next.0", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@types/node": "^16.11.26", "@types/sanitize-html": "^2.6.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 3e4f8df529..e07597f6c1 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-gcp-projects +## 0.3.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 0.3.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.30-next.0 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 6b1ea7a0d4..e8ac3297e9 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.30-next.0", + "version": "0.3.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 00b079b7cd..b167b3f05d 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-git-release-manager +## 0.3.24 + +### Patch Changes + +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/theme@0.2.16 + +## 0.3.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.24-next.0 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 9b3533d994..aa2f3cb9de 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.24-next.0", + "version": "0.3.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,7 +53,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index b3570d20cf..1c2247c478 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-github-actions +## 0.5.11 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.5.11-next.1 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.11-next.0 ### Patch Changes diff --git a/plugins/github-actions/README.md b/plugins/github-actions/README.md index 792d13280f..cb6867193c 100644 --- a/plugins/github-actions/README.md +++ b/plugins/github-actions/README.md @@ -11,7 +11,7 @@ TBD ### Generic Requirements 1. Provide OAuth credentials: - 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) in the GitHub organization with the callback URL set to `http://localhost:7007/api/auth/github`. + 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) in the GitHub organization with the callback URL set to `http://localhost:7007/api/auth/github/handler/frame`. 2. Take the Client ID and Client Secret from the newly created app's settings page and put them into `AUTH_GITHUB_CLIENT_ID` and `AUTH_GITHUB_CLIENT_SECRET` environment variables. 2. Annotate your component with a correct GitHub Actions repository and owner: diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 8247c48fa5..e69bd568da 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.5.11-next.0", + "version": "0.5.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx index 89fd40da33..59d64af9c9 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx @@ -29,6 +29,7 @@ import { useRouteRef, } from '@backstage/core-plugin-api'; import { + ErrorPanel, InfoCard, InfoCardVariants, Link, @@ -76,6 +77,11 @@ export const RecentWorkflowRunsCard = (props: { const githubHost = hostname || 'github.com'; const routeLink = useRouteRef(buildRouteRef); + + if (error) { + return ; + } + return ( { expect(rendered.getAllByText(testLabel)).toHaveLength(2); }); - describe('when the user hasn`t clicked on it', () => { + describe("when the user hasn't clicked on it", () => { it('should only render the current select item', async () => { const rendered = await renderInTestApp( `. + - Add the `PodStatusFetchResponse` to the `FetchResponse` union type. + - Add `NOT_FOUND` to the `KubernetesErrorTypes` union type, the HTTP error with status code 404 will be mapped to this error. + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-kubernetes-common@0.4.4 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.8.0-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.8.0-next.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 4082bd5b3a..acf28eeb36 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.8.0-next.0", + "version": "0.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@google-cloud/container": "^4.0.0", - "@kubernetes/client-node": "^0.17.0", + "@kubernetes/client-node": "0.17.0", "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", "aws-sdk": "^2.840.0", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index b85e3c00ee..3a255e7525 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-kubernetes-common +## 0.4.4 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- cbf5d11fdf: The Kubernetes errors when fetching pod metrics are now captured and returned to the frontend. + + - **BREAKING** The method `fetchPodMetricsByNamespace` in the interface `KubernetesFetcher` is changed to `fetchPodMetricsByNamespaces`. It now accepts a set of namespace strings and returns `Promise`. + - Add the `PodStatusFetchResponse` to the `FetchResponse` union type. + - Add `NOT_FOUND` to the `KubernetesErrorTypes` union type, the HTTP error with status code 404 will be mapped to this error. + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + +## 0.4.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 48c04fb222..f82c8bb9d9 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.4.4-next.0", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,7 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@kubernetes/client-node": "^0.17.0" + "@kubernetes/client-node": "0.17.0" }, "devDependencies": { "@backstage/cli": "workspace:^" diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 2272804b22..f01d0b8db4 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-kubernetes +## 0.7.4 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-kubernetes-common@0.4.4 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## 0.7.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.7.4-next.0 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index ee4da4b55f..6851f01162 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.7.4-next.0", + "version": "0.7.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/theme": "workspace:^", - "@kubernetes/client-node": "^0.17.0", + "@kubernetes/client-node": "0.17.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -66,7 +66,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 8a5a1bee97..f47334f73c 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-lighthouse +## 0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 8c87e8eec3..caf0df17e2 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.3.11-next.0", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx index 53de33d21b..3e34eed6e3 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListForEntity.test.tsx @@ -122,7 +122,7 @@ describe('', () => { it('renders nothing', async () => { const { queryByTestId } = subject(); - expect(await queryByTestId('AuditListTable')).toBeNull(); + expect(queryByTestId('AuditListTable')).toBeNull(); }); }); @@ -137,7 +137,7 @@ describe('', () => { it('renders nothing', async () => { const { queryByTestId } = subject(); - expect(await queryByTestId('AuditListTable')).toBeNull(); + expect(queryByTestId('AuditListTable')).toBeNull(); }); }); }); diff --git a/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx b/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx index 58a3033a1f..ab1e2683b6 100644 --- a/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx +++ b/plugins/lighthouse/src/components/Cards/LastLighthouseAuditCard.test.tsx @@ -151,10 +151,10 @@ describe('', () => { it('renders nothing', async () => { const { queryByTestId } = subject(); - expect(await queryByTestId('AuditListTable')).toBeNull(); + expect(queryByTestId('AuditListTable')).toBeNull(); }); }); - // + describe('where there is no data', () => { beforeEach(() => { (useWebsiteForEntity as jest.Mock).mockReturnValue({ @@ -166,7 +166,7 @@ describe('', () => { it('renders nothing', async () => { const { queryByTestId } = subject(); - expect(await queryByTestId('AuditListTable')).toBeNull(); + expect(queryByTestId('AuditListTable')).toBeNull(); }); }); }); diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 81efe251d3..39a1e77549 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-newrelic-dashboard +## 0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index a8100bdd38..2766346636 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.2.4-next.0", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 526010f2f8..328c73e448 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-newrelic +## 0.3.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.29-next.0 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 0eedad1ced..5dfe152a2f 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.29-next.0", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/org-react/.eslintrc.js b/plugins/org-react/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/org-react/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md new file mode 100644 index 0000000000..c84b6306c9 --- /dev/null +++ b/plugins/org-react/CHANGELOG.md @@ -0,0 +1,33 @@ +# @backstage/plugin-org-react + +## 0.1.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/theme@0.2.16 + +## 0.1.0-next.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md new file mode 100644 index 0000000000..91c7ebf48a --- /dev/null +++ b/plugins/org-react/README.md @@ -0,0 +1,30 @@ +# org-react + +## features + +- Group list picker component + +### GroupListPicker + +The `GroupListPicker` component displays a select box which also has autocomplete functionality. + +To use the `GroupListPicker` component you'll need to import it and add it to your desired place. + +```diff ++ import { GroupListPicker } from '@backstage/plugin-org-react'; ++ import React, { useState } from 'react'; + ++ const [group, setGroup] = useState(); + + + ++ + + +``` + +The `GroupListPicker` comes with three props: + +- `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; +- `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is. +- `onChange`: a prop to help the user to give access to the selected group diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md new file mode 100644 index 0000000000..60cd6944d0 --- /dev/null +++ b/plugins/org-react/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-org-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { GroupEntity } from '@backstage/catalog-model'; + +// @public (undocumented) +export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; + +// @public +export type GroupListPickerProps = { + placeholder?: string; + groupTypes?: Array; + onChange: (value: GroupEntity | undefined) => void; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json new file mode 100644 index 0000000000..df0264a73d --- /dev/null +++ b/plugins/org-react/package.json @@ -0,0 +1,62 @@ +{ + "name": "@backstage/plugin-org-react", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library" + }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/org-react" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.57", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.48.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx new file mode 100644 index 0000000000..21b85ffe5c --- /dev/null +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -0,0 +1,88 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { ApiProvider } from '@backstage/core-app-api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { CatalogApi } from '@backstage/catalog-client'; +import { GroupListPicker } from '../GroupListPicker'; +import { GroupEntity } from '@backstage/catalog-model'; +import { TestApiRegistry } from '@backstage/test-utils'; + +const mockGroups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + namespace: 'default', + name: 'group-a', + }, + spec: { + type: 'org', + profile: { + displayName: 'Group A', + }, + children: [], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + namespace: 'default', + name: 'group-b', + }, + spec: { + type: 'department', + profile: { + displayName: 'Group B', + }, + children: [], + }, + }, +]; + +const mockCatalogApi = { + getEntities: () => Promise.resolve({ items: mockGroups }), +} as Partial; + +const apis = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); + +describe('', () => { + it('can choose a group', async () => { + const { getByText, getByTestId } = render( + + {}} + /> + , + ); + + await userEvent.click(getByTestId('group-list-picker-button')); + const input = getByTestId('group-list-picker-input').querySelector('input'); + await userEvent.type(input as HTMLElement, 'GR'); + + await waitFor(async () => { + expect(getByText('Group A')).toBeInTheDocument(); + await userEvent.click(getByText('Group A')); + expect(getByText('Group A')).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx new file mode 100644 index 0000000000..1296c520c3 --- /dev/null +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -0,0 +1,120 @@ +/* + * Copyright 2022 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, { useCallback } from 'react'; +import { + catalogApiRef, + humanizeEntityRef, +} from '@backstage/plugin-catalog-react'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import useAsync from 'react-use/lib/useAsync'; +import Popover from '@material-ui/core/Popover'; +import { useApi } from '@backstage/core-plugin-api'; +import { ResponseErrorPanel } from '@backstage/core-components'; +import { Entity, GroupEntity } from '@backstage/catalog-model'; +import { GroupListPickerButton } from './GroupListPickerButton'; + +/** + * Props for {@link GroupListPicker}. + * + * @public + */ +export type GroupListPickerProps = { + placeholder?: string; + groupTypes?: Array; + onChange: (value: GroupEntity | undefined) => void; +}; + +/** @public */ +export const GroupListPicker = (props: GroupListPickerProps) => { + const catalogApi = useApi(catalogApiRef); + + const { onChange, groupTypes, placeholder = '' } = props; + const [anchorEl, setAnchorEl] = React.useState(null); + const [inputValue, setInputValue] = React.useState(''); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + + const { + loading, + error, + value: groups, + } = useAsync(async () => { + const groupsList = await catalogApi.getEntities({ + filter: { + kind: 'Group', + 'spec.type': groupTypes || [], + }, + }); + + return groupsList.items as GroupEntity[]; + }, [catalogApi, groupTypes]); + + const handleChange = useCallback( + (_, v: GroupEntity | null) => { + onChange(v ?? undefined); + }, + [onChange], + ); + + if (error) { + return ; + } + + const getHumanEntityRef = (entity: Entity) => humanizeEntityRef(entity); + + return ( + <> + + option.spec.type} + getOptionLabel={option => + option.spec.profile?.displayName ?? getHumanEntityRef(option) + } + inputValue={inputValue} + onInputChange={(_, value) => setInputValue(value)} + onChange={handleChange} + style={{ width: '300px' }} + renderInput={params => ( + + )} + /> + + + + ); +}; diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx new file mode 100644 index 0000000000..149bf778b1 --- /dev/null +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx @@ -0,0 +1,68 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { BackstageTheme } from '@backstage/theme'; +import { makeStyles, Typography, Button } from '@material-ui/core'; +import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; +import PeopleIcon from '@material-ui/icons/People'; + +const useStyles = makeStyles((theme: BackstageTheme) => ({ + btn: { + margin: 0, + padding: 10, + width: '100%', + cursor: 'pointer', + justifyContent: 'space-between', + }, + title: { + fontSize: '1.5rem', + fontStyle: 'normal', + fontWeight: theme.typography.fontWeightBold, + letterSpacing: '-0.25px', + lineHeight: '32px', + marginBottom: 0, + textTransform: 'none', + }, + icon: { + transform: 'scale(1.5)', + }, +})); + +type GroupListPickerButtonProps = { + handleClick: (event: React.MouseEvent) => void; + group: string | undefined; +}; + +/** @public */ +export const GroupListPickerButton = (props: GroupListPickerButtonProps) => { + const { handleClick, group } = props; + const classes = useStyles(); + + return ( + + ); +}; diff --git a/plugins/org-react/src/components/GroupListPicker/index.ts b/plugins/org-react/src/components/GroupListPicker/index.ts new file mode 100644 index 0000000000..fe1ba8e1ee --- /dev/null +++ b/plugins/org-react/src/components/GroupListPicker/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { GroupListPicker } from './GroupListPicker'; +export type { GroupListPickerProps } from './GroupListPicker'; diff --git a/plugins/org-react/src/index.ts b/plugins/org-react/src/index.ts new file mode 100644 index 0000000000..c3393bee48 --- /dev/null +++ b/plugins/org-react/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { GroupListPicker } from './components/GroupListPicker'; +export type { GroupListPickerProps } from './components/GroupListPicker'; diff --git a/plugins/org-react/src/setupTests.ts b/plugins/org-react/src/setupTests.ts new file mode 100644 index 0000000000..9bb3e72355 --- /dev/null +++ b/plugins/org-react/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; +import 'cross-fetch/polyfill'; diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 682da2da91..6bfce1e679 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-org +## 0.6.0 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- 38dd29ea95: Add entity kind to the Ownership Cards. Fix the query parameters for the links of the Ownership Cards so that the catalog page actually selects the right entity kind. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.6.0-next.1 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.11-next.0 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 507660f1a3..b49b1ea390 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.5.11-next.0", + "version": "0.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx index fc45d9a8fe..cfb3d847a4 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx @@ -87,3 +87,44 @@ export default { ), ], }; + +const extraDetailsEntity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'team-a', + description: 'Team A', + links: [ + { + url: 'slack://user?team=T00000000&id=U00000000', + title: 'Slack', + icon: 'chat', + }, + { + url: 'https://www.google.com', + title: 'Google', + }, + ], + }, + spec: { + profile: { + displayName: 'Team A', + email: 'team-a@example.com', + picture: + 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25', + }, + type: 'group', + children: [], + }, + relations: [dummyDepartment], +}; + +export const ExtraDetails = () => ( + + + + + + + +); diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx index dfdb566b20..3a6b7c238d 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx @@ -52,6 +52,7 @@ import { Link, } from '@backstage/core-components'; import { alertApiRef, useApi } from '@backstage/core-plugin-api'; +import { LinksGroup } from '../../Meta'; const CardTitle = (props: { title: string }) => ( @@ -76,7 +77,7 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => { } const { - metadata: { name, description, annotations }, + metadata: { name, description, annotations, links }, spec: { profile }, } = group; @@ -190,6 +191,7 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => { secondary="Child Groups" /> + diff --git a/plugins/org/src/components/Cards/Meta/LinksGroup.tsx b/plugins/org/src/components/Cards/Meta/LinksGroup.tsx new file mode 100644 index 0000000000..eeade18411 --- /dev/null +++ b/plugins/org/src/components/Cards/Meta/LinksGroup.tsx @@ -0,0 +1,66 @@ +/* + * Copyright 2022 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 { EntityLink } from '@backstage/catalog-model'; +import { IconComponent, useApp } from '@backstage/core-plugin-api'; +import LanguageIcon from '@material-ui/icons/Language'; +import { + ListItem, + ListItemIcon, + ListItemText, + Divider, +} from '@material-ui/core'; +import React from 'react'; + +const WebLink = ({ + href, + Icon, + text, +}: { + href: string; + text?: string; + Icon?: IconComponent; +}) => ( + + {Icon ? : } + {text} + +); + +export const LinksGroup = ({ links }: { links?: EntityLink[] }) => { + const app = useApp(); + const iconResolver = (key?: string): IconComponent => + key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon; + + if (links === undefined) { + return null; + } + + return ( + <> + + {links.map(link => { + return ( + + ); + })} + + ); +}; diff --git a/plugins/org/src/components/Cards/Meta/index.ts b/plugins/org/src/components/Cards/Meta/index.ts new file mode 100644 index 0000000000..076af49bf9 --- /dev/null +++ b/plugins/org/src/components/Cards/Meta/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './LinksGroup'; diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index 6f7680849c..f996342454 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -56,15 +56,17 @@ const useStyles = makeStyles((theme: BackstageTheme) => const EntityCountTile = ({ counter, type, - name, + kind, url, }: { counter: number; - type: string; - name: string; + type?: string; + kind: string; url: string; }) => { - const classes = useStyles({ type }); + const classes = useStyles({ type: type ?? kind }); + + const rawTitle = type ?? kind; return ( @@ -78,8 +80,9 @@ const EntityCountTile = ({ {counter} - {pluralize(name, counter)} + {pluralize(rawTitle.toLocaleUpperCase('en-US'), counter)} + {type && {kind}} ); @@ -113,11 +116,11 @@ export const ComponentsGrid = ({ return ( {componentsWithCounters?.map(c => ( - + diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 28fa3f4988..84f27fa183 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -217,10 +217,16 @@ describe('OwnershipCard', () => { expect( queryByText(getByText('SYSTEM').parentElement!, '1'), ).toBeInTheDocument(); + expect( + queryByText(getByText('SYSTEM').parentElement!, 'System'), + ).not.toBeInTheDocument(); expect(getByText('OPENAPI')).toBeInTheDocument(); expect( queryByText(getByText('OPENAPI').parentElement!, '1'), ).toBeInTheDocument(); + expect( + queryByText(getByText('OPENAPI').parentElement!, 'API'), + ).toBeInTheDocument(); expect(() => getByText('LIBRARY')).toThrow(); }); @@ -246,7 +252,7 @@ describe('OwnershipCard', () => { expect(getByText('OPENAPI').closest('a')).toHaveAttribute( 'href', - '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D=my-team&filters%5Buser%5D=all', + '/create/?filters%5Bkind%5D=api&filters%5Btype%5D=openapi&filters%5Bowners%5D=my-team&filters%5Buser%5D=all', ); }); @@ -292,7 +298,7 @@ describe('OwnershipCard', () => { expect(getByText('OPENAPI').closest('a')).toHaveAttribute( 'href', - '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D=user%3Athe-user&filters%5Bowners%5D=my-team&filters%5Bowners%5D=custom%2Fsome-team&filters%5Buser%5D=all', + '/create/?filters%5Bkind%5D=api&filters%5Btype%5D=openapi&filters%5Bowners%5D=user%3Athe-user&filters%5Bowners%5D=my-team&filters%5Bowners%5D=custom%2Fsome-team&filters%5Buser%5D=all', ); }); diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index 7c0bb76e2e..c928d9b55f 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -36,7 +36,7 @@ const limiter = limiterFactory(10); type EntityTypeProps = { kind: string; - type: string; + type?: string; count: number; }; @@ -49,7 +49,7 @@ const getQueryParams = ( humanizeEntityRef(parseEntityRef(owner), { defaultKind: 'group' }), ); const filters = { - kind, + kind: kind.toLocaleLowerCase('en-US'), type, owners, user: 'all', @@ -135,7 +135,7 @@ export function useGetEntities( | { counter: number; type: string; - name: string; + kind: string; queryParams: string; }[] | undefined; @@ -173,16 +173,14 @@ export function useGetEntities( const counts = ownedEntitiesList.items.reduce( (acc: EntityTypeProps[], ownedEntity) => { const match = acc.find( - x => - x.kind === ownedEntity.kind && - x.type === (ownedEntity.spec?.type ?? ownedEntity.kind), + x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, ); if (match) { match.count += 1; } else { acc.push({ kind: ownedEntity.kind, - type: ownedEntity.spec?.type?.toString() ?? ownedEntity.kind, + type: ownedEntity.spec?.type?.toString(), count: 1, }); } @@ -197,12 +195,12 @@ export function useGetEntities( return topN.map(topOwnedEntity => ({ counter: topOwnedEntity.count, type: topOwnedEntity.type, - name: topOwnedEntity.type.toLocaleUpperCase('en-US'), + kind: topOwnedEntity.kind, queryParams: getQueryParams(owners, topOwnedEntity), })) as Array<{ counter: number; type: string; - name: string; + kind: string; queryParams: string; }>; }, [catalogApi, entity, relationsType]); diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx index eb7b8fadda..a27be7857b 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx @@ -102,3 +102,43 @@ export default { }), ], }; + +const extraDetailsEntity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: 'guest', + description: 'Description for guest', + links: [ + { + url: 'slack://user?team=T00000000&id=U00000000', + title: 'Slack', + icon: 'chat', + }, + { + url: 'https://www.google.com', + title: 'Google', + }, + ], + }, + spec: { + profile: { + displayName: 'Guest User', + email: 'guest@example.com', + picture: + 'https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff', + }, + memberOf: ['team-a'], + }, + relations: [dummyGroup], +}; + +export const ExtraDetails = () => ( + + + + + + + +); diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx index f339a5828c..fb0df3d25f 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx @@ -155,4 +155,58 @@ describe('Edit Button', () => { ); expect(rendered.getByRole('button')).toBeInTheDocument(); }); + + it('Should show the extra fields if either links or extra profile are filled', async () => { + const annotations: Record = { + 'backstage.io/edit-url': 'https://example.com/user.yaml', + }; + const userEntity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: 'calum.leavy', + description: 'Super awesome human', + annotations, + links: [ + { + url: 'slack://user?team=T00000000&id=U00000000', + title: 'Slack', + icon: 'message', + }, + { + url: 'https://www.google.com', + title: 'Google', + }, + ], + }, + spec: { + profile: { + displayName: 'Calum Leavy', + email: 'calum-leavy@example.com', + }, + memberOf: ['ExampleGroup'], + }, + relations: [ + { + type: 'memberOf', + targetRef: 'group:default/examplegroup', + }, + ], + }; + + const rendered = await renderWithEffects( + wrapInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ), + ); + expect(rendered.getByText('Slack')).toBeInTheDocument(); + expect(rendered.getByText('Google')).toBeInTheDocument(); + }); }); diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx index dd75578687..a35c1c057b 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx @@ -46,6 +46,7 @@ import { InfoCardVariants, Link, } from '@backstage/core-components'; +import { LinksGroup } from '../../Meta'; const CardTitle = (props: { title?: string }) => props.title ? ( @@ -66,7 +67,7 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => { user.metadata.annotations?.[ANNOTATION_EDIT_URL]; const { - metadata: { name: metaName, description }, + metadata: { name: metaName, description, links }, spec: { profile }, } = user; const displayName = profile?.displayName ?? metaName; @@ -128,6 +129,8 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => { /> + + diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index ec4a152a4d..c8f4e7cc4f 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-pagerduty +## 0.5.4 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.4-next.0 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 64ab795489..bdf6668060 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.5.4-next.0", + "version": "0.5.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/pagerduty/src/api/client.ts b/plugins/pagerduty/src/api/client.ts index 7266d5e9eb..7d99be219d 100644 --- a/plugins/pagerduty/src/api/client.ts +++ b/plugins/pagerduty/src/api/client.ts @@ -73,7 +73,7 @@ export class PagerDutyClient implements PagerDutyApi { url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/pagerduty/services?${commonGetServiceParams}&query=${integrationKey}`; - const { services } = await this.getByUrl(url); + const { services } = await this.findByUrl(url); const service = services[0]; if (!service) throw new NotFoundError(); @@ -84,7 +84,7 @@ export class PagerDutyClient implements PagerDutyApi { 'proxy', )}/pagerduty/services/${serviceId}?${commonGetServiceParams}`; - response = await this.getByUrl(url); + response = await this.findByUrl(url); } else { throw new NotFoundError(); } @@ -100,7 +100,7 @@ export class PagerDutyClient implements PagerDutyApi { 'proxy', )}/pagerduty/incidents?${params}`; - return await this.getByUrl(url); + return await this.findByUrl(url); } async getChangeEventsByServiceId( @@ -111,7 +111,7 @@ export class PagerDutyClient implements PagerDutyApi { 'proxy', )}/pagerduty/services/${serviceId}/change_events?${params}`; - return await this.getByUrl(url); + return await this.findByUrl(url); } async getOnCallByPolicyId( @@ -122,7 +122,7 @@ export class PagerDutyClient implements PagerDutyApi { 'proxy', )}/pagerduty/oncalls?${params}`; - return await this.getByUrl(url); + return await this.findByUrl(url); } triggerAlarm(request: PagerDutyTriggerAlarmRequest): Promise { @@ -158,7 +158,7 @@ export class PagerDutyClient implements PagerDutyApi { return this.request(`${url}/enqueue`, options); } - private async getByUrl(url: string): Promise { + private async findByUrl(url: string): Promise { const options = { method: 'GET', headers: { diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 63ca36cc60..7725bf2fe0 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-periskop-backend +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index 3a91af5252..0c23f24efd 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.1.9-next.0", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index afec1859f2..3c583dd8da 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-periskop +## 0.1.9 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 53971e9930..a061553ab2 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.9-next.0", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index d57c79ca08..b8d42cf4cf 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-permission-backend +## 0.5.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + ## 0.5.13-next.0 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 16351d26b9..52d376118a 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.13-next.0", + "version": "0.5.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index 31c212bffd..b5599964b9 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-common +## 0.7.1 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 64848c963c: Properly handle rules that have no parameters in `PermissionClient` +- Updated dependencies + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + ## 0.7.1-next.0 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 394cbe896f..376bdbcf51 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-common", "description": "Isomorphic types and client for Backstage permissions and authorization", - "version": "0.7.1-next.0", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -50,6 +50,6 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "msw": "^0.47.0" + "msw": "^0.48.0" } } diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 2d31993117..743c2af016 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-permission-node +## 0.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + ## 0.7.1-next.0 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 33baf825ac..d21e351f82 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.7.1-next.0", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index c8e1cb072e..ef4d4f46ff 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + ## 0.4.7-next.0 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 857e1a3881..2f978efc38 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.7-next.0", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 9798c12013..ef38cbc96e 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-playlist-backend +## 0.2.1 + +### Patch Changes + +- 605f269f0d: Updated Playlist plugin docs: + + - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features + - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/backend-test-utils@0.1.30 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-playlist-common@0.1.2 + +## 0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + ## 0.2.1-next.1 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 8548a3e4b8..5edb8b0754 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.2.1-next.1", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/playlist-common/CHANGELOG.md b/plugins/playlist-common/CHANGELOG.md index 7dcf06740e..89cb9934f9 100644 --- a/plugins/playlist-common/CHANGELOG.md +++ b/plugins/playlist-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-playlist-common +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/playlist-common/package.json b/plugins/playlist-common/package.json index 287c69495a..baeb49d1ba 100644 --- a/plugins/playlist-common/package.json +++ b/plugins/playlist-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-playlist-common", "description": "Common functionalities for the playlist plugin", - "version": "0.1.2-next.0", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index d7135e79a0..9f965ead21 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-playlist +## 0.1.2 + +### Patch Changes + +- 605f269f0d: Updated Playlist plugin docs: + + - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features + - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/plugin-search-react@1.2.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-playlist-common@0.1.2 + +## 0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 0.1.2-next.1 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index e8fc47a2a9..259cbdcca5 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.2-next.1", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0", + "msw": "^0.48.0", "swr": "^1.1.2" }, "files": [ diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 91c3419ccd..047565b294 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-proxy-backend +## 0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## 0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.2.32-next.0 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 2deee67f17..74c054c1fb 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.2.32-next.0", + "version": "0.2.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", "@types/yup": "^0.29.13", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 962b167902..c4dd8ca52c 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-rollbar-backend +## 0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + +## 0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.1.35-next.0 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 0fb2c0a4e0..30f3d94e77 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.35-next.0", + "version": "0.1.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,7 +52,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 340e06d265..47ebcbd1f0 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-rollbar +## 0.4.11 + +### Patch Changes + +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.11-next.0 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 1c4b585f5f..1843222577 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.4.11-next.0", + "version": "0.4.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 37d00c6885..4c108955cc 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.13-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 939e2801da..8b0a58d416 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.2.13-next.1", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", "mock-fs": "^5.1.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 65f0b6cc49..cf235ed430 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/integration@1.4.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.4.6-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 8f39024301..a068484bdc 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.4.6-next.1", + "version": "0.4.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 56cc580bbd..745f478ecc 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index cf7a13a7a4..a1d17283ed 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.2.11-next.1", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 0a86b5e9bb..bdafef8ee3 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,92 @@ # @backstage/plugin-scaffolder-backend +## 1.8.0 + +### Minor Changes + +- ea14eb62a2: Added a set of default Prometheus metrics around scaffolding. See below for a list of metrics and an explanation of their labels: + + - `scaffolder_task_count`: Tracks successful task runs. + + Labels: + + - `template`: The entity ref of the scaffolded template + - `user`: The entity ref of the user that invoked the template run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + - `scaffolder_task_duration`: a histogram which tracks the duration of a task run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `result`: A boolean describing whether the task ran successfully + + - `scaffolder_step_count`: a count that tracks each step run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `step`: The name of the step that was run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + - `scaffolder_step_duration`: a histogram which tracks the duration of each step run + + Labels: + + - `template`: The entity ref of the scaffolded template + - `step`: The name of the step that was run + - `result`: A string describing whether the task ran successfully, failed, or was skipped + + You can find a guide for running Prometheus metrics here: https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/prometheus-metrics.md + +- 5921b5ce49: - The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project. +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-catalog-backend@1.5.1 + - @backstage/integration@1.4.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/backend-plugin-api@0.1.4 + - @backstage/plugin-catalog-node@1.2.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-scaffolder-common@1.2.2 + +## 1.8.0-next.2 + +### Minor Changes + +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + ## 1.8.0-next.1 ### Minor Changes diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 846fa59b08..50395ed4c9 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -198,6 +198,13 @@ export function createGithubRepoCreateAction(options: { allowMergeCommit?: boolean | undefined; allowAutoMerge?: boolean | undefined; requireCodeOwnerReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[] | undefined; + teams?: string[] | undefined; + apps?: string[] | undefined; + } + | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; repoVisibility?: 'internal' | 'private' | 'public' | undefined; @@ -236,6 +243,13 @@ export function createGithubRepoPushAction(options: { gitAuthorName?: string | undefined; gitAuthorEmail?: string | undefined; requireCodeOwnerReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; sourcePath?: string | undefined; @@ -366,6 +380,13 @@ export function createPublishGithubAction(options: { allowMergeCommit?: boolean | undefined; allowAutoMerge?: boolean | undefined; sourcePath?: string | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requireCodeOwnerReviews?: boolean | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; @@ -422,6 +443,7 @@ export function createPublishGitlabAction(options: { gitAuthorName?: string | undefined; gitAuthorEmail?: string | undefined; setUserAsOwner?: boolean | undefined; + topics?: string[] | undefined; }>; // @public diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index a52adf1cf7..d5371053ca 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.8.0-next.1", + "version": "1.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -77,7 +77,7 @@ "vm2": "^3.9.11", "winston": "^3.2.1", "yaml": "^2.0.0", - "zen-observable": "^0.8.15", + "zen-observable": "^0.9.0", "zod": "^3.11.6" }, "devDependencies": { @@ -90,10 +90,10 @@ "@types/nunjucks": "^3.1.4", "@types/supertest": "^2.0.8", "@types/zen-observable": "^0.8.0", - "esbuild": "^0.14.1", + "esbuild": "^0.15.0", "jest-when": "^3.1.0", "mock-fs": "^5.1.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3", "yaml": "^2.0.0" }, diff --git a/plugins/scaffolder-backend/scripts/build-nunjucks.js b/plugins/scaffolder-backend/scripts/build-nunjucks.js index b195f96159..8b98ac4305 100755 --- a/plugins/scaffolder-backend/scripts/build-nunjucks.js +++ b/plugins/scaffolder-backend/scripts/build-nunjucks.js @@ -58,7 +58,7 @@ require('esbuild') bundle: true, format: 'cjs', platform: 'node', - target: 'node14', + target: 'node16', banner: { js: NUNJUCKS_LICENSE }, external: ['fsevents'], outfile: path.resolve(__dirname, '../assets/nunjucks.js.txt'), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts index 9348526b20..760f42eade 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts @@ -52,6 +52,11 @@ export function createGithubRepoCreateAction(options: { allowMergeCommit?: boolean; allowAutoMerge?: boolean; requireCodeOwnerReviews?: boolean; + bypassPullRequestAllowances?: { + users?: string[]; + teams?: string[]; + apps?: string[]; + }; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; repoVisibility?: 'private' | 'internal' | 'public'; @@ -85,6 +90,7 @@ export function createGithubRepoCreateAction(options: { homepage: inputProps.homepage, access: inputProps.access, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, repoVisibility: inputProps.repoVisibility, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts index b02a475698..1694e37710 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts @@ -49,6 +49,13 @@ export function createGithubRepoPushAction(options: { gitAuthorName?: string; gitAuthorEmail?: string; requireCodeOwnerReviews?: boolean; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; sourcePath?: string; @@ -65,6 +72,7 @@ export function createGithubRepoPushAction(options: { repoUrl: inputProps.repoUrl, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, defaultBranch: inputProps.defaultBranch, protectDefaultBranch: inputProps.protectDefaultBranch, @@ -94,6 +102,7 @@ export function createGithubRepoPushAction(options: { gitAuthorName, gitAuthorEmail, requireCodeOwnerReviews = false, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, token: providedToken, @@ -131,6 +140,7 @@ export function createGithubRepoPushAction(options: { client, repo, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts, requireBranchesToBeUpToDate, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts index 2264da1dac..fe29378e2e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { Config } from '@backstage/config'; import { assertError, InputError } from '@backstage/errors'; import { @@ -124,6 +125,7 @@ export async function createGithubRepoWithCollaboratorsAndTopics( topics: string[] | undefined, logger: Logger, ) { + // eslint-disable-next-line testing-library/no-await-sync-query const user = await client.rest.users.getByUsername({ username: owner, }); @@ -247,6 +249,13 @@ export async function initRepoPushAndProtect( client: Octokit, repo: string, requireCodeOwnerReviews: boolean, + bypassPullRequestAllowances: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined, requiredStatusCheckContexts: string[], requireBranchesToBeUpToDate: boolean, config: Config, @@ -289,6 +298,7 @@ export async function initRepoPushAndProtect( repoName: repo, logger, defaultBranch, + bypassPullRequestAllowances, requireCodeOwnerReviews, requiredStatusCheckContexts, requireBranchesToBeUpToDate, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts index b00d5fa132..e832c3dbfa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts @@ -147,6 +147,35 @@ const protectEnforceAdmins = { type: 'boolean', description: `Enforce admins to adhere to default branch protection. The default value is 'true'`, }; + +const bypassPullRequestAllowances = { + title: 'Bypass pull request requirements', + description: + 'Allow specific users, teams, or apps to bypass pull request requirements.', + type: 'object', + additionalProperties: false, + properties: { + apps: { + type: 'array', + items: { + type: 'string', + }, + }, + users: { + type: 'array', + items: { + type: 'string', + }, + }, + teams: { + type: 'array', + items: { + type: 'string', + }, + }, + }, +}; + const gitCommitMessage = { title: 'Git Commit Message', type: 'string', @@ -174,6 +203,7 @@ export { gitCommitMessage }; export { homepage }; export { protectDefaultBranch }; export { protectEnforceAdmins }; +export { bypassPullRequestAllowances }; export { repoUrl }; export { repoVisibility }; export { requireCodeOwnerReviews }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts index be77d27a9a..5afe51cc35 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts @@ -185,6 +185,11 @@ type BranchProtectionOptions = { logger: Logger; requireCodeOwnerReviews: boolean; requiredStatusCheckContexts?: string[]; + bypassPullRequestAllowances?: { + users?: string[]; + teams?: string[]; + apps?: string[]; + }; requireBranchesToBeUpToDate?: boolean; defaultBranch?: string; enforceAdmins?: boolean; @@ -196,6 +201,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ owner, logger, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, defaultBranch = 'master', @@ -226,6 +232,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ required_pull_request_reviews: { required_approving_review_count: 1, require_code_owner_reviews: requireCodeOwnerReviews, + bypass_pull_request_allowances: bypassPullRequestAllowances, }, }); } catch (e) { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index c1f8e8b5b6..be4cbb1dad 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -29,6 +29,7 @@ import { import * as inputProps from '../github/inputProperties'; import * as outputProps from '../github/outputProperties'; import { parseRepoUrl } from './util'; + /** * Creates a new action that initializes a git repository of the content in the workspace * and publishes it to GitHub. @@ -59,6 +60,13 @@ export function createPublishGithubAction(options: { allowMergeCommit?: boolean; allowAutoMerge?: boolean; sourcePath?: string; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requireCodeOwnerReviews?: boolean; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; @@ -93,6 +101,7 @@ export function createPublishGithubAction(options: { description: inputProps.description, homepage: inputProps.homepage, access: inputProps.access, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, @@ -129,6 +138,7 @@ export function createPublishGithubAction(options: { homepage, access, requireCodeOwnerReviews = false, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, repoVisibility = 'private', @@ -195,6 +205,7 @@ export function createPublishGithubAction(options: { client, repo, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts, requireBranchesToBeUpToDate, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts index 9fc95b1b5e..53669efd0b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -44,6 +44,7 @@ export function createPublishGitlabAction(options: { gitAuthorName?: string; gitAuthorEmail?: string; setUserAsOwner?: boolean; + topics?: string[]; }>({ id: 'publish:gitlab', description: @@ -99,6 +100,14 @@ export function createPublishGitlabAction(options: { description: 'Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host', }, + topics: { + title: 'Topic labels', + description: 'Topic labels to apply on the repository.', + type: 'array', + items: { + type: 'string', + }, + }, }, }, output: { @@ -128,6 +137,7 @@ export function createPublishGitlabAction(options: { gitAuthorName, gitAuthorEmail, setUserAsOwner = false, + topics = [], } = ctx.input; const { owner, repo, host } = parseRepoUrl(repoUrl, integrations); @@ -173,6 +183,7 @@ export function createPublishGitlabAction(options: { namespace_id: targetNamespace, name: repo, visibility: repoVisibility, + ...(topics.length ? { topics } : {}), }); // When setUserAsOwner is true the input token is expected to come from an unprivileged user GitLab diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index eff7e95c50..634e344a2c 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -23,9 +23,10 @@ import { stringifyEntityRef, UserEntity, } from '@backstage/catalog-model'; -import { Config, JsonObject, JsonValue } from '@backstage/config'; +import { Config } from '@backstage/config'; import { InputError, NotFoundError, stringifyError } from '@backstage/errors'; import { ScmIntegrations } from '@backstage/integration'; +import { JsonObject, JsonValue } from '@backstage/types'; import { TaskSpec, TemplateEntityV1beta3, diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index b6f8b3e77b..88cdd66d95 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-scaffolder-common +## 1.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + ## 1.2.2-next.0 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 6db049aaed..4c244d4535 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "1.2.2-next.0", + "version": "1.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 709809f5f7..d40cacd62b 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/plugin-scaffolder +## 1.8.0 + +### Minor Changes + +- edae17309e: Added props to override default Scaffolder page title, subtitle and pageTitleOverride. + Routes like `rootRouteRef`, `selectedTemplateRouteRef`, `nextRouteRef`, `nextSelectedTemplateRouteRef` were made public and can be used in your app (e.g. in custom TemplateCard component). + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. +- 4830a3569f: Basic analytics instrumentation is now in place: + + - As users make their way through template steps, a `click` event is fired, including the step number. + - After a user clicks "Create" a `create` event is fired, including the name of the software that was just created. The template used at creation is set on the `entityRef` context key. + +- 94b7ca9c6d: Updated to use `@rjsf` packages of version `^5.0.0-beta.12` +- 87840c8c6c: Fixed tiny grammar error in EntityNamePicker. The first letter of the description is now capitalized. +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version +- b2bb48a6f4: Fix the return type for the `createNextScaffodlerFieldExtension` type as before it wasn't a component type for the extension +- f905853ad6: Prefer using `Link` from `@backstage/core-components` rather than material-UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/integration-react@1.1.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-permission-react@0.4.7 + - @backstage/plugin-scaffolder-common@1.2.2 + +## 1.8.0-next.1 + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + ## 1.8.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 158c75e5bd..33a5f8c2fe 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -11,6 +11,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import type { ErrorTransformer } from '@rjsf/utils'; import { Extension } from '@backstage/core-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; @@ -35,6 +36,7 @@ import { TaskStep } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { UIOptionsType } from '@rjsf/utils'; import { UiSchema } from '@rjsf/utils'; +import { z } from 'zod'; // @alpha export function createNextScaffolderFieldExtension< @@ -42,7 +44,7 @@ export function createNextScaffolderFieldExtension< TInputProps extends UIOptionsType = {}, >( options: NextFieldExtensionOptions, -): Extension>; +): Extension>; // @public export function createScaffolderFieldExtension< @@ -57,6 +59,12 @@ export function createScaffolderLayout( options: LayoutOptions, ): Extension>; +// @public +export type CustomFieldExtensionSchema = { + returnValue: JSONSchema7; + uiOptions?: JSONSchema7; +}; + // @public export type CustomFieldValidator = ( data: TFieldReturnValue, @@ -75,36 +83,52 @@ export const EntityNamePickerFieldExtension: FieldExtensionComponent< // @public export const EntityPickerFieldExtension: FieldExtensionComponent< string, - EntityPickerUiOptions + { + defaultKind?: string | undefined; + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } +>; + +// @public (undocumented) +export const EntityPickerFieldSchema: FieldSchema< + string, + { + defaultKind?: string | undefined; + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } >; // @public -export interface EntityPickerUiOptions { - // (undocumented) - allowArbitraryValues?: boolean; - // (undocumented) - allowedKinds?: string[]; - // (undocumented) - defaultKind?: string; - // (undocumented) - defaultNamespace?: string | false; -} +export type EntityPickerUiOptions = + typeof EntityPickerFieldSchema.uiOptionsType; // @public export const EntityTagsPickerFieldExtension: FieldExtensionComponent< string[], - EntityTagsPickerUiOptions + { + showCounts?: boolean | undefined; + kinds?: string[] | undefined; + helperText?: string | undefined; + } +>; + +// @public (undocumented) +export const EntityTagsPickerFieldSchema: FieldSchema< + string[], + { + showCounts?: boolean | undefined; + kinds?: string[] | undefined; + helperText?: string | undefined; + } >; // @public -export interface EntityTagsPickerUiOptions { - // (undocumented) - helperText?: string; - // (undocumented) - kinds?: string[]; - // (undocumented) - showCounts?: boolean; -} +export type EntityTagsPickerUiOptions = + typeof EntityTagsPickerFieldSchema.uiOptionsType; // @public export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; @@ -130,8 +154,19 @@ export type FieldExtensionOptions< props: FieldExtensionComponentProps, ) => JSX.Element | null; validation?: CustomFieldValidator; + schema?: CustomFieldExtensionSchema; }; +// @public +export interface FieldSchema { + // (undocumented) + readonly schema: CustomFieldExtensionSchema; + // (undocumented) + readonly type: FieldExtensionComponentProps; + // (undocumented) + readonly uiOptionsType: TUiOptions; +} + // @public export type LayoutComponent<_TInputProps> = () => null; @@ -169,6 +204,20 @@ export type LogEvent = { taskId: string; }; +// @public +export function makeFieldSchemaFromZod< + TReturnSchema extends z.ZodType, + TUiOptionsSchema extends z.ZodType = z.ZodType, +>( + returnSchema: TReturnSchema, + uiOptionsSchema?: TUiOptionsSchema, +): FieldSchema< + TReturnSchema extends z.ZodType ? IReturn : never, + TUiOptionsSchema extends z.ZodType + ? IUiOptions + : never +>; + // @alpha export type NextCustomFieldValidator = ( data: TFieldReturnValue, @@ -199,6 +248,7 @@ export type NextFieldExtensionOptions< props: NextFieldExtensionComponentProps, ) => JSX.Element | null; validation?: NextCustomFieldValidator; + schema?: CustomFieldExtensionSchema; }; // @alpha (undocumented) @@ -213,6 +263,7 @@ export type NextRouterProps = { TaskPageComponent?: React_2.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; + transformErrors?: ErrorTransformer; }; // @alpha @@ -228,36 +279,51 @@ export const nextSelectedTemplateRouteRef: SubRouteRef< // @public export const OwnedEntityPickerFieldExtension: FieldExtensionComponent< string, - OwnedEntityPickerUiOptions + { + defaultKind?: string | undefined; + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } +>; + +// @public (undocumented) +export const OwnedEntityPickerFieldSchema: FieldSchema< + string, + { + defaultKind?: string | undefined; + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } >; // @public -export interface OwnedEntityPickerUiOptions { - // (undocumented) - allowArbitraryValues?: boolean; - // (undocumented) - allowedKinds?: string[]; - // (undocumented) - defaultKind?: string; - // (undocumented) - defaultNamespace?: string | false; -} +export type OwnedEntityPickerUiOptions = + typeof OwnedEntityPickerFieldSchema.uiOptionsType; // @public export const OwnerPickerFieldExtension: FieldExtensionComponent< string, - OwnerPickerUiOptions + { + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } +>; + +// @public (undocumented) +export const OwnerPickerFieldSchema: FieldSchema< + string, + { + defaultNamespace?: string | false | undefined; + allowedKinds?: string[] | undefined; + allowArbitraryValues?: boolean | undefined; + } >; // @public -export interface OwnerPickerUiOptions { - // (undocumented) - allowArbitraryValues?: boolean; - // (undocumented) - allowedKinds?: string[]; - // (undocumented) - defaultNamespace?: string | false; -} +export type OwnerPickerUiOptions = typeof OwnerPickerFieldSchema.uiOptionsType; // @public export const repoPickerValidation: ( @@ -271,31 +337,56 @@ export const repoPickerValidation: ( // @public export const RepoUrlPickerFieldExtension: FieldExtensionComponent< string, - RepoUrlPickerUiOptions + { + allowedOwners?: string[] | undefined; + allowedOrganizations?: string[] | undefined; + allowedRepos?: string[] | undefined; + allowedHosts?: string[] | undefined; + requestUserCredentials?: + | { + additionalScopes?: + | { + azure?: string[] | undefined; + github?: string[] | undefined; + gitlab?: string[] | undefined; + bitbucket?: string[] | undefined; + gerrit?: string[] | undefined; + } + | undefined; + secretsKey: string; + } + | undefined; + } +>; + +// @public (undocumented) +export const RepoUrlPickerFieldSchema: FieldSchema< + string, + { + allowedOwners?: string[] | undefined; + allowedOrganizations?: string[] | undefined; + allowedRepos?: string[] | undefined; + allowedHosts?: string[] | undefined; + requestUserCredentials?: + | { + additionalScopes?: + | { + azure?: string[] | undefined; + github?: string[] | undefined; + gitlab?: string[] | undefined; + bitbucket?: string[] | undefined; + gerrit?: string[] | undefined; + } + | undefined; + secretsKey: string; + } + | undefined; + } >; // @public -export interface RepoUrlPickerUiOptions { - // (undocumented) - allowedHosts?: string[]; - // (undocumented) - allowedOrganizations?: string[]; - // (undocumented) - allowedOwners?: string[]; - // (undocumented) - allowedRepos?: string[]; - // (undocumented) - requestUserCredentials?: { - secretsKey: string; - additionalScopes?: { - gerrit?: string[]; - github?: string[]; - gitlab?: string[]; - bitbucket?: string[]; - azure?: string[]; - }; - }; -} +export type RepoUrlPickerUiOptions = + typeof RepoUrlPickerFieldSchema.uiOptionsType; // @public (undocumented) export const rootRouteRef: RouteRef; diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index cfa69c128a..adb7461dd9 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.8.0-next.0", + "version": "1.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,11 +55,11 @@ "@material-ui/lab": "4.0.0-alpha.57", "@react-hookz/web": "^15.0.0", "@rjsf/core": "^3.2.1", - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.10", + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12", "@rjsf/material-ui": "^3.2.1", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.10", - "@rjsf/utils": "^5.0.0-beta.10", - "@rjsf/validator-ajv8": "^5.0.0-beta.10", + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12", + "@rjsf/utils": "^5.0.0-beta.12", + "@rjsf/validator-ajv8": "^5.0.0-beta.12", "@types/json-schema": "^7.0.9", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", @@ -74,7 +74,9 @@ "react-use": "^17.2.4", "use-immer": "^0.7.0", "yaml": "^2.0.0", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0", + "zod": "^3.11.6", + "zod-to-json-schema": "^3.18.1" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", @@ -96,7 +98,7 @@ "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "event-source-polyfill": "1.0.25", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx b/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx index 837b87437f..57dde13a43 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx @@ -236,7 +236,7 @@ describe('', () => { ); await act(async () => { - const allButton = await getByText('All'); + const allButton = getByText('All'); fireEvent.click(allButton); }); diff --git a/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.test.tsx b/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.test.tsx index 63f943d6dd..7c335a0ef7 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.test.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/OwnerListPicker.test.tsx @@ -15,7 +15,6 @@ */ import { renderInTestApp } from '@backstage/test-utils'; - import React from 'react'; import { OwnerListPicker } from './OwnerListPicker'; import { fireEvent } from '@testing-library/react'; @@ -29,8 +28,8 @@ describe('', () => { const { getByText } = await renderInTestApp(); - expect(await getByText('Owned')).toBeDefined(); - expect(await getByText('All')).toBeDefined(); + expect(getByText('Owned')).toBeDefined(); + expect(getByText('All')).toBeDefined(); }); it('should call the function on select other item', async () => { @@ -41,7 +40,7 @@ describe('', () => { const { getByText } = await renderInTestApp(); - fireEvent.click(await getByText('All')); + fireEvent.click(getByText('All')); expect(props.onSelectOwner).toHaveBeenCalledWith('all'); }); }); diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index 097eddf6cd..9f46b427a0 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -163,6 +163,7 @@ export const Router = (props: RouterProps) => { } diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx new file mode 100644 index 0000000000..3510968acd --- /dev/null +++ b/plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx @@ -0,0 +1,201 @@ +/* + * Copyright 2022 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 { StreamLanguage } from '@codemirror/language'; +import { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml'; +import { + Button, + Card, + CardContent, + CardHeader, + FormControl, + IconButton, + InputLabel, + makeStyles, + MenuItem, + Select, +} from '@material-ui/core'; +import CloseIcon from '@material-ui/icons/Close'; +import { withTheme } from '@rjsf/core'; +import { Theme as MuiTheme } from '@rjsf/material-ui'; +import CodeMirror from '@uiw/react-codemirror'; +import React, { useCallback, useMemo, useState } from 'react'; +import yaml from 'yaml'; +import { FieldExtensionOptions } from '../../extensions'; +import * as fieldOverrides from '../MultistepJsonForm/FieldOverrides'; +import { TemplateEditorForm } from './TemplateEditorForm'; + +const Form = withTheme(MuiTheme); + +const useStyles = makeStyles(theme => ({ + root: { + gridArea: 'pageContent', + display: 'grid', + gridTemplateAreas: ` + "controls controls" + "fieldForm preview" + `, + gridTemplateRows: 'auto 1fr', + gridTemplateColumns: '1fr 1fr', + }, + controls: { + gridArea: 'controls', + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + margin: theme.spacing(1), + }, + fieldForm: { + gridArea: 'fieldForm', + }, + preview: { + gridArea: 'preview', + }, +})); + +export const CustomFieldExplorer = ({ + customFieldExtensions = [], + onClose, +}: { + customFieldExtensions?: FieldExtensionOptions[]; + onClose?: () => void; +}) => { + const classes = useStyles(); + const fieldOptions = customFieldExtensions.filter(field => !!field.schema); + const [selectedField, setSelectedField] = useState(fieldOptions[0]); + const [fieldFormState, setFieldFormState] = useState({}); + const [formState, setFormState] = useState({}); + const [refreshKey, setRefreshKey] = useState(Date.now()); + const sampleFieldTemplate = useMemo( + () => + yaml.stringify({ + parameters: [ + { + title: `${selectedField.name} Example`, + properties: { + [selectedField.name]: { + type: selectedField.schema?.returnValue?.type, + 'ui:field': selectedField.name, + 'ui:options': fieldFormState, + }, + }, + }, + ], + }), + [fieldFormState, selectedField], + ); + + const fieldComponents = useMemo(() => { + return Object.fromEntries( + customFieldExtensions.map(({ name, component }) => [name, component]), + ); + }, [customFieldExtensions]); + + const handleSelectionChange = useCallback( + selection => { + setSelectedField(selection); + setFieldFormState({}); + setFormState({}); + }, + [setFieldFormState, setFormState, setSelectedField], + ); + + const handleFieldConfigChange = useCallback( + state => { + setFieldFormState(state); + setFormState({}); + // Force TemplateEditorForm to re-render since some fields + // may not be responsive to ui:option changes + setRefreshKey(Date.now()); + }, + [setFieldFormState, setRefreshKey], + ); + + return ( +
+
+ + + Choose Custom Field Extension + + + + + + + +
+
+ + + +
handleFieldConfigChange(e.formData)} + schema={selectedField.schema?.uiOptions || {}} + > + + +
+
+
+
+ + + + + + + null} + /> +
+
+ ); +}; diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx index dc411ee965..61e6c46964 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx @@ -44,7 +44,7 @@ const useStyles = makeStyles(theme => ({ interface EditorIntroProps { style?: JSX.IntrinsicElements['div']['style']; - onSelect?: (option: 'local' | 'form') => void; + onSelect?: (option: 'local' | 'form' | 'field-explorer') => void; } export function TemplateEditorIntro(props: EditorIntroProps) { @@ -104,6 +104,22 @@ export function TemplateEditorIntro(props: EditorIntroProps) { ); + const cardFieldExplorer = ( + + props.onSelect?.('field-explorer')}> + + + Custom Field Explorer + + + View and play around with available installed custom field + extensions. + + + + + ); + return (
@@ -121,6 +137,7 @@ export function TemplateEditorIntro(props: EditorIntroProps) { {supportsLoad && cardLoadLocal} {cardFormEditor} {!supportsLoad && cardLoadLocal} + {cardFieldExplorer}
); diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx index b539b6403b..8847b85373 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx @@ -19,6 +19,7 @@ import { TemplateDirectoryAccess, WebFileSystemAccess, } from '../../lib/filesystem'; +import { CustomFieldExplorer } from './CustomFieldExplorer'; import { TemplateEditorIntro } from './TemplateEditorIntro'; import { TemplateEditor } from './TemplateEditor'; import { TemplateFormPreviewer } from './TemplateFormPreviewer'; @@ -32,6 +33,9 @@ type Selection = } | { type: 'form'; + } + | { + type: 'field-explorer'; }; interface TemplateEditorPageProps { @@ -62,6 +66,13 @@ export function TemplateEditorPage(props: TemplateEditorPageProps) { layouts={props.layouts} /> ); + } else if (selection?.type === 'field-explorer') { + content = ( + setSelection(undefined)} + /> + ); } else { content = ( @@ -73,6 +84,8 @@ export function TemplateEditorPage(props: TemplateEditorPageProps) { .catch(() => {}); } else if (option === 'form') { setSelection({ type: 'form' }); + } else if (option === 'field-explorer') { + setSelection({ type: 'field-explorer' }); } }} /> diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index a48644e72d..71f5ffad47 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { MockAnalyticsApi, renderInTestApp, @@ -340,9 +341,9 @@ describe('TemplatePage', () => { }, ); - expect(await queryByText('Name')).not.toBeInTheDocument(); - expect(await queryByText('Description')).toBeInTheDocument(); - expect(await queryByText('Owner')).toBeInTheDocument(); - expect(await queryByText('Send data')).toBeInTheDocument(); + expect(queryByText('Name')).not.toBeInTheDocument(); + expect(queryByText('Description')).toBeInTheDocument(); + expect(queryByText('Owner')).toBeInTheDocument(); + expect(queryByText('Send data')).toBeInTheDocument(); }); }); diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 87678d2a83..522f37dfc9 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -51,13 +51,21 @@ const useTemplateParameterSchema = (templateRef: string) => { return { schema: value, loading, error }; }; +type Props = { + customFieldExtensions?: FieldExtensionOptions[]; + layouts?: LayoutOptions[]; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; +}; + export const TemplatePage = ({ customFieldExtensions = [], layouts = [], -}: { - customFieldExtensions?: FieldExtensionOptions[]; - layouts?: LayoutOptions[]; -}) => { + headerOptions, +}: Props) => { const apiHolder = useApiHolder(); const secretsContext = useContext(SecretsContext); const errorApi = useApi(errorApiRef); @@ -136,6 +144,7 @@ export const TemplatePage = ({ pageTitleOverride="Create a New Component" title="Create a New Component" subtitle="Create new software components using standard templates" + {...headerOptions} /> {loading && } diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx b/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx index 802135a863..555b726917 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx @@ -14,15 +14,15 @@ * limitations under the License. */ import React from 'react'; -import { FieldExtensionComponentProps } from '../../../extensions'; +import { EntityNamePickerProps } from './schema'; import { TextField } from '@material-ui/core'; +export { EntityNamePickerSchema } from './schema'; + /** * EntityName Picker */ -export const EntityNamePicker = ( - props: FieldExtensionComponentProps, -) => { +export const EntityNamePicker = (props: EntityNamePickerProps) => { const { onChange, required, diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/schema.ts b/plugins/scaffolder/src/components/fields/EntityNamePicker/schema.ts new file mode 100644 index 0000000000..27e33befb5 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/schema.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +const EntityNamePickerFieldSchema = makeFieldSchemaFromZod(z.string()); + +export const EntityNamePickerSchema = EntityNamePickerFieldSchema.schema; + +export type EntityNamePickerProps = typeof EntityNamePickerFieldSchema.type; diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts index 7a40a460ba..d116bef228 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts @@ -23,7 +23,7 @@ export const entityNamePickerValidation = ( ) => { if (!KubernetesValidatorFunctions.isValidObjectName(value)) { validation.addError( - 'must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.', + 'Must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.', ); } }; diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index e7883a4721..bc78e00576 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -23,20 +23,9 @@ import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import React, { useCallback, useEffect } from 'react'; import useAsync from 'react-use/lib/useAsync'; -import { FieldExtensionComponentProps } from '../../../extensions'; +import { EntityPickerProps } from './schema'; -/** - * The input props that can be specified under `ui:options` for the - * `EntityPicker` field extension. - * - * @public - */ -export interface EntityPickerUiOptions { - allowedKinds?: string[]; - defaultKind?: string; - allowArbitraryValues?: boolean; - defaultNamespace?: string | false; -} +export { EntityPickerSchema } from './schema'; /** * The underlying component that is rendered in the form for the `EntityPicker` @@ -44,9 +33,7 @@ export interface EntityPickerUiOptions { * * @public */ -export const EntityPicker = ( - props: FieldExtensionComponentProps, -) => { +export const EntityPicker = (props: EntityPickerProps) => { const { onChange, schema: { title = 'Entity', description = 'An entity from the catalog' }, diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/index.ts b/plugins/scaffolder/src/components/fields/EntityPicker/index.ts index 891b5bef16..b8df596c98 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/EntityPicker/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { EntityPickerUiOptions } from './EntityPicker'; +export { EntityPickerFieldSchema, type EntityPickerUiOptions } from './schema'; diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts b/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts new file mode 100644 index 0000000000..9236457fc0 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2022 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const EntityPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + allowedKinds: z + .array(z.string()) + .optional() + .describe('List of kinds of entities to derive options from'), + defaultKind: z + .string() + .optional() + .describe( + 'The default entity kind. Options of this kind will not be prefixed.', + ), + allowArbitraryValues: z + .boolean() + .optional() + .describe('Whether to allow arbitrary user input. Defaults to true'), + defaultNamespace: z + .union([z.string(), z.literal(false)]) + .optional() + .describe( + 'The default namespace. Options with this namespace will not be prefixed.', + ), + }), +); + +/** + * The input props that can be specified under `ui:options` for the + * `EntityPicker` field extension. + * + * @public + */ +export type EntityPickerUiOptions = + typeof EntityPickerFieldSchema.uiOptionsType; + +export type EntityPickerProps = typeof EntityPickerFieldSchema.type; + +export const EntityPickerSchema = EntityPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx index c0e3aab436..549ccdb8aa 100644 --- a/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx @@ -22,19 +22,9 @@ import { useApi } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { FormControl, TextField } from '@material-ui/core'; import { Autocomplete } from '@material-ui/lab'; -import { FieldExtensionComponentProps } from '../../../extensions'; +import { EntityTagsPickerProps } from './schema'; -/** - * The input props that can be specified under `ui:options` for the - * `EntityTagsPicker` field extension. - * - * @public - */ -export interface EntityTagsPickerUiOptions { - kinds?: string[]; - showCounts?: boolean; - helperText?: string; -} +export { EntityTagsPickerSchema } from './schema'; /** * The underlying component that is rendered in the form for the `EntityTagsPicker` @@ -42,9 +32,7 @@ export interface EntityTagsPickerUiOptions { * * @public */ -export const EntityTagsPicker = ( - props: FieldExtensionComponentProps, -) => { +export const EntityTagsPicker = (props: EntityTagsPickerProps) => { const { formData, onChange, uiSchema } = props; const catalogApi = useApi(catalogApiRef); const [tagOptions, setTagOptions] = useState([]); diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts index 9ff6e553a6..52bad9a80d 100644 --- a/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts @@ -13,4 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { EntityTagsPickerUiOptions } from './EntityTagsPicker'; +export { + EntityTagsPickerFieldSchema, + type EntityTagsPickerUiOptions, +} from './schema'; diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/schema.ts b/plugins/scaffolder/src/components/fields/EntityTagsPicker/schema.ts new file mode 100644 index 0000000000..6677d16e98 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/schema.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2022 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const EntityTagsPickerFieldSchema = makeFieldSchemaFromZod( + z.array(z.string()), + z.object({ + kinds: z + .array(z.string()) + .optional() + .describe('List of kinds of entities to derive tags from'), + showCounts: z + .boolean() + .optional() + .describe('Whether to show usage counts per tag'), + helperText: z.string().optional().describe('Helper text to display'), + }), +); + +export const EntityTagsPickerSchema = EntityTagsPickerFieldSchema.schema; + +export type EntityTagsPickerProps = typeof EntityTagsPickerFieldSchema.type; + +/** + * The input props that can be specified under `ui:options` for the + * `EntityTagsPicker` field extension. + * + * @public + */ +export type EntityTagsPickerUiOptions = + typeof EntityTagsPickerFieldSchema.uiOptionsType; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index 2446883a86..01a174a6a3 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -26,20 +26,9 @@ import Autocomplete from '@material-ui/lab/Autocomplete'; import React, { useMemo } from 'react'; import useAsync from 'react-use/lib/useAsync'; -import { FieldExtensionComponentProps } from '../../../extensions'; +import { OwnedEntityPickerProps } from './schema'; -/** - * The input props that can be specified under `ui:options` for the - * `OwnedEntityPicker` field extension. - * - * @public - */ -export interface OwnedEntityPickerUiOptions { - allowedKinds?: string[]; - defaultKind?: string; - allowArbitraryValues?: boolean; - defaultNamespace?: string | false; -} +export { OwnedEntityPickerSchema } from './schema'; /** * The underlying component that is rendered in the form for the `OwnedEntityPicker` @@ -47,9 +36,7 @@ export interface OwnedEntityPickerUiOptions { * * @public */ -export const OwnedEntityPicker = ( - props: FieldExtensionComponentProps, -) => { +export const OwnedEntityPicker = (props: OwnedEntityPickerProps) => { const { onChange, schema: { title = 'Entity', description = 'An entity from the catalog' }, diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts index 2988ba8cdc..985dae1d3c 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts @@ -13,4 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { OwnedEntityPickerUiOptions } from './OwnedEntityPicker'; +export { + OwnedEntityPickerFieldSchema, + type OwnedEntityPickerUiOptions, +} from './schema'; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/schema.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/schema.ts new file mode 100644 index 0000000000..4190b89f95 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/schema.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const OwnedEntityPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + allowedKinds: z + .array(z.string()) + .optional() + .describe('List of kinds of entities to derive options from'), + defaultKind: z + .string() + .optional() + .describe( + 'The default entity kind. Options of this kind will not be prefixed.', + ), + allowArbitraryValues: z + .boolean() + .optional() + .describe('Whether to allow arbitrary user input. Defaults to true'), + defaultNamespace: z + .union([z.string(), z.literal(false)]) + .optional() + .describe( + 'The default namespace. Options with this namespace will not be prefixed.', + ), + }), +); + +/** + * The input props that can be specified under `ui:options` for the + * `OwnedEntityPicker` field extension. + * + * @public + */ +export type OwnedEntityPickerUiOptions = + typeof OwnedEntityPickerFieldSchema.uiOptionsType; + +export type OwnedEntityPickerProps = typeof OwnedEntityPickerFieldSchema.type; + +export const OwnedEntityPickerSchema = OwnedEntityPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx index 3de2b12bd0..1c4c356906 100644 --- a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx @@ -15,19 +15,9 @@ */ import React from 'react'; import { EntityPicker } from '../EntityPicker/EntityPicker'; -import { FieldExtensionComponentProps } from '../../../extensions'; +import { OwnerPickerProps } from './schema'; -/** - * The input props that can be specified under `ui:options` for the - * `OwnerPicker` field extension. - * - * @public - */ -export interface OwnerPickerUiOptions { - allowedKinds?: string[]; - allowArbitraryValues?: boolean; - defaultNamespace?: string | false; -} +export { OwnerPickerSchema } from './schema'; /** * The underlying component that is rendered in the form for the `OwnerPicker` @@ -35,9 +25,7 @@ export interface OwnerPickerUiOptions { * * @public */ -export const OwnerPicker = ( - props: FieldExtensionComponentProps, -) => { +export const OwnerPicker = (props: OwnerPickerProps) => { const { schema: { title = 'Owner', description = 'The owner of the component' }, uiSchema, diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts index aa26024b5b..9d94650e04 100644 --- a/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { OwnerPickerUiOptions } from './OwnerPicker'; +export { OwnerPickerFieldSchema, type OwnerPickerUiOptions } from './schema'; diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/schema.ts b/plugins/scaffolder/src/components/fields/OwnerPicker/schema.ts new file mode 100644 index 0000000000..56edef1343 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/schema.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const OwnerPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + allowedKinds: z + .array(z.string()) + .default(['Group', 'User']) + .optional() + .describe( + 'List of kinds of entities to derive options from. Defaults to Group and User', + ), + allowArbitraryValues: z + .boolean() + .optional() + .describe('Whether to allow arbitrary user input. Defaults to true'), + defaultNamespace: z + .union([z.string(), z.literal(false)]) + .optional() + .describe( + 'The default namespace. Options with this namespace will not be prefixed.', + ), + }), +); + +/** + * The input props that can be specified under `ui:options` for the + * `OwnerPicker` field extension. + * + * @public + */ +export type OwnerPickerUiOptions = typeof OwnerPickerFieldSchema.uiOptionsType; + +export type OwnerPickerProps = typeof OwnerPickerFieldSchema.type; + +export const OwnerPickerSchema = OwnerPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 451df857e5..827eff6ea2 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -24,36 +24,15 @@ import { GitlabRepoPicker } from './GitlabRepoPicker'; import { AzureRepoPicker } from './AzureRepoPicker'; import { BitbucketRepoPicker } from './BitbucketRepoPicker'; import { GerritRepoPicker } from './GerritRepoPicker'; -import { FieldExtensionComponentProps } from '../../../extensions'; import { RepoUrlPickerHost } from './RepoUrlPickerHost'; import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; import { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils'; +import { RepoUrlPickerProps } from './schema'; import { RepoUrlPickerState } from './types'; import useDebounce from 'react-use/lib/useDebounce'; import { useTemplateSecrets } from '../../secrets'; -/** - * The input props that can be specified under `ui:options` for the - * `RepoUrlPicker` field extension. - * - * @public - */ -export interface RepoUrlPickerUiOptions { - allowedHosts?: string[]; - allowedOrganizations?: string[]; - allowedOwners?: string[]; - allowedRepos?: string[]; - requestUserCredentials?: { - secretsKey: string; - additionalScopes?: { - gerrit?: string[]; - github?: string[]; - gitlab?: string[]; - bitbucket?: string[]; - azure?: string[]; - }; - }; -} +export { RepoUrlPickerSchema } from './schema'; /** * The underlying component that is rendered in the form for the `RepoUrlPicker` @@ -61,9 +40,7 @@ export interface RepoUrlPickerUiOptions { * * @public */ -export const RepoUrlPicker = ( - props: FieldExtensionComponentProps, -) => { +export const RepoUrlPicker = (props: RepoUrlPickerProps) => { const { uiSchema, onChange, rawErrors, formData } = props; const [state, setState] = useState( parseRepoPickerUrl(formData), diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts index c5f596a786..33e5ef1715 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/index.ts @@ -13,5 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { RepoUrlPickerUiOptions } from './RepoUrlPicker'; +export { + RepoUrlPickerFieldSchema, + type RepoUrlPickerUiOptions, +} from './schema'; export { repoPickerValidation } from './validation'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/schema.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/schema.ts new file mode 100644 index 0000000000..8f8674a0a7 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/schema.ts @@ -0,0 +1,95 @@ +/* + * Copyright 2022 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; + +/** + * @public + */ +export const RepoUrlPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + allowedHosts: z + .array(z.string()) + .optional() + .describe('List of allowed SCM platform hosts'), + allowedOrganizations: z + .array(z.string()) + .optional() + .describe('List of allowed organizations in the given SCM platform'), + allowedOwners: z + .array(z.string()) + .optional() + .describe('List of allowed owners in the given SCM platform'), + allowedRepos: z + .array(z.string()) + .optional() + .describe('List of allowed repos in the given SCM platform'), + requestUserCredentials: z + .object({ + secretsKey: z + .string() + .describe( + 'Key used within the template secrets context to store the credential', + ), + additionalScopes: z + .object({ + gerrit: z + .array(z.string()) + .optional() + .describe('Additional Gerrit scopes to request'), + github: z + .array(z.string()) + .optional() + .describe('Additional GitHub scopes to request'), + gitlab: z + .array(z.string()) + .optional() + .describe('Additional GitLab scopes to request'), + bitbucket: z + .array(z.string()) + .optional() + .describe('Additional BitBucket scopes to request'), + azure: z + .array(z.string()) + .optional() + .describe('Additional Azure scopes to request'), + }) + .optional() + .describe('Additional permission scopes to request'), + }) + .optional() + .describe( + 'If defined will request user credentials to auth against the given SCM platform', + ), + }), +); + +/** + * The input props that can be specified under `ui:options` for the + * `RepoUrlPicker` field extension. + * + * @public + */ +export type RepoUrlPickerUiOptions = + typeof RepoUrlPickerFieldSchema.uiOptionsType; + +export type RepoUrlPickerProps = typeof RepoUrlPickerFieldSchema.type; + +// NOTE: There is a bug with this failing validation in the custom field explorer due +// to https://github.com/rjsf-team/react-jsonschema-form/issues/675 even if +// requestUserCredentials is not defined +export const RepoUrlPickerSchema = RepoUrlPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 6358934025..8d86f601ce 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -18,3 +18,4 @@ export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './OwnedEntityPicker'; export * from './EntityTagsPicker'; +export { type FieldSchema, makeFieldSchemaFromZod } from './utils'; diff --git a/plugins/scaffolder/src/components/fields/utils.ts b/plugins/scaffolder/src/components/fields/utils.ts new file mode 100644 index 0000000000..2d3e2aab1e --- /dev/null +++ b/plugins/scaffolder/src/components/fields/utils.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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 { JSONSchema7 } from 'json-schema'; +import { z } from 'zod'; +import zodToJsonSchema from 'zod-to-json-schema'; +import { + CustomFieldExtensionSchema, + FieldExtensionComponentProps, +} from '../../extensions'; + +/** + * @public + * FieldSchema encapsulates a JSONSchema7 along with the + * matching FieldExtensionComponentProps type for a field extension. + */ +export interface FieldSchema { + readonly schema: CustomFieldExtensionSchema; + readonly type: FieldExtensionComponentProps; + readonly uiOptionsType: TUiOptions; +} + +/** + * @public + * Utility function to convert zod return and UI options schemas to a + * CustomFieldExtensionSchema with FieldExtensionComponentProps type inference + */ +export function makeFieldSchemaFromZod< + TReturnSchema extends z.ZodType, + TUiOptionsSchema extends z.ZodType = z.ZodType, +>( + returnSchema: TReturnSchema, + uiOptionsSchema?: TUiOptionsSchema, +): FieldSchema< + TReturnSchema extends z.ZodType ? IReturn : never, + TUiOptionsSchema extends z.ZodType + ? IUiOptions + : never +> { + return { + schema: { + returnValue: zodToJsonSchema(returnSchema) as JSONSchema7, + uiOptions: uiOptionsSchema + ? (zodToJsonSchema(uiOptionsSchema) as JSONSchema7) + : undefined, + }, + type: null as any, + uiOptionsType: null as any, + }; +} diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 8081dcb0ca..c6ab5276d0 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -13,40 +13,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { EntityPicker } from '../components/fields/EntityPicker/EntityPicker'; -import { EntityNamePicker } from '../components/fields/EntityNamePicker/EntityNamePicker'; +import { + EntityPicker, + EntityPickerSchema, +} from '../components/fields/EntityPicker/EntityPicker'; +import { + EntityNamePicker, + EntityNamePickerSchema, +} from '../components/fields/EntityNamePicker/EntityNamePicker'; import { entityNamePickerValidation } from '../components/fields/EntityNamePicker/validation'; -import { EntityTagsPicker } from '../components/fields/EntityTagsPicker/EntityTagsPicker'; -import { OwnerPicker } from '../components/fields/OwnerPicker/OwnerPicker'; -import { RepoUrlPicker } from '../components/fields/RepoUrlPicker/RepoUrlPicker'; +import { + EntityTagsPicker, + EntityTagsPickerSchema, +} from '../components/fields/EntityTagsPicker/EntityTagsPicker'; +import { + OwnerPicker, + OwnerPickerSchema, +} from '../components/fields/OwnerPicker/OwnerPicker'; +import { + RepoUrlPicker, + RepoUrlPickerSchema, +} from '../components/fields/RepoUrlPicker/RepoUrlPicker'; import { repoPickerValidation } from '../components/fields/RepoUrlPicker/validation'; -import { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker/OwnedEntityPicker'; +import { + OwnedEntityPicker, + OwnedEntityPickerSchema, +} from '../components/fields/OwnedEntityPicker/OwnedEntityPicker'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { component: EntityPicker, name: 'EntityPicker', + schema: EntityPickerSchema, }, { component: EntityNamePicker, name: 'EntityNamePicker', validation: entityNamePickerValidation, + schema: EntityNamePickerSchema, }, { component: EntityTagsPicker, name: 'EntityTagsPicker', + schema: EntityTagsPickerSchema, }, { component: RepoUrlPicker, name: 'RepoUrlPicker', validation: repoPickerValidation, + schema: RepoUrlPickerSchema, }, { component: OwnerPicker, name: 'OwnerPicker', + schema: OwnerPickerSchema, }, { component: OwnedEntityPicker, name: 'OwnedEntityPicker', + schema: OwnedEntityPickerSchema, }, ]; diff --git a/plugins/scaffolder/src/extensions/index.tsx b/plugins/scaffolder/src/extensions/index.tsx index 08075b5b9d..a3a4fdf57b 100644 --- a/plugins/scaffolder/src/extensions/index.tsx +++ b/plugins/scaffolder/src/extensions/index.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { + CustomFieldExtensionSchema, CustomFieldValidator, FieldExtensionOptions, FieldExtensionComponentProps, @@ -72,7 +73,7 @@ export function createNextScaffolderFieldExtension< TInputProps extends UIOptionsType = {}, >( options: NextFieldExtensionOptions, -): Extension> { +): Extension> { return { expose() { const FieldExtensionDataHolder: any = () => null; @@ -103,6 +104,7 @@ attachComponentData( ); export type { + CustomFieldExtensionSchema, CustomFieldValidator, FieldExtensionOptions, FieldExtensionComponentProps, diff --git a/plugins/scaffolder/src/extensions/types.ts b/plugins/scaffolder/src/extensions/types.ts index 62f17dff15..3834b39c0a 100644 --- a/plugins/scaffolder/src/extensions/types.ts +++ b/plugins/scaffolder/src/extensions/types.ts @@ -15,14 +15,14 @@ */ import { ApiHolder } from '@backstage/core-plugin-api'; import { FieldValidation, FieldProps } from '@rjsf/core'; -import { PropsWithChildren } from 'react'; - import { UIOptionsType, FieldProps as FieldPropsV5, UiSchema as UiSchemaV5, FieldValidation as FieldValidationV5, } from '@rjsf/utils'; +import { PropsWithChildren } from 'react'; +import { JSONSchema7 } from 'json-schema'; /** * Field validation type for Custom Field Extensions. @@ -35,6 +35,16 @@ export type CustomFieldValidator = ( context: { apiHolder: ApiHolder }, ) => void | Promise; +/** + * Type for the Custom Field Extension schema. + * + * @public + */ +export type CustomFieldExtensionSchema = { + returnValue: JSONSchema7; + uiOptions?: JSONSchema7; +}; + /** * Type for the Custom Field Extension with the * name and components and validation function. @@ -50,6 +60,7 @@ export type FieldExtensionOptions< props: FieldExtensionComponentProps, ) => JSX.Element | null; validation?: CustomFieldValidator; + schema?: CustomFieldExtensionSchema; }; /** @@ -107,4 +118,5 @@ export type NextFieldExtensionOptions< props: NextFieldExtensionComponentProps, ) => JSX.Element | null; validation?: NextCustomFieldValidator; + schema?: CustomFieldExtensionSchema; }; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 7853667101..0e5e2630ac 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -43,6 +43,7 @@ export { ScaffolderFieldExtensions, } from './extensions'; export type { + CustomFieldExtensionSchema, CustomFieldValidator, FieldExtensionOptions, FieldExtensionComponentProps, diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index ebe00fdfb8..0fc1c9eceb 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -30,6 +30,7 @@ import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups'; import { nextSelectedTemplateRouteRef } from '../../routes'; import { SecretsContextProvider } from '../../components/secrets/SecretsContext'; +import type { ErrorTransformer } from '@rjsf/utils'; /** * The Props for the Scaffolder Router @@ -44,6 +45,7 @@ export type NextRouterProps = { TaskPageComponent?: React.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; + transformErrors?: ErrorTransformer; }; /** diff --git a/plugins/scaffolder/src/next/TemplateListPage/RegisterExistingButton.test.tsx b/plugins/scaffolder/src/next/TemplateListPage/RegisterExistingButton.test.tsx index e6022d16fb..a8e377bd3d 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/RegisterExistingButton.test.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/RegisterExistingButton.test.tsx @@ -34,7 +34,7 @@ describe('RegisterExistingButton', () => { , ); - expect(await queryByText('Pick me')).not.toBeInTheDocument(); + expect(queryByText('Pick me')).not.toBeInTheDocument(); }); it('should not render if permissions are not allowed', async () => { @@ -43,7 +43,7 @@ describe('RegisterExistingButton', () => { , ); - expect(await queryByText('Pick me')).not.toBeInTheDocument(); + expect(queryByText('Pick me')).not.toBeInTheDocument(); }); it('should render the button with the text', async () => { @@ -52,6 +52,6 @@ describe('RegisterExistingButton', () => { , ); - expect(await queryByText('Pick me')).toBeInTheDocument(); + expect(queryByText('Pick me')).toBeInTheDocument(); }); }); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/ReviewState.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/ReviewState.test.tsx index 2b2e706102..c03df8f73c 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/ReviewState.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/ReviewState.test.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React from 'react'; import { ReviewState } from './ReviewState'; import { render } from '@testing-library/react'; @@ -97,9 +98,7 @@ describe('ReviewState', () => { , ); - expect( - await queryByRole('row', { name: 'Name ******' }), - ).not.toBeInTheDocument(); + expect(queryByRole('row', { name: 'Name ******' })).not.toBeInTheDocument(); }); it('should allow for masking an option with a set text', () => { diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx index 12ad05ab75..bf82fecf49 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx @@ -18,6 +18,7 @@ import { TemplateParameterSchema } from '../../../types'; import { Stepper } from './Stepper'; import { renderInTestApp } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; +import type { RJSFValidationError } from '@rjsf/utils'; describe('Stepper', () => { it('should render the step titles for each step of the manifest', async () => { @@ -140,4 +141,50 @@ describe('Stepper', () => { expect(getByText('im a custom field extension')).toBeInTheDocument(); }); + + it('should transform default error message', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { + title: 'Step 1', + schema: { + properties: { + postcode: { + type: 'string', + pattern: '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]', + }, + }, + }, + }, + ], + title: 'transformErrors Form Test', + }; + + const transformErrors = (errors: RJSFValidationError[]) => { + return errors.map(err => + err.property === '.postcode' + ? { ...err, message: 'invalid postcode' } + : err, + ); + }; + + const { getByText, getByRole } = await renderInTestApp( + , + ); + + await fireEvent.change(getByRole('textbox', { name: 'postcode' }), { + target: { value: 'invalid' }, + }); + + await act(async () => { + await fireEvent.click(getByRole('button', { name: 'Review' })); + }); + + expect(getByText('invalid postcode')).toBeInTheDocument(); + }); }); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx index 511b020c3c..de06655aa1 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx @@ -13,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useApiHolder } from '@backstage/core-plugin-api'; -import { JsonObject, JsonValue } from '@backstage/types'; +import { + useAnalytics, + useApiHolder, + useRouteRefParams, +} from '@backstage/core-plugin-api'; +import { JsonValue } from '@backstage/types'; import { Stepper as MuiStepper, Step as MuiStep, @@ -31,6 +35,8 @@ import { createAsyncValidators } from './createAsyncValidators'; import { useTemplateSchema } from './useTemplateSchema'; import { ReviewState } from './ReviewState'; import validator from '@rjsf/validator-ajv8'; +import { selectedTemplateRouteRef } from '../../../routes'; +import type { ErrorTransformer } from '@rjsf/utils'; const useStyles = makeStyles(theme => ({ backButton: { @@ -51,6 +57,7 @@ export interface StepperProps { manifest: TemplateParameterSchema; extensions: NextFieldExtensionOptions[]; onComplete: (values: Record) => Promise; + transformErrors?: ErrorTransformer; } // TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly @@ -59,10 +66,12 @@ export interface StepperProps { const Form = withTheme(require('@rjsf/material-ui-v5').Theme); export const Stepper = (props: StepperProps) => { + const { templateName } = useRouteRefParams(selectedTemplateRouteRef); + const analytics = useAnalytics(); const { steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); const [activeStep, setActiveStep] = useState(0); - const [formState, setFormState] = useState({}); + const [formState, setFormState] = useState>({}); const [errors, setErrors] = useState< undefined | Record >(); @@ -90,7 +99,11 @@ export const Stepper = (props: StepperProps) => { setActiveStep(prevActiveStep => prevActiveStep - 1); }; - const handleNext = async ({ formData }: { formData: JsonObject }) => { + const handleNext = async ({ + formData, + }: { + formData: Record; + }) => { // TODO(blam): What do we do about loading states, does each field extension get a chance // to display it's own loading? Or should we grey out the entire form. setErrors(undefined); @@ -105,7 +118,11 @@ export const Stepper = (props: StepperProps) => { setErrors(returnedValidation); } else { setErrors(undefined); - setActiveStep(prevActiveStep => prevActiveStep + 1); + setActiveStep(prevActiveStep => { + const stepNum = prevActiveStep + 1; + analytics.captureEvent('click', `Next Step (${stepNum})`); + return stepNum; + }); } setFormState(current => ({ ...current, ...formData })); }; @@ -128,11 +145,13 @@ export const Stepper = (props: StepperProps) => { validator={validator} extraErrors={errors as unknown as ErrorSchema} formData={formState} + formContext={{ formData: formState }} schema={steps[activeStep].schema} uiSchema={steps[activeStep].uiSchema} onSubmit={handleNext} fields={extensions} showErrorList={false} + transformErrors={props.transformErrors} >
diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx new file mode 100644 index 0000000000..f36fae9aa3 --- /dev/null +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -0,0 +1,115 @@ +/* + * Copyright 2022 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 { ApiProvider } from '@backstage/core-app-api'; +import { analyticsApiRef } from '@backstage/core-plugin-api'; +import { + MockAnalyticsApi, + renderInTestApp, + TestApiRegistry, +} from '@backstage/test-utils'; +import { act, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { scaffolderApiRef } from '../../api'; +import { nextRouteRef, rootRouteRef } from '../../routes'; +import { ScaffolderApi } from '../../types'; +import { TemplateWizardPage } from './TemplateWizardPage'; + +jest.mock('react-router-dom', () => { + return { + ...(jest.requireActual('react-router-dom') as any), + useParams: () => ({ + templateName: 'test', + }), + }; +}); + +const scaffolderApiMock: jest.Mocked = { + scaffold: jest.fn(), + getTemplateParameterSchema: jest.fn(), + getIntegrationsList: jest.fn(), + getTask: jest.fn(), + streamLogs: jest.fn(), + listActions: jest.fn(), + listTasks: jest.fn(), +}; + +const analyticsMock = new MockAnalyticsApi(); +const apis = TestApiRegistry.from( + [scaffolderApiRef, scaffolderApiMock], + [analyticsApiRef, analyticsMock], +); + +describe('TemplateWizardPage', () => { + it('captures expected analytics events', async () => { + scaffolderApiMock.scaffold.mockResolvedValue({ taskId: 'xyz' }); + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + steps: [ + { + title: 'Step 1', + schema: { + properties: { + name: { + type: 'string', + }, + }, + }, + }, + ], + title: 'React JSON Schema Form Test', + }); + + const { findByRole, getByRole } = await renderInTestApp( + + , + , + { + mountedRoutes: { + '/create': nextRouteRef, + '/create-legacy': rootRouteRef, + }, + }, + ); + + // Fill out the name field + fireEvent.change(getByRole('textbox', { name: 'name' }), { + target: { value: 'expected-name' }, + }); + + // Go to the final page + await act(async () => { + fireEvent.click(await findByRole('button', { name: 'Review' })); + }); + + // Create the software + await act(async () => { + fireEvent.click(await findByRole('button', { name: 'Create' })); + }); + + // The "Next Step" button should have fired an event + expect(analyticsMock.getEvents()[0]).toMatchObject({ + action: 'click', + subject: 'Next Step (1)', + context: { entityRef: 'template:default/test' }, + }); + + // And the "Create" button should have fired an event + expect(analyticsMock.getEvents()[1]).toMatchObject({ + action: 'create', + subject: 'expected-name', + context: { entityRef: 'template:default/test' }, + }); + }); +}); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index b650e4a676..79ba9d33c9 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -26,6 +26,7 @@ import { NextFieldExtensionOptions } from '../../extensions'; import { Navigate, useNavigate } from 'react-router'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { + AnalyticsContext, errorApiRef, useApi, useRouteRef, @@ -43,9 +44,11 @@ import { } from '../../routes'; import { SecretsContext } from '../../components/secrets/SecretsContext'; import { JsonValue } from '@backstage/types'; +import type { ErrorTransformer } from '@rjsf/utils'; export interface TemplateWizardPageProps { customFieldExtensions: NextFieldExtensionOptions[]; + transformErrors?: ErrorTransformer; } const useStyles = makeStyles(() => ({ @@ -111,34 +114,37 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { } return ( - -
- - {loading && } - {manifest && ( - + +
+ + {loading && } + {manifest && ( + + } + noPadding + titleTypographyProps={{ component: 'h2' }} + > + - } - noPadding - titleTypographyProps={{ component: 'h2' }} - > - - - )} - - + + )} + + + ); }; diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index f9b359d93a..a34105745f 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -16,12 +16,24 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { scaffolderApiRef, ScaffolderClient } from './api'; -import { EntityPicker } from './components/fields/EntityPicker/EntityPicker'; +import { + EntityPicker, + EntityPickerSchema, +} from './components/fields/EntityPicker/EntityPicker'; import { entityNamePickerValidation } from './components/fields/EntityNamePicker'; -import { EntityNamePicker } from './components/fields/EntityNamePicker/EntityNamePicker'; -import { OwnerPicker } from './components/fields/OwnerPicker/OwnerPicker'; +import { + EntityNamePicker, + EntityNamePickerSchema, +} from './components/fields/EntityNamePicker/EntityNamePicker'; +import { + OwnerPicker, + OwnerPickerSchema, +} from './components/fields/OwnerPicker/OwnerPicker'; import { repoPickerValidation } from './components/fields/RepoUrlPicker'; -import { RepoUrlPicker } from './components/fields/RepoUrlPicker/RepoUrlPicker'; +import { + RepoUrlPicker, + RepoUrlPickerSchema, +} from './components/fields/RepoUrlPicker/RepoUrlPicker'; import { createScaffolderFieldExtension } from './extensions'; import { nextRouteRef, @@ -37,8 +49,14 @@ import { fetchApiRef, identityApiRef, } from '@backstage/core-plugin-api'; -import { OwnedEntityPicker } from './components/fields/OwnedEntityPicker/OwnedEntityPicker'; -import { EntityTagsPicker } from './components/fields/EntityTagsPicker/EntityTagsPicker'; +import { + OwnedEntityPicker, + OwnedEntityPickerSchema, +} from './components/fields/OwnedEntityPicker/OwnedEntityPicker'; +import { + EntityTagsPicker, + EntityTagsPickerSchema, +} from './components/fields/EntityTagsPicker/EntityTagsPicker'; /** * The main plugin export for the scaffolder. @@ -82,6 +100,7 @@ export const EntityPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ component: EntityPicker, name: 'EntityPicker', + schema: EntityPickerSchema, }), ); @@ -95,6 +114,7 @@ export const EntityNamePickerFieldExtension = scaffolderPlugin.provide( component: EntityNamePicker, name: 'EntityNamePicker', validation: entityNamePickerValidation, + schema: EntityNamePickerSchema, }), ); @@ -109,6 +129,7 @@ export const RepoUrlPickerFieldExtension = scaffolderPlugin.provide( component: RepoUrlPicker, name: 'RepoUrlPicker', validation: repoPickerValidation, + schema: RepoUrlPickerSchema, }), ); @@ -121,6 +142,7 @@ export const OwnerPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ component: OwnerPicker, name: 'OwnerPicker', + schema: OwnerPickerSchema, }), ); @@ -146,6 +168,7 @@ export const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ component: OwnedEntityPicker, name: 'OwnedEntityPicker', + schema: OwnedEntityPickerSchema, }), ); @@ -157,6 +180,7 @@ export const EntityTagsPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ component: EntityTagsPicker, name: 'EntityTagsPicker', + schema: EntityTagsPickerSchema, }), ); diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 30a3367bf4..f808ffb752 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index a45c3c43e5..945ecfed15 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "1.0.4-next.0", + "version": "1.0.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index dcd0bbdc78..c84b823149 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-search-backend-module-pg +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.4.2-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 5e91bfabeb..0dad5637e6 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.4.2-next.0", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index bfcd09dcad..209fa9e0c4 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-search-backend-node +## 1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index a0c4964ccf..2dc9e150a0 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "1.0.4-next.0", + "version": "1.0.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/src/indexing/BatchSearchEngineIndexer.ts b/plugins/search-backend-node/src/indexing/BatchSearchEngineIndexer.ts index 24b90c2a59..b41dd524a9 100644 --- a/plugins/search-backend-node/src/indexing/BatchSearchEngineIndexer.ts +++ b/plugins/search-backend-node/src/indexing/BatchSearchEngineIndexer.ts @@ -34,26 +34,10 @@ export type BatchSearchEngineOptions = { export abstract class BatchSearchEngineIndexer extends Writable { private batchSize: number; private currentBatch: IndexableDocument[] = []; - private initialized: Promise; constructor(options: BatchSearchEngineOptions) { super({ objectMode: true }); this.batchSize = options.batchSize; - - // @todo Once node v15 is minimum, convert to _construct implementation. - this.initialized = new Promise(done => { - // Necessary to allow concrete implementation classes to construct - // themselves before calling their initialize() methods. - setImmediate(async () => { - try { - await this.initialize(); - done(undefined); - } catch (e) { - assertError(e); - done(e); - } - }); - }); } /** @@ -73,6 +57,20 @@ export abstract class BatchSearchEngineIndexer extends Writable { */ public abstract finalize(): Promise; + /** + * Encapsulates initialization logic. + * @internal + */ + async _construct(done: (error?: Error | null | undefined) => void) { + try { + await this.initialize(); + done(); + } catch (e) { + assertError(e); + done(e); + } + } + /** * Encapsulates batch stream write logic. * @internal @@ -82,13 +80,6 @@ export abstract class BatchSearchEngineIndexer extends Writable { _e: any, done: (error?: Error | null) => void, ) { - // Wait for init before proceeding. Throw error if initialization failed. - const maybeError = await this.initialized; - if (maybeError) { - done(maybeError); - return; - } - this.currentBatch.push(doc); if (this.currentBatch.length < this.batchSize) { done(); diff --git a/plugins/search-backend-node/src/indexing/DecoratorBase.ts b/plugins/search-backend-node/src/indexing/DecoratorBase.ts index bcf5729674..9ed8dfe0a7 100644 --- a/plugins/search-backend-node/src/indexing/DecoratorBase.ts +++ b/plugins/search-backend-node/src/indexing/DecoratorBase.ts @@ -24,25 +24,8 @@ import { Transform } from 'stream'; * @public */ export abstract class DecoratorBase extends Transform { - private initialized: Promise; - constructor() { super({ objectMode: true }); - - // @todo Once node v15 is minimum, convert to _construct implementation. - this.initialized = new Promise(done => { - // Necessary to allow concrete implementation classes to construct - // themselves before calling their initialize() methods. - setImmediate(async () => { - try { - await this.initialize(); - done(undefined); - } catch (e) { - assertError(e); - done(e); - } - }); - }); } /** @@ -68,6 +51,20 @@ export abstract class DecoratorBase extends Transform { */ public abstract finalize(): Promise; + /** + * Encapsulates initialization logic. + * @internal + */ + async _construct(done: (error?: Error | null | undefined) => void) { + try { + await this.initialize(); + done(); + } catch (e) { + assertError(e); + done(e); + } + } + /** * Encapsulates simple transform stream logic. * @internal @@ -77,13 +74,6 @@ export abstract class DecoratorBase extends Transform { _: any, done: (error?: Error | null) => void, ) { - // Wait for init before proceeding. Throw error if initialization failed. - const maybeError = await this.initialized; - if (maybeError) { - done(maybeError); - return; - } - try { const decorated = await this.decorate(document); diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index c2cc89ac5b..a260266c64 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-search-backend +## 1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + - @backstage/plugin-permission-node@0.7.1 + - @backstage/plugin-search-backend-node@1.0.4 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## 1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.1.1-next.0 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index d221cf1ea5..834886e6f0 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "1.1.1-next.0", + "version": "1.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index 4ed96d5397..816230ee1f 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-common +## 1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.1 + - @backstage/types@1.0.1 + ## 1.1.1-next.0 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index a0ec2513b4..918213ec54 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-common", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", - "version": "1.1.1-next.0", + "version": "1.1.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index d5f100d97c..8cf413bbb7 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-search-react +## 1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 7097d8fa4e..71308297e2 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.2.1-next.0", + "version": "1.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 5e71299d1e..ca0385d0ba 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-search +## 1.0.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-search-react@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 7d0f6d4f52..81a969db7f 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "1.0.4-next.0", + "version": "1.0.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -66,7 +66,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 661950e6ca..31eb58a5ea 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-sentry +## 0.4.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 190e9b048b..98b688499b 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.4.4-next.0", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index e918aa8608..a7a499c87f 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-shortcuts +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/theme@0.2.16 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.3.3-next.0 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 2bd0204af7..773c6e019a 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.3.3-next.0", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "react-hook-form": "^7.12.2", "react-use": "^17.2.4", "uuid": "^8.3.2", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0", @@ -50,7 +50,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index e752ee9a2b..a76482ae32 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-sonarqube-backend +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 59f02b2950..e18ac34969 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.1.3-next.0", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,7 +36,7 @@ "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/supertest": "^2.0.12", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index dd5aa80817..4c92de36ea 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-sonarqube +## 0.5.0 + +### Minor Changes + +- 786117e98a: Fix sonarqube annotation parsing. Add content page for Sonarqube. + Removed the deprecated `plugin` export; please use `sonarQubePlugin` instead. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.3-next.0 ### Patch Changes diff --git a/plugins/sonarqube/api-report.md b/plugins/sonarqube/api-report.md index e0a51479a4..2edf80618e 100644 --- a/plugins/sonarqube/api-report.md +++ b/plugins/sonarqube/api-report.md @@ -21,9 +21,17 @@ export const EntitySonarQubeCard: (props: { duplicationRatings?: DuplicationRating[] | undefined; }) => JSX.Element; +// @public (undocumented) +export const EntitySonarQubeContentPage: ( + props: SonarQubeContentPageProps, +) => JSX.Element; + // @public (undocumented) export const isSonarQubeAvailable: (entity: Entity) => boolean; +// @public (undocumented) +export const SONARQUBE_PROJECT_KEY_ANNOTATION = 'sonarqube.org/project-key'; + // @public (undocumented) export const SonarQubeCard: (props: { variant?: InfoCardVariants; @@ -31,7 +39,11 @@ export const SonarQubeCard: (props: { }) => JSX.Element; // @public (undocumented) -const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; -export { sonarQubePlugin as plugin }; -export { sonarQubePlugin }; +export type SonarQubeContentPageProps = { + title?: string; + supportTitle?: string; +}; + +// @public (undocumented) +export const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; ``` diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index b46cb5c0b1..d8f54b80f5 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.4.3-next.0", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx new file mode 100644 index 0000000000..8e847d7c31 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { lightTheme } from '@backstage/theme'; +import { ThemeProvider } from '@material-ui/core'; +import React from 'react'; +import { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from '../useProjectKey'; +import { SonarQubeApi, sonarQubeApiRef } from '../../api'; + +const Providers = ({ + annotation, + children, +}: { annotation: string } & React.PropsWithChildren): JSX.Element => ( + + + {children} + + +); + +describe('', () => { + beforeAll(() => { + jest.mock('@backstage/plugin-sonarqube', () => ({ + __esModule: true, + isSonarQubeAvailable, + EntitySonarQubeCard: () => { + return
; + }, + })); + }); + + it('renders EntitySonarQubeCard', async () => { + const { SonarQubeContentPage } = require('./SonarQubeContentPage'); + + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('SonarQube Dashboard')).toBeInTheDocument(); + expect(rendered.getByText('No information to display')).toBeInTheDocument(); + expect( + rendered.getByText("There is no SonarQube project with key 'bar'."), + ).toBeInTheDocument(); + }, 15000); + + it('renders MissingAnnotationEmptyState if sonar annotation is missing', async () => { + const { SonarQubeContentPage } = require('./SonarQubeContentPage'); + + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('Missing Annotation')).toBeInTheDocument(); + expect( + rendered.getAllByText(SONARQUBE_PROJECT_KEY_ANNOTATION, { exact: false }) + .length, + ).toBe(2); + }, 15000); +}); diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx new file mode 100644 index 0000000000..33a145b746 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Content, + ContentHeader, + SupportButton, +} from '@backstage/core-components'; +import { MissingAnnotationEmptyState } from '@backstage/core-components'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from '../useProjectKey'; +import { SonarQubeCard } from '../SonarQubeCard'; + +/** @public */ +export type SonarQubeContentPageProps = { + title?: string; + supportTitle?: string; +}; + +export const SonarQubeContentPage = (props: SonarQubeContentPageProps) => { + const { entity } = useEntity(); + const { title, supportTitle } = props; + + return isSonarQubeAvailable(entity) ? ( + + + {supportTitle && {supportTitle}} + + + + ) : ( + + ); +}; diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts b/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts new file mode 100644 index 0000000000..59327e9a88 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { SonarQubeContentPage } from './SonarQubeContentPage'; +export type { SonarQubeContentPageProps } from './SonarQubeContentPage'; diff --git a/plugins/sonarqube/src/components/index.ts b/plugins/sonarqube/src/components/index.ts index 7e58100efa..8e1d93f85b 100644 --- a/plugins/sonarqube/src/components/index.ts +++ b/plugins/sonarqube/src/components/index.ts @@ -14,5 +14,10 @@ * limitations under the License. */ -export * from './SonarQubeCard'; -export { isSonarQubeAvailable } from './useProjectKey'; +export { SonarQubeCard } from './SonarQubeCard'; +export type { DuplicationRating } from './SonarQubeCard'; +export type { SonarQubeContentPageProps } from './SonarQubeContentPage'; +export { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from './useProjectKey'; diff --git a/plugins/sonarqube/src/components/useProjectKey.test.ts b/plugins/sonarqube/src/components/useProjectKey.test.ts index 921e9455c0..8686ac82de 100644 --- a/plugins/sonarqube/src/components/useProjectKey.test.ts +++ b/plugins/sonarqube/src/components/useProjectKey.test.ts @@ -39,10 +39,12 @@ describe('isSonarQubeAvailable', () => { const entity = createDummyEntity('dummy'); expect(isSonarQubeAvailable(entity)).toBe(true); }); + it('returns false if sonarqube annotation empty', () => { const entity = createDummyEntity(''); expect(isSonarQubeAvailable(entity)).toBe(false); }); + it('returns false if sonarqube annotation not defined', () => { const entity = { apiVersion: '', @@ -59,6 +61,7 @@ describe('isSonarQubeAvailable', () => { describe('useProjectInfo', () => { const DUMMY_INSTANCE = 'dummyInstance'; const DUMMY_KEY = 'dummyKey'; + it('parse annotation with key and instance', () => { const entity = createDummyEntity( DUMMY_INSTANCE + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + DUMMY_KEY, @@ -68,6 +71,33 @@ describe('useProjectInfo', () => { projectKey: DUMMY_KEY, }); }); + + it('parse annotation with instance, tenant/project-key', () => { + const DUMMY_KEY_WITH_TENANT = 'dummy-tenant/dummyKey'; + const entity = createDummyEntity( + DUMMY_INSTANCE + + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + + DUMMY_KEY_WITH_TENANT, + ); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: DUMMY_INSTANCE, + projectKey: DUMMY_KEY_WITH_TENANT, + }); + }); + + it('parse annotation with instance, tenant:project-key', () => { + const DUMMY_KEY_WITH_TENANT = 'dummy-tenant:dummyKey'; + const entity = createDummyEntity( + DUMMY_INSTANCE + + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + + DUMMY_KEY_WITH_TENANT, + ); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: DUMMY_INSTANCE, + projectKey: DUMMY_KEY_WITH_TENANT, + }); + }); + // compatibility with previous mono-instance sonarqube config it('parse annotation with only key', () => { const entity = createDummyEntity(DUMMY_KEY); @@ -76,6 +106,7 @@ describe('useProjectInfo', () => { projectKey: DUMMY_KEY, }); }); + it('handle empty annotation', () => { const entity = createDummyEntity(''); expect(useProjectInfo(entity)).toEqual({ @@ -83,6 +114,7 @@ describe('useProjectInfo', () => { projectKey: undefined, }); }); + it('handle non-existent annotation', () => { const entity = { apiVersion: '', diff --git a/plugins/sonarqube/src/components/useProjectKey.ts b/plugins/sonarqube/src/components/useProjectKey.ts index 59a572a6c4..20f7f03bb3 100644 --- a/plugins/sonarqube/src/components/useProjectKey.ts +++ b/plugins/sonarqube/src/components/useProjectKey.ts @@ -16,6 +16,7 @@ import { Entity } from '@backstage/catalog-model'; +/** @public */ export const SONARQUBE_PROJECT_KEY_ANNOTATION = 'sonarqube.org/project-key'; export const SONARQUBE_PROJECT_INSTANCE_SEPARATOR = '/'; @@ -42,11 +43,16 @@ export const useProjectInfo = ( const annotation = entity?.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION]; if (annotation) { - if (annotation.indexOf(SONARQUBE_PROJECT_INSTANCE_SEPARATOR) > -1) { - [projectInstance, projectKey] = annotation.split( - SONARQUBE_PROJECT_INSTANCE_SEPARATOR, - 2, - ); + const instanceSeparatorIndex = annotation.indexOf( + SONARQUBE_PROJECT_INSTANCE_SEPARATOR, + ); + if (instanceSeparatorIndex > -1) { + // Examples: + // instanceA/projectA -> projectInstance = "instanceA" & projectKey = "projectA" + // instanceA/tenantA:projectA -> projectInstance = "instanceA" & projectKey = "tenantA:projectA" + // instanceA/tenantA/projectA -> projectInstance = "instanceA" & projectKey = "tenantA/projectA" + projectInstance = annotation.substring(0, instanceSeparatorIndex); + projectKey = annotation.substring(instanceSeparatorIndex + 1); } else { projectKey = annotation; } diff --git a/plugins/sonarqube/src/index.ts b/plugins/sonarqube/src/index.ts index 1e6f83aa49..30f6351d4d 100644 --- a/plugins/sonarqube/src/index.ts +++ b/plugins/sonarqube/src/index.ts @@ -22,8 +22,4 @@ */ export * from './components'; -export { - sonarQubePlugin, - sonarQubePlugin as plugin, - EntitySonarQubeCard, -} from './plugin'; +export * from './plugin'; diff --git a/plugins/sonarqube/src/plugin.ts b/plugins/sonarqube/src/plugin.ts index 0ea62de492..5eb5ea82f3 100644 --- a/plugins/sonarqube/src/plugin.ts +++ b/plugins/sonarqube/src/plugin.ts @@ -52,3 +52,16 @@ export const EntitySonarQubeCard = sonarQubePlugin.provide( }, }), ); + +/** @public */ +export const EntitySonarQubeContentPage = sonarQubePlugin.provide( + createComponentExtension({ + name: 'EntitySonarQubeContentPage', + component: { + lazy: () => + import('./components/SonarQubeContentPage').then( + m => m.SonarQubeContentPage, + ), + }, + }), +); diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 02a736b782..35bf66f661 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-splunk-on-call +## 0.4.0 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/theme@0.2.16 + +## 0.4.0-next.1 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.35-next.0 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 0434c7b07b..53aefc5ee0 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.3.35-next.0", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "configSchema": "config.d.ts", "files": [ diff --git a/plugins/splunk-on-call/src/api/client.ts b/plugins/splunk-on-call/src/api/client.ts index aa655a4772..2c5e122ac8 100644 --- a/plugins/splunk-on-call/src/api/client.ts +++ b/plugins/splunk-on-call/src/api/client.ts @@ -64,7 +64,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { 'proxy', )}/splunk-on-call/v1/incidents`; - const { incidents } = await this.getByUrl(url); + const { incidents } = await this.findByUrl(url); return incidents; } @@ -73,7 +73,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/splunk-on-call/v1/oncall/current`; - const { teamsOnCall } = await this.getByUrl(url); + const { teamsOnCall } = await this.findByUrl(url); return teamsOnCall; } @@ -82,7 +82,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/splunk-on-call/v1/team`; - const teams = await this.getByUrl(url); + const teams = await this.findByUrl(url); return teams; } @@ -91,7 +91,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/splunk-on-call/v1/org/routing-keys`; - const { routingKeys } = await this.getByUrl(url); + const { routingKeys } = await this.findByUrl(url); return routingKeys; } @@ -100,7 +100,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/splunk-on-call/v2/user`; - const { users } = await this.getByUrl(url); + const { users } = await this.findByUrl(url); return users; } @@ -109,7 +109,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { const url = `${await this.config.discoveryApi.getBaseUrl( 'proxy', )}/splunk-on-call/v1/policies`; - const { policies } = await this.getByUrl(url); + const { policies } = await this.findByUrl(url); return policies; } @@ -146,7 +146,7 @@ export class SplunkOnCallClient implements SplunkOnCallApi { return this.request(url, options); } - private async getByUrl(url: string): Promise { + private async findByUrl(url: string): Promise { const options = { method: 'GET', headers: { diff --git a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx index 0688fb8237..704d2d9ed9 100644 --- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx +++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx @@ -13,11 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { act, fireEvent, render, waitFor } from '@testing-library/react'; + import { Entity } from '@backstage/catalog-model'; +import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; +import { + alertApiRef, + ConfigApi, + configApiRef, +} from '@backstage/core-plugin-api'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; +import { act, fireEvent, render, waitFor } from '@testing-library/react'; +import React from 'react'; import { splunkOnCallApiRef, SplunkOnCallClient, @@ -33,13 +40,7 @@ import { MOCK_TEAM_NO_INCIDENTS, } from '../api/mocks'; import { EntitySplunkOnCallCard } from './EntitySplunkOnCallCard'; - -import { - alertApiRef, - ConfigApi, - configApiRef, -} from '@backstage/core-plugin-api'; -import { ApiProvider, ConfigReader } from '@backstage/core-app-api'; +import { expectTriggeredIncident } from './TriggerDialog/testUtils'; const mockSplunkOnCallApi: Partial = { getUsers: async () => [], @@ -167,8 +168,10 @@ describe('SplunkOnCallCard', () => { mockSplunkOnCallApi.getTeams = jest .fn() .mockImplementation(async () => [MOCK_TEAM]); + const mockTriggerAlarmFn = jest.fn(); + mockSplunkOnCallApi.incidentAction = mockTriggerAlarmFn; - const { getByText, queryByTestId } = render( + const { getByRole, getByTestId, getByText, queryByTestId } = render( wrapInTestApp( @@ -179,10 +182,23 @@ describe('SplunkOnCallCard', () => { ); await waitFor(() => !queryByTestId('progress')); expect(getByText(`Team: ${MOCK_TEAM.name}`)).toBeInTheDocument(); + expect(getByText('Create Incident')).toBeInTheDocument(); await waitFor( () => expect(getByText('test-incident')).toBeInTheDocument(), { timeout: 2000 }, ); + + const createIncidentButton = getByText('Create Incident'); + await act(async () => { + fireEvent.click(createIncidentButton); + }); + expect(getByRole('dialog')).toBeInTheDocument(); + + await expectTriggeredIncident( + 'test-routing-key', + getByTestId, + mockTriggerAlarmFn, + ); }); it('Handles custom error for missing token', async () => { diff --git a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx index d635f7328f..26521ea9ee 100644 --- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx +++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx @@ -29,11 +29,11 @@ import AlarmAddIcon from '@material-ui/icons/AlarmAdd'; import WebIcon from '@material-ui/icons/Web'; import { Alert } from '@material-ui/lab'; import { splunkOnCallApiRef, UnauthorizedError } from '../api'; -import { MissingApiKeyOrApiIdError } from './Errors/MissingApiKeyOrApiIdError'; +import { MissingApiKeyOrApiIdError } from './Errors'; import { EscalationPolicy } from './Escalation'; import { Incidents } from './Incident'; import { TriggerDialog } from './TriggerDialog'; -import { Team, User } from './types'; +import { RoutingKey, Team, User } from './types'; import { configApiRef, useApi } from '@backstage/core-plugin-api'; import { @@ -143,7 +143,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { }, []); const { - value: usersAndTeams, + value: entityData, loading, error, } = useAsync(async () => { @@ -162,11 +162,15 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { teams.find(teamValue => teamValue.name === teamAnnotation), ].filter(team => team !== undefined); - if (!foundTeams.length && routingKeyAnnotation) { + let foundRoutingKey: RoutingKey | undefined; + if (routingKeyAnnotation) { const routingKeys = await api.getRoutingKeys(); - const foundRoutingKey = routingKeys.find( + foundRoutingKey = routingKeys.find( key => key.routingKey === routingKeyAnnotation, ); + } + + if (!foundTeams.length) { foundTeams = foundRoutingKey ? foundRoutingKey.targets .map(target => { @@ -179,7 +183,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { : []; } - return { usersHashMap, foundTeams }; + return { usersHashMap, foundTeams, foundRoutingKey }; }); if (!teamAnnotation && !routingKeyAnnotation) { @@ -206,7 +210,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { return ; } - if (!usersAndTeams?.foundTeams || !usersAndTeams?.foundTeams.length) { + if (!entityData?.foundTeams || !entityData?.foundTeams.length) { return ( { const Content = ({ team, + routingKey, usersHashMap, }: { team: Team | undefined; + routingKey: RoutingKey | undefined; usersHashMap: any; }) => { const teamName = team?.name ?? ''; @@ -235,7 +241,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { )} { icon: , }; - const teams = usersAndTeams?.foundTeams || []; + const teams = entityData?.foundTeams || []; return ( <> @@ -277,7 +283,11 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => { /> - + ))} diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx index 0b64a137af..3bfbddb0e4 100644 --- a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx +++ b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { render, fireEvent, act } from '@testing-library/react'; -import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; -import { splunkOnCallApiRef } from '../../api'; -import { TriggerDialog } from './TriggerDialog'; - import { ApiProvider } from '@backstage/core-app-api'; import { alertApiRef } from '@backstage/core-plugin-api'; +import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { splunkOnCallApiRef } from '../../api'; +import { TriggerDialog } from './TriggerDialog'; +import { expectTriggeredIncident } from './testUtils'; describe('TriggerDialog', () => { const mockTriggerAlarmFn = jest.fn(); @@ -38,7 +38,7 @@ describe('TriggerDialog', () => { wrapInTestApp( {}} onIncidentCreated={() => {}} @@ -53,34 +53,6 @@ describe('TriggerDialog', () => { exact: false, }), ).toBeInTheDocument(); - const incidentType = getByTestId('trigger-incident-type'); - const incidentId = getByTestId('trigger-incident-id'); - const incidentDisplayName = getByTestId('trigger-incident-displayName'); - const incidentMessage = getByTestId('trigger-incident-message'); - - await act(async () => { - fireEvent.change(incidentType, { target: { value: 'CRITICAL' } }); - fireEvent.change(incidentId, { target: { value: 'incident-id' } }); - fireEvent.change(incidentDisplayName, { - target: { value: 'incident-display-name' }, - }); - fireEvent.change(incidentMessage, { - target: { value: 'incident-message' }, - }); - }); - - // Trigger incident creation button - const triggerButton = getByTestId('trigger-button'); - await act(async () => { - fireEvent.click(triggerButton); - }); - expect(mockTriggerAlarmFn).toHaveBeenCalled(); - expect(mockTriggerAlarmFn).toHaveBeenCalledWith({ - incidentType: 'CRITICAL', - incidentId: 'incident-id', - routingKey: 'Example', - incidentDisplayName: 'incident-display-name', - incidentMessage: 'incident-message', - }); + await expectTriggeredIncident('Example', getByTestId, mockTriggerAlarmFn); }); }); diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx index 82dd2da74d..dd8f0b1909 100644 --- a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx +++ b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx @@ -35,11 +35,11 @@ import { import useAsyncFn from 'react-use/lib/useAsyncFn'; import { splunkOnCallApiRef } from '../../api'; import { Alert } from '@material-ui/lab'; -import { TriggerAlarmRequest } from '../../api/types'; +import { TriggerAlarmRequest } from '../../api'; import { useApi, alertApiRef } from '@backstage/core-plugin-api'; type Props = { - team: string; + routingKey: string; showDialog: boolean; handleDialog: () => void; onIncidentCreated: () => void; @@ -76,7 +76,7 @@ const useStyles = makeStyles((theme: Theme) => ); export const TriggerDialog = ({ - team, + routingKey, showDialog, handleDialog, onIncidentCreated: onIncidentCreated, @@ -221,7 +221,7 @@ export const TriggerDialog = ({ id="details" multiline fullWidth - rows="2" + minRows="2" margin="normal" label="Incident message" variant="outlined" @@ -242,7 +242,7 @@ export const TriggerDialog = ({ variant="contained" onClick={() => handleTriggerAlarm({ - routingKey: team, + routingKey, incidentType, incidentDisplayName, incidentMessage, diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts b/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts new file mode 100644 index 0000000000..764ac94e2c --- /dev/null +++ b/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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. + */ +// eslint-disable-next-line import/no-extraneous-dependencies +import { + act, + fireEvent, + Matcher, + MatcherOptions, +} from '@testing-library/react'; + +export async function expectTriggeredIncident( + routingKey: string, + getByTestId: ( + id: Matcher, + options?: MatcherOptions | undefined, + ) => HTMLElement, + mockTriggerAlarmFn: any, +): Promise { + const incidentType = getByTestId('trigger-incident-type'); + const incidentId = getByTestId('trigger-incident-id'); + const incidentDisplayName = getByTestId('trigger-incident-displayName'); + const incidentMessage = getByTestId('trigger-incident-message'); + + await act(async () => { + fireEvent.change(incidentType, { target: { value: 'CRITICAL' } }); + fireEvent.change(incidentId, { target: { value: 'incident-id' } }); + fireEvent.change(incidentDisplayName, { + target: { value: 'incident-display-name' }, + }); + fireEvent.change(incidentMessage, { + target: { value: 'incident-message' }, + }); + }); + + // Trigger incident creation button + const triggerButton = getByTestId('trigger-button'); + await act(async () => { + fireEvent.click(triggerButton); + }); + + expect(mockTriggerAlarmFn).toHaveBeenCalled(); + expect(mockTriggerAlarmFn).toHaveBeenCalledWith({ + incidentType: 'CRITICAL', + incidentId: 'incident-id', + routingKey: routingKey, + incidentDisplayName: 'incident-display-name', + incidentMessage: 'incident-message', + }); +} diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index 50b989079a..4f4ba31caf 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-stack-overflow-backend +## 0.1.7 + +### Patch Changes + +- cbe11d1e23: Tweak README +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/cli@0.21.0 + - @backstage/config@1.0.4 + - @backstage/plugin-search-common@1.1.1 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 4714c29551..a31d1c1d14 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow-backend", - "version": "0.1.7-next.0", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index a725475f69..3e97f1b293 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-stack-overflow +## 0.1.7 + +### Patch Changes + +- e32d5643e3: `StackOverflowSearchResultListItem` now accept optional rank property to be able to capture rank analytics data. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-home@0.4.27 + - @backstage/config@1.0.4 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/stack-overflow/api-report.md b/plugins/stack-overflow/api-report.md index 81cfe1395b..9af9231094 100644 --- a/plugins/stack-overflow/api-report.md +++ b/plugins/stack-overflow/api-report.md @@ -44,5 +44,6 @@ export type StackOverflowQuestionsRequestParams = { export const StackOverflowSearchResultListItem: (props: { result: any; icon?: ReactNode; + rank?: number | undefined; }) => JSX.Element; ``` diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 2b0910bbae..96df3e4856 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow", - "version": "0.1.7-next.0", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx index 61e901591e..9e27149efb 100644 --- a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx @@ -15,9 +15,15 @@ */ import React from 'react'; -import { renderInTestApp } from '@backstage/test-utils'; +import { + MockAnalyticsApi, + renderInTestApp, + TestApiProvider, +} from '@backstage/test-utils'; +import userEvent from '@testing-library/user-event'; import { screen } from '@testing-library/react'; import { StackOverflowSearchResultListItem } from './StackOverflowSearchResultListItem'; +import { analyticsApiRef } from '@backstage/core-plugin-api'; describe('', () => { it('should render without exploding', async () => { @@ -40,4 +46,36 @@ describe('', () => { screen.getByText(/Customizing Spotify backstage UI/i).closest('a'), ).toHaveAttribute('href', 'https://stackoverflow.com/questions/7'); }); + + it('should capture analytics for rank', async () => { + const analyticsSpy = new MockAnalyticsApi(); + + await renderInTestApp( + + + , + , + ); + + await userEvent.click( + screen.getByText(/Customizing Spotify backstage UI/i), + ); + + expect(analyticsSpy.getEvents()[0]).toMatchObject({ + action: 'discover', + attributes: { to: 'https://stackoverflow.com/questions/7' }, + context: { extension: 'App', pluginId: 'root', routeRef: 'unknown' }, + subject: 'Customizing Spotify backstage UI', + value: 1, + }); + }); }); diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx index c793939593..581fe34dfb 100644 --- a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx @@ -25,19 +25,29 @@ import { Box, Chip, } from '@material-ui/core'; +import { useAnalytics } from '@backstage/core-plugin-api'; type StackOverflowSearchResultListItemProps = { result: any; // TODO(emmaindal): type to StackOverflowDocument. icon?: React.ReactNode; + rank?: number; }; export const StackOverflowSearchResultListItem = ( props: StackOverflowSearchResultListItemProps, ) => { const { location, title, text, answers, tags } = props.result; + const analytics = useAnalytics(); + + const handleClick = () => { + analytics.captureEvent('discover', title, { + attributes: { to: location }, + value: props.rank, + }); + }; return ( - + {props.icon && {props.icon}} diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 84a682dc8e..94001990b9 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-tech-insights-common@0.2.8 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 9a811bc65a..0b344a4d04 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.22-next.0", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index b39c640ddb..262cdfc764 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-tech-insights-backend +## 0.5.4 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- 06cf8f1cf2: Add a default delay to the fact retrievers to prevent cold-start errors +- 30e43717c7: Use `HumanDuration` from `@backstage/types` +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/plugin-tech-insights-node@0.3.6 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-tech-insights-common@0.2.8 + +## 0.5.4-next.1 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.5.4-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend/README.md b/plugins/tech-insights-backend/README.md index 26dac78db5..95fa3ccda9 100644 --- a/plugins/tech-insights-backend/README.md +++ b/plugins/tech-insights-backend/README.md @@ -213,6 +213,8 @@ and modify the `techInsights.ts` file to contain a reference to the FactChecker }); ``` +NOTE: You need a Fact Checker Factory to get access to the backend routes that will allow the facts to be checked. If you don't have a Fact Checker Factory you will see 404s and potentially other errors. + To be able to run checks, you need to additionally add individual checks into your FactChecker implementation. For examples how to add these, you can check the documentation of the individual implementation of the FactChecker #### Modifying check persistence diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 6d42c1aecc..6b3c50a6f1 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend", - "version": "0.5.4-next.0", + "version": "0.5.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-common/CHANGELOG.md b/plugins/tech-insights-common/CHANGELOG.md index 80db666774..3ea396442e 100644 --- a/plugins/tech-insights-common/CHANGELOG.md +++ b/plugins/tech-insights-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-tech-insights-common +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.0.1 + ## 0.2.8-next.0 ### Patch Changes diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json index 016ccc9a2a..910fe5608c 100644 --- a/plugins/tech-insights-common/package.json +++ b/plugins/tech-insights-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-common", - "version": "0.2.8-next.0", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index 8173dbc132..82d2c59f0f 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-tech-insights-node +## 0.3.6 + +### Patch Changes + +- 06cf8f1cf2: Add a default delay to the fact retrievers to prevent cold-start errors +- 30e43717c7: Use `HumanDuration` from `@backstage/types` +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/types@1.0.1 + - @backstage/config@1.0.4 + - @backstage/plugin-tech-insights-common@0.2.8 + +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.3.6-next.0 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 7300089744..b6f41aaa2e 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.3.6-next.0", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index f60027e045..0066de5b0f 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-tech-insights +## 0.3.3 + +### Patch Changes + +- 7095e8bc03: Fixed bug when sending data by Post in `runChecks` and `runBulkChecks` functions of the `TechInsightsClient` class, the default `Content-Type` used was `plain/text` +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-tech-insights-common@0.2.8 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index cb9def285e..387f88b9c3 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.3.2-next.0", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index df5bee360a..17025f1c85 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-tech-radar +## 0.5.18 + +### Patch Changes + +- 1f888af5f6: Fixed bug in Tech Radar where, on hover, the tech list quadrant would rerender and scroll top +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/theme@0.2.16 + +## 0.5.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.5.18-next.0 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index a4dd1f0848..67a863e606 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.5.18-next.0", + "version": "0.5.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index ba3141919a..dda684478d 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.6 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0 + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/plugin-catalog@1.6.1 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/test-utils@1.2.2 + - @backstage/theme@0.2.16 + +## 1.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.0.6-next.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index a7b6abd782..694c69ec58 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.6-next.1", + "version": "1.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -63,7 +63,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index b038fa202f..8965b8be7f 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-techdocs-backend +## 1.4.1 + +### Patch Changes + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. +- a6d779d58a: Remove explicit default visibility at `config.d.ts` files. + + ```ts + /** + * @visibility backend + */ + ``` + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/plugin-techdocs-node@1.4.2 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-permission-common@0.7.1 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-catalog-common@1.0.8 + - @backstage/plugin-search-common@1.1.1 + +## 1.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.4.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 5e74c47d3c..d6c71c4ba1 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "1.4.1-next.0", + "version": "1.4.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@types/dockerode": "^3.3.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index c56e9cbf12..34d8ebacf1 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.0.6 + +### Patch Changes + +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/integration-react@1.1.6 + - @backstage/theme@0.2.16 + +## 1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 782273e8c0..91362aa4b0 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.0.6-next.0", + "version": "1.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index cc8770c34b..1fad63a9a1 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-techdocs-node +## 1.4.2 + +### Patch Changes + +- a7607b5413: Replace usage of deprecataed `UrlReader.read` with `UrlReader.readUrl`. +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/plugin-search-common@1.1.1 + +## 1.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.4.2-next.0 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index eef2da8ccb..7da0d65167 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-node", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "1.4.2-next.0", + "version": "1.4.2", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 9418517a6c..262c7f5284 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-techdocs-react +## 1.0.6 + +### Patch Changes + +- 7d1352d459: Analytics events captured within the `` now include the conventional `entityRef` context value, associating those events with their corresponding entity. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/version-bridge@1.0.2 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/config@1.0.4 + +## 1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/version-bridge@1.0.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/api-report.md b/plugins/techdocs-react/api-report.md index d04b852d07..09da4e012c 100644 --- a/plugins/techdocs-react/api-report.md +++ b/plugins/techdocs-react/api-report.md @@ -173,7 +173,7 @@ export const useShadowRootElements: < ) => TReturnedElement[]; // @public -export const useShadowRootSelection: (wait?: number) => Selection | null; +export const useShadowRootSelection: (waitMillis?: number) => Selection | null; // @public export const useTechDocsAddons: () => { diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index d7ff40bed8..3adc83c969 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.0.6-next.0", + "version": "1.0.6", "publishConfig": { "access": "public", "alphaTypes": "dist/index.alpha.d.ts", diff --git a/plugins/techdocs-react/src/context.test.tsx b/plugins/techdocs-react/src/context.test.tsx index 6cc5537d9e..4800204f36 100644 --- a/plugins/techdocs-react/src/context.test.tsx +++ b/plugins/techdocs-react/src/context.test.tsx @@ -19,9 +19,13 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; -import { TestApiProvider } from '@backstage/test-utils'; +import { MockAnalyticsApi, TestApiProvider } from '@backstage/test-utils'; import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; -import { configApiRef } from '@backstage/core-plugin-api'; +import { + analyticsApiRef, + configApiRef, + useAnalytics, +} from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { useTechDocsReaderPage, TechDocsReaderPageProvider } from './context'; @@ -60,6 +64,8 @@ const configApiMock = { getOptionalBoolean: jest.fn().mockReturnValue(undefined), }; +const analyticsApiMock = new MockAnalyticsApi(); + const wrapper = ({ entityRef = { kind: mockEntityMetadata.kind, @@ -74,6 +80,7 @@ const wrapper = ({ { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should set title', async () => { const { result, waitForNextUpdate } = renderHook( () => useTechDocsReaderPage(), @@ -157,4 +168,21 @@ describe('useTechDocsReaderPage', () => { expect(result.current.entityRef).toStrictEqual(caseSensitiveEntityRef); }); + + it('entityRef provided as analytics context', async () => { + const { waitForNextUpdate } = renderHook( + () => useAnalytics().captureEvent('action', 'subject'), + { wrapper }, + ); + + await waitForNextUpdate(); + + expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + action: 'action', + subject: 'subject', + context: { + entityRef: 'component:default/test', + }, + }); + }); }); diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 66faf858fa..2a5b151824 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -33,7 +33,11 @@ import { createVersionedValueMap, } from '@backstage/version-bridge'; -import { configApiRef, useApi } from '@backstage/core-plugin-api'; +import { + AnalyticsContext, + configApiRef, + useApi, +} from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { TechDocsEntityMetadata, TechDocsMetadata } from './types'; @@ -141,9 +145,13 @@ export const TechDocsReaderPageProvider = memo( const versionedValue = createVersionedValueMap({ 1: value }); return ( - - {children instanceof Function ? children(value) : children} - + + + {children instanceof Function ? children(value) : children} + + ); }, (prevProps, nextProps) => { diff --git a/plugins/techdocs-react/src/hooks.ts b/plugins/techdocs-react/src/hooks.ts index 560c548156..e8cc7bddc8 100644 --- a/plugins/techdocs-react/src/hooks.ts +++ b/plugins/techdocs-react/src/hooks.ts @@ -57,10 +57,10 @@ const isValidSelection = (newSelection: Selection) => { }; /** - * Hook for retreiving a selection within the ShadowRoot. + * Hook for retrieving a selection within the ShadowRoot. * @public */ -export const useShadowRootSelection = (wait: number = 0) => { +export const useShadowRootSelection = (waitMillis: number = 0) => { const shadowRoot = useShadowRoot(); const [selection, setSelection] = useState(null); const handleSelectionChange = useMemo( @@ -78,8 +78,8 @@ export const useShadowRootSelection = (wait: number = 0) => { } else { setSelection(null); } - }, wait), - [shadowRoot, setSelection, wait], + }, waitMillis), + [shadowRoot, setSelection, waitMillis], ); useEffect(() => { diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index d146a4d576..8bbf00e84d 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,76 @@ # @backstage/plugin-techdocs +## 1.4.0 + +### Minor Changes + +- 5691baea69: Add ability to configure filters when using EntityListDocsGrid + + The following example will render two sections of cards grid: + + - One section for documentations tagged as `recommended` + - One section for documentations tagged as `runbook` + + ```js + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + { + title: "RunBooks Documentation", + filterPredicate: entity => + entity?.metadata?.tags?.includes('runbook') ?? false, + } + ]}} /> + ``` + +- 63705e73d9: Hide document description if not provided +- 847fc588a6: Updated TechDocs header to include label for source code icon and updated label to reflect Kind name + +### Patch Changes + +- 9e4d8e6198: Fix logic bug that broke techdocs-cli-embedded-app +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- cbe11d1e23: Tweak README +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- c1784a4980: Replaces in-code uses of `GitHub` with `Github` and deprecates old versions. +- 3a1a999b7b: Include query parameters when navigating to relative links in documents +- bd2aab4726: An analytics event matching the semantics of the `click` action is now captured when users click links within a TechDocs document. +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-techdocs-react@1.0.6 + - @backstage/integration-react@1.1.6 + - @backstage/plugin-search-react@1.2.1 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + - @backstage/plugin-search-common@1.1.1 + +## 1.4.0-next.2 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.4.0-next.1 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index cb03cb9e3f..5762a3d8af 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.4.0-next.1", + "version": "1.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -76,9 +76,9 @@ "@types/dompurify": "^2.2.2", "@types/event-source-polyfill": "^1.0.0", "@types/node": "^16.11.26", - "canvas": "^2.6.1", + "canvas": "^2.10.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx b/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx index effd8fe0c5..2837ab340a 100644 --- a/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx +++ b/plugins/techdocs/src/home/components/Grids/EntityListDocsGrid.test.tsx @@ -103,10 +103,10 @@ describe('Entity List Docs Grid', () => { }, ); - expect(await screen.queryByText('All Documentation')).toBeInTheDocument(); - expect(await screen.queryByText('Documentation #1')).toBeInTheDocument(); - expect(await screen.queryByText('Documentation #2')).toBeInTheDocument(); - expect(await screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); + expect(screen.queryByText('All Documentation')).toBeInTheDocument(); + expect(screen.queryByText('Documentation #1')).toBeInTheDocument(); + expect(screen.queryByText('Documentation #2')).toBeInTheDocument(); + expect(screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); }); it('should render only filtered entities with filtering', async () => { @@ -131,14 +131,10 @@ describe('Entity List Docs Grid', () => { }, ); - expect( - await screen.queryByText('Curated Documentation'), - ).toBeInTheDocument(); - expect(await screen.queryByText('Documentation #1')).toBeInTheDocument(); - expect( - await screen.queryByText('Documentation #2'), - ).not.toBeInTheDocument(); - expect(await screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); + expect(screen.queryByText('Curated Documentation')).toBeInTheDocument(); + expect(screen.queryByText('Documentation #1')).toBeInTheDocument(); + expect(screen.queryByText('Documentation #2')).not.toBeInTheDocument(); + expect(screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); }); it('should render nothing with filtering yielding no result', async () => { @@ -163,16 +159,10 @@ describe('Entity List Docs Grid', () => { }, ); - expect( - await screen.queryByText('Curated Documentation'), - ).not.toBeInTheDocument(); - expect( - await screen.queryByText('Documentation #1'), - ).not.toBeInTheDocument(); - expect( - await screen.queryByText('Documentation #2'), - ).not.toBeInTheDocument(); - expect(await screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); + expect(screen.queryByText('Curated Documentation')).not.toBeInTheDocument(); + expect(screen.queryByText('Documentation #1')).not.toBeInTheDocument(); + expect(screen.queryByText('Documentation #2')).not.toBeInTheDocument(); + expect(screen.queryByTestId('doc-not-found')).not.toBeInTheDocument(); }); it('should render an error without any documentation and without filtering', async () => { @@ -189,15 +179,9 @@ describe('Entity List Docs Grid', () => { }, ); - expect( - await screen.queryByText('All Documentation'), - ).not.toBeInTheDocument(); - expect( - await screen.queryByText('Documentation #1'), - ).not.toBeInTheDocument(); - expect( - await screen.queryByText('Documentation #2'), - ).not.toBeInTheDocument(); - expect(await screen.queryByTestId('doc-not-found')).toBeInTheDocument(); + expect(screen.queryByText('All Documentation')).not.toBeInTheDocument(); + expect(screen.queryByText('Documentation #1')).not.toBeInTheDocument(); + expect(screen.queryByText('Documentation #2')).not.toBeInTheDocument(); + expect(screen.queryByTestId('doc-not-found')).toBeInTheDocument(); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index e886454594..9babff0c54 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -21,7 +21,7 @@ import { useTheme, useMediaQuery } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import { CompoundEntityRef } from '@backstage/catalog-model'; -import { useApi } from '@backstage/core-plugin-api'; +import { useAnalytics, useApi } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { @@ -63,6 +63,7 @@ export const useTechDocsReaderDom = ( const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY); const sanitizerTransformer = useSanitizerTransformer(); const stylesTransformer = useStylesTransformer(); + const analytics = useAnalytics(); const techdocsStorageApi = useApi(techdocsStorageApiRef); const scmIntegrationsApi = useApi(scmIntegrationsApiRef); @@ -177,6 +178,12 @@ export const useTechDocsReaderDom = ( const parsedUrl = new URL(url); const fullPath = `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`; + // capture link clicks within documentation + const linkText = + (event.target as HTMLAnchorElement | undefined)?.innerText || url; + const to = url.replace(window.location.origin, ''); + analytics.captureEvent('click', linkText, { attributes: { to } }); + // hash exists when anchor is clicked on secondary sidebar if (parsedUrl.hash) { if (modifierActive) { @@ -219,7 +226,7 @@ export const useTechDocsReaderDom = ( onLoaded: () => {}, }), ]), - [theme, navigate], + [theme, navigate, analytics], ); useEffect(() => { diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx index e76cb1d173..dcb75f4cc4 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx @@ -17,6 +17,7 @@ import React, { PropsWithChildren, useEffect } from 'react'; import Helmet from 'react-helmet'; +import { Grid } from '@material-ui/core'; import { Skeleton } from '@material-ui/lab'; import CodeIcon from '@material-ui/icons/Code'; @@ -36,6 +37,8 @@ import { RELATION_OWNED_BY, CompoundEntityRef } from '@backstage/catalog-model'; import { Header, HeaderLabel } from '@backstage/core-components'; import { useRouteRef, configApiRef, useApi } from '@backstage/core-plugin-api'; +import { capitalize } from 'lodash'; + import { rootRouteRef } from '../../../routes'; const skeleton = ; @@ -81,7 +84,7 @@ export const TechDocsReaderPageHeader = ( setSubtitle(() => { let { site_description } = metadata; if (!site_description || site_description === 'None') { - site_description = 'Home'; + site_description = ''; } return site_description; }); @@ -102,7 +105,7 @@ export const TechDocsReaderPageHeader = ( const labels = ( <> - - + + + + + Source + + } + url={locationMetadata.target} /> ) : null} @@ -155,7 +165,7 @@ export const TechDocsReaderPageHeader = ( type="Documentation" typeLink={docsRootLink} title={title || skeleton} - subtitle={subtitle || skeleton} + subtitle={subtitle === '' ? undefined : subtitle || skeleton} > {tabTitle} diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index f4827591df..0acae327c1 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-todo-backend +## 0.1.35 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/integration@1.4.0 + - @backstage/catalog-model@1.1.3 + - @backstage/catalog-client@1.1.2 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.35-next.0 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index ae227478b6..f08ef060c5 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.35-next.0", + "version": "0.1.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/todo-backend/src/service/TodoReaderService.test.ts b/plugins/todo-backend/src/service/TodoReaderService.test.ts index 8077e2ddb9..3f68636a05 100644 --- a/plugins/todo-backend/src/service/TodoReaderService.test.ts +++ b/plugins/todo-backend/src/service/TodoReaderService.test.ts @@ -58,7 +58,7 @@ function mockCatalogClient(entity?: Entity): jest.Mocked { if (entity) { mock.getEntityByRef.mockReturnValue(entity); } - return mock; + return mock as Partial> as jest.Mocked; } function mockTodoReader(items?: TodoItem[]): jest.Mocked { diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index c97576555d..f05b2c3d4d 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-todo +## 0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.13-next.0 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index c5cd8df216..a098fe1132 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.2.13-next.0", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 54a75f3888..f17baf793d 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-user-settings-backend +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/catalog-model@1.1.3 + - @backstage/plugin-auth-node@0.2.7 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 5015b60456..94a9c01d55 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings-backend", "description": "The Backstage backend plugin to manage user settings", - "version": "0.1.2-next.0", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index d73d533cba..ff36b363d8 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-user-settings +## 0.5.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-app-api@1.2.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/types@1.0.1 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.5.1-next.0 ### Patch Changes diff --git a/plugins/user-settings/README.md b/plugins/user-settings/README.md index ce07d76257..9a99a69b36 100644 --- a/plugins/user-settings/README.md +++ b/plugins/user-settings/README.md @@ -16,7 +16,7 @@ for installation instructions. Add the item to the Sidebar: -```ts +```tsx import { Settings as SidebarSettings } from '@backstage/plugin-user-settings'; @@ -28,7 +28,7 @@ import { Settings as SidebarSettings } from '@backstage/plugin-user-settings'; Add the page to the App routing: -```ts +```tsx import { UserSettingsPage } from '@backstage/plugin-user-settings'; const AppRoutes = () => ( @@ -46,7 +46,7 @@ By default, the plugin provides a list of configured authentication providers fe If you want to supply your own custom list of Authentication Providers, use the `providerSettings` prop: -```ts +```tsx const MyAuthProviders = () => ( @@ -71,20 +71,20 @@ const AppRoutes = () => ( By default, the plugin renders 3 tabs of settings; GENERAL, AUTHENTICATION PROVIDERS, and FEATURE FLAGS. If you want to add more options for your users, -just pass the extra tabs using `UserSettingsTab` components as children of the `UserSettingsPage` route. +just pass the extra tabs using `SettingsLayout.Route` components as children of the `UserSettingsPage` route. The path is in this case a child of the settings path, in the example below it would be `/settings/advanced` so that you can easily link to it. ```tsx import { + SettingsLayout, UserSettingsPage, - UserSettingsTab, } from '@backstage/plugin-user-settings'; }> - + - + ; ``` @@ -93,3 +93,40 @@ make sure you use a similar component structure as the other tabs. You can take a look at [the example extra tab](https://github.com/backstage/backstage/blob/master/packages/app/src/components/advancedSettings/AdvancedSettings.tsx) we have created in Backstage's demo app. + +To change the layout altogether, create a custom page in `packages/app/src/components/user-settings/SettingsPage.tsx`: + +```tsx +import React from 'react'; +import { + SettingsLayout, + UserSettingsGeneral, +} from '@backstage/plugin-user-settings'; +import { AdvancedSettings } from './advancedSettings'; + +export const settingsPage = ( + + + + + + + + +); +``` + +Now register the new settings page in `packages/app/src/App.tsx`: + +```diff ++ import {settingsPage} from './components/settings/settingsPage'; + +const routes = ( + +- } /> ++ }> ++ {settingsPage} ++ + +); +``` diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md index c51d4f992a..dd8f9428ca 100644 --- a/plugins/user-settings/api-report.md +++ b/plugins/user-settings/api-report.md @@ -18,10 +18,12 @@ import { Observable } from '@backstage/types'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; +import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; import { SessionApi } from '@backstage/core-plugin-api'; import { StorageApi } from '@backstage/core-plugin-api'; import { StorageValueSnapshot } from '@backstage/core-plugin-api'; +import { TabProps } from '@material-ui/core'; // @public (undocumented) export const DefaultProviderSettings: (props: { @@ -43,7 +45,33 @@ export const Router: (props: { providerSettings?: JSX.Element }) => JSX.Element; export const Settings: (props: { icon?: IconComponent }) => JSX.Element; // @public (undocumented) -export const USER_SETTINGS_TAB_KEY = 'user-settings.tab'; +export const SettingsLayout: { + (props: SettingsLayoutProps): JSX.Element; + Route: (props: SettingsLayoutRouteProps) => null; +}; + +// @public (undocumented) +export type SettingsLayoutProps = { + title?: string; + subtitle?: string; + children?: React_2.ReactNode; +}; + +// @public (undocumented) +export type SettingsLayoutRouteProps = { + path: string; + title: string; + children: JSX.Element; + tabProps?: TabProps< + React_2.ElementType, + { + component?: React_2.ElementType; + } + >; +}; + +// @public @deprecated (undocumented) +export const USER_SETTINGS_TAB_KEY = 'plugin.user-settings.settingsLayoutRoute'; // @public (undocumented) export const UserSettingsAppearanceCard: () => JSX.Element; @@ -116,10 +144,10 @@ export class UserSettingsStorage implements StorageApi { snapshot(key: string): StorageValueSnapshot; } -// @public +// @public @deprecated export const UserSettingsTab: (props: UserSettingsTabProps) => JSX.Element; -// @public (undocumented) +// @public @deprecated (undocumented) export type UserSettingsTabProps = PropsWithChildren<{ path: string; title: string; diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 744cf40eec..b8db3a5b03 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.5.1-next.0", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@material-ui/lab": "4.0.0-alpha.57", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4", - "zen-observable": "^0.8.15" + "zen-observable": "^0.9.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0", @@ -58,7 +58,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/user-settings/src/components/SettingsPage.test.tsx b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx similarity index 63% rename from plugins/user-settings/src/components/SettingsPage.test.tsx rename to plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx index 01810bcc8e..d4560bdd06 100644 --- a/plugins/user-settings/src/components/SettingsPage.test.tsx +++ b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx @@ -16,39 +16,53 @@ import React from 'react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; -import { SettingsPage } from './SettingsPage'; -import { UserSettingsTab } from './UserSettingsTab'; +import { DefaultSettingsPage } from './DefaultSettingsPage'; +import { UserSettingsTab } from '../UserSettingsTab'; +import { useOutlet } from 'react-router'; +import { SettingsLayout } from '../SettingsLayout'; jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), useOutlet: jest.fn().mockReturnValue(undefined), })); -import { useOutlet } from 'react-router'; - -describe('', () => { +describe('', () => { beforeEach(() => { (useOutlet as jest.Mock).mockReset(); }); it('should render the settings page with 3 tabs', async () => { const { container } = await renderWithEffects( - wrapInTestApp(), + wrapInTestApp(), ); const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); expect(tabs).toHaveLength(3); }); - it('should render the settings page with 4 tabs when extra tabs are provided', async () => { + it('should render the settings page with 4 tabs when extra tabs are provided via UserSettingsTab', async () => { const advancedTabRoute = (
Advanced settings
); - (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute); const { container } = await renderWithEffects( - wrapInTestApp(), + wrapInTestApp(), + ); + + const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); + expect(tabs).toHaveLength(4); + expect(tabs[3].textContent).toEqual('Advanced'); + }); + + it('should render the settings page with 4 tabs when extra tabs are provided via SettingsLayout.Route', async () => { + const advancedTabRoute = ( + +
Advanced settings
+
+ ); + const { container } = await renderWithEffects( + wrapInTestApp(), ); const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); diff --git a/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx new file mode 100644 index 0000000000..6b5b63d6bd --- /dev/null +++ b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx @@ -0,0 +1,49 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { UserSettingsAuthProviders } from '../AuthProviders'; +import { UserSettingsFeatureFlags } from '../FeatureFlags'; +import { UserSettingsGeneral } from '../General'; +import { SettingsLayout, SettingsLayoutRouteProps } from '../SettingsLayout'; + +/** + * @public + */ +export const DefaultSettingsPage = (props: { + tabs?: React.ReactElement[]; + providerSettings?: JSX.Element; +}) => { + const { providerSettings, tabs } = props; + + return ( + + + + + + + + + + + {tabs} + + ); +}; diff --git a/plugins/user-settings/src/components/DefaultSettingsPage/index.ts b/plugins/user-settings/src/components/DefaultSettingsPage/index.ts new file mode 100644 index 0000000000..34dcb9340d --- /dev/null +++ b/plugins/user-settings/src/components/DefaultSettingsPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DefaultSettingsPage } from './DefaultSettingsPage'; diff --git a/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx new file mode 100644 index 0000000000..9855fdd048 --- /dev/null +++ b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx @@ -0,0 +1,82 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { TabProps } from '@material-ui/core'; +import { + Header, + Page, + RoutedTabs, + useSidebarPinState, +} from '@backstage/core-components'; +import { + attachComponentData, + useElementFilter, +} from '@backstage/core-plugin-api'; + +/** @public */ +export type SettingsLayoutRouteProps = { + path: string; + title: string; + children: JSX.Element; + tabProps?: TabProps; +}; + +export const LAYOUT_DATA_KEY = 'plugin.user-settings.settingsLayout'; +export const LAYOUT_ROUTE_DATA_KEY = 'plugin.user-settings.settingsLayoutRoute'; + +const Route: (props: SettingsLayoutRouteProps) => null = () => null; +attachComponentData(Route, LAYOUT_ROUTE_DATA_KEY, true); + +// This causes all mount points that are discovered within this route to use the path of the route itself +attachComponentData(Route, 'core.gatherMountPoints', true); + +/** @public */ +export type SettingsLayoutProps = { + title?: string; + subtitle?: string; + children?: React.ReactNode; +}; + +/** + * @public + */ +export const SettingsLayout = (props: SettingsLayoutProps) => { + const { title, children } = props; + const { isMobile } = useSidebarPinState(); + + const routes = useElementFilter(children, elements => + elements + .selectByComponentData({ + key: LAYOUT_ROUTE_DATA_KEY, + withStrictError: + 'Child of SettingsLayout must be an SettingsLayout.Route', + }) + .getElements() + .map(child => child.props), + ); + + return ( + + {!isMobile &&
} + + + ); +}; + +attachComponentData(SettingsLayout, LAYOUT_DATA_KEY, true); + +SettingsLayout.Route = Route; diff --git a/plugins/user-settings/src/components/SettingsLayout/index.ts b/plugins/user-settings/src/components/SettingsLayout/index.ts new file mode 100644 index 0000000000..6e610f8078 --- /dev/null +++ b/plugins/user-settings/src/components/SettingsLayout/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { + SettingsLayoutProps, + SettingsLayoutRouteProps, +} from './SettingsLayout'; +export { SettingsLayout } from './SettingsLayout'; diff --git a/plugins/user-settings/src/components/SettingsPage.tsx b/plugins/user-settings/src/components/SettingsPage.tsx deleted file mode 100644 index 9803bf4761..0000000000 --- a/plugins/user-settings/src/components/SettingsPage.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - Header, - Page, - TabbedLayout, - useSidebarPinState, -} from '@backstage/core-components'; -import React from 'react'; -import { useOutlet } from 'react-router'; -import { useElementFilter } from '@backstage/core-plugin-api'; -import { UserSettingsAuthProviders } from './AuthProviders'; -import { UserSettingsFeatureFlags } from './FeatureFlags'; -import { UserSettingsGeneral } from './General'; -import { USER_SETTINGS_TAB_KEY, UserSettingsTabProps } from './UserSettingsTab'; - -/** - * @public - */ -export const SettingsPage = (props: { providerSettings?: JSX.Element }) => { - const { providerSettings } = props; - const { isMobile } = useSidebarPinState(); - const outlet = useOutlet(); - - const tabs = useElementFilter(outlet, elements => - elements - .selectByComponentData({ - key: USER_SETTINGS_TAB_KEY, - }) - .getElements(), - ); - - return ( - - {!isMobile &&
} - - - - - - - - - - - - {tabs.map((child, i) => ( - - {child} - - ))} - - - ); -}; diff --git a/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx new file mode 100644 index 0000000000..b6277f0b59 --- /dev/null +++ b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx @@ -0,0 +1,106 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; +import { SettingsPage } from './SettingsPage'; +import { UserSettingsTab } from '../UserSettingsTab'; +import { useOutlet } from 'react-router'; +import { SettingsLayout } from '../SettingsLayout'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useOutlet: jest.fn().mockReturnValue(undefined), +})); + +describe('', () => { + beforeEach(() => { + (useOutlet as jest.Mock).mockReset(); + }); + + it('should render the default settings page with 3 tabs', async () => { + const { container } = await renderWithEffects( + wrapInTestApp(), + ); + + const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); + expect(tabs).toHaveLength(3); + }); + + it('should render the default settings page with 4 tabs when extra tabs are provided via UserSettingsTab', async () => { + const advancedTabRoute = ( + +
Advanced settings
+
+ ); + (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute); + const { container } = await renderWithEffects( + wrapInTestApp(), + ); + + const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); + expect(tabs).toHaveLength(4); + expect(tabs[3].textContent).toEqual('Advanced'); + }); + + it('should render the default settings page with 4 tabs when extra tabs are provided via SettingsLayout.Route', async () => { + const advancedTabRoute = ( + +
Advanced settings
+
+ ); + (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute); + const { container } = await renderWithEffects( + wrapInTestApp(), + ); + + const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); + expect(tabs).toHaveLength(4); + expect(tabs[3].textContent).toEqual('Advanced'); + const user = userEvent.setup(); + await user.click(screen.getByText(/Advanced/i)); + const content = container.querySelectorAll('article'); + expect(content[0].textContent).toEqual('Advanced settings'); + }); + + it('should render the custom settings page when custom layout is provided', async () => { + const customLayout = ( + + +
User settings
+
+ +
Advanced settings
+
+
+ ); + (useOutlet as jest.Mock).mockReturnValue(customLayout); + const { container } = await renderWithEffects( + wrapInTestApp(), + ); + + const tabs = container.querySelectorAll('[class*=MuiTabs-root] button'); + expect(tabs).toHaveLength(2); + expect(tabs[0].textContent).toEqual('General'); + expect(tabs[1].textContent).toEqual('Advanced'); + const user = userEvent.setup(); + await user.click(screen.getByText(/Advanced/i)); + const content = container.querySelectorAll('article'); + expect(content[0].textContent).toEqual('Advanced settings'); + }); +}); diff --git a/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx b/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx new file mode 100644 index 0000000000..eec386d60e --- /dev/null +++ b/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx @@ -0,0 +1,55 @@ +/* + * Copyright 2022 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 { useOutlet } from 'react-router'; +import React from 'react'; +import { DefaultSettingsPage } from '../DefaultSettingsPage'; +import { useElementFilter } from '@backstage/core-plugin-api'; +import { + SettingsLayoutProps, + SettingsLayoutRouteProps, +} from '../SettingsLayout'; +import { + LAYOUT_DATA_KEY, + LAYOUT_ROUTE_DATA_KEY, +} from '../SettingsLayout/SettingsLayout'; + +/** @public */ +export const SettingsPage = (props: { providerSettings?: JSX.Element }) => { + const { providerSettings } = props; + const outlet = useOutlet(); + const layout = useElementFilter(outlet, elements => + elements + .selectByComponentData({ + key: LAYOUT_DATA_KEY, + }) + .getElements(), + ); + const tabs = useElementFilter(outlet, elements => + elements + .selectByComponentData({ + key: LAYOUT_ROUTE_DATA_KEY, + }) + .getElements(), + ); + + return ( + <> + {(layout.length !== 0 && layout) || ( + + )} + + ); +}; diff --git a/plugins/user-settings/src/components/SettingsPage/index.ts b/plugins/user-settings/src/components/SettingsPage/index.ts new file mode 100644 index 0000000000..e957a1bf09 --- /dev/null +++ b/plugins/user-settings/src/components/SettingsPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { SettingsPage } from './SettingsPage'; diff --git a/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx index 171c54ecf3..ebddac00c1 100644 --- a/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx +++ b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx @@ -15,11 +15,15 @@ */ import React, { PropsWithChildren } from 'react'; import { attachComponentData } from '@backstage/core-plugin-api'; +import { + LAYOUT_ROUTE_DATA_KEY, + SettingsLayout, +} from '../SettingsLayout/SettingsLayout'; -/** @public */ -export const USER_SETTINGS_TAB_KEY = 'user-settings.tab'; +/** @public @deprecated Use SettingsLayout.Route approach instead */ +export const USER_SETTINGS_TAB_KEY = LAYOUT_ROUTE_DATA_KEY; -/** @public */ +/** @public @deprecated Use SettingsLayoutRouteProps instead */ export type UserSettingsTabProps = PropsWithChildren<{ /** * The path to the tab in the settings route @@ -34,9 +38,12 @@ export type UserSettingsTabProps = PropsWithChildren<{ * Renders a tab inside the settings page * @param props - Component props * @public + * @deprecated Use SettingsLayout.Route instead */ -export const UserSettingsTab = (props: UserSettingsTabProps) => { - return <>{props.children}; -}; +export const UserSettingsTab = (props: UserSettingsTabProps) => ( + + <>props.children + +); attachComponentData(UserSettingsTab, USER_SETTINGS_TAB_KEY, 'UserSettingsTab'); diff --git a/plugins/user-settings/src/components/index.ts b/plugins/user-settings/src/components/index.ts index 8dc76ee7f1..8eb43a7a10 100644 --- a/plugins/user-settings/src/components/index.ts +++ b/plugins/user-settings/src/components/index.ts @@ -21,3 +21,4 @@ export * from './General'; export * from './FeatureFlags'; export { useUserProfile } from './useUserProfileInfo'; export * from './UserSettingsTab'; +export * from './SettingsLayout'; diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 6f3270dba1..08fb5bf341 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-vault-backend +## 0.2.4 + +### Patch Changes + +- 687237da4c: Added `errorHandler()` middleware to `router` to prevent crashes caused by fatal errors in plugin backend +- Updated dependencies + - @backstage/backend-common@0.16.0 + - @backstage/backend-tasks@0.3.7 + - @backstage/backend-test-utils@0.1.30 + - @backstage/config@1.0.4 + - @backstage/errors@1.1.3 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index 2cc170337a..5a023e50e6 100644 --- a/plugins/vault-backend/package.json +++ b/plugins/vault-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-backend", "description": "A Backstage backend plugin that integrates towards Vault", - "version": "0.2.4-next.0", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,7 +53,7 @@ "@backstage/cli": "workspace:^", "@types/compression": "^1.7.2", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/vault-backend/src/service/VaultBuilder.ts b/plugins/vault-backend/src/service/VaultBuilder.ts index 67260f45ca..b82a5802bb 100644 --- a/plugins/vault-backend/src/service/VaultBuilder.ts +++ b/plugins/vault-backend/src/service/VaultBuilder.ts @@ -20,6 +20,7 @@ import { Logger } from 'winston'; import express, { Router } from 'express'; import { VaultClient } from './vaultApi'; import { TaskRunner, PluginTaskScheduler } from '@backstage/backend-tasks'; +import { errorHandler } from '@backstage/backend-common'; /** * Environment values needed by the VaultBuilder @@ -145,6 +146,7 @@ export class VaultBuilder { res.json({ items: secrets }); }); + router.use(errorHandler()); return router; } } diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index ce0f6c41cf..6f7da110d1 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-vault +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.2.1 + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/catalog-model@1.1.3 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/vault/package.json b/plugins/vault/package.json index dc5e7b0c13..6b0a360e4e 100644 --- a/plugins/vault/package.json +++ b/plugins/vault/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault", "description": "A Backstage plugin that integrates towards Vault", - "version": "0.1.5-next.0", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 8c68404127..a4fccd2e16 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-xcmetrics +## 0.2.31 + +### Patch Changes + +- 7573b65232: Internal refactor of imports to avoid circular dependencies +- 43afded227: Updated recharts to v2.0.0 and fixed typing issues +- dcf9e728de: Removed an unused and hidden build details route. +- Updated dependencies + - @backstage/core-components@0.12.0 + - @backstage/core-plugin-api@1.1.0 + - @backstage/errors@1.1.3 + - @backstage/theme@0.2.16 + +## 0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.2.31-next.0 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 6946095a01..026391e627 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.31-next.0", + "version": "0.2.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/scripts/check-type-dependencies.js b/scripts/check-type-dependencies.js index ba362bd5ff..ebad9b6dfc 100755 --- a/scripts/check-type-dependencies.js +++ b/scripts/check-type-dependencies.js @@ -136,10 +136,21 @@ function findTypesPackage(dep, pkg) { return undefined; } catch { try { - // Finally check if it's just a .d.ts file + // Check if it's just a .d.ts file require.resolve(`${dep}.d.ts`, { paths: [pkg.dir] }); return undefined; } catch { + // And finally a naive lookup of the file directly, in case `require.resolve` fails us due to "exports" + if (fs.existsSync(resolvePath(pkg.dir, `node_modules/${dep}.d.ts`))) { + return undefined; + } + if ( + fs.existsSync( + resolvePath(pkg.dir, `../../node_modules/${dep}.d.ts`), + ) + ) { + return undefined; + } throw mkErr('MissingDepError', `No types for ${dep}`, { dep }); } } diff --git a/scripts/isolated-release.js b/scripts/isolated-release.js deleted file mode 100755 index 4df900450e..0000000000 --- a/scripts/isolated-release.js +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env node -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const path = require('path'); -const childProcess = require('child_process'); -const { getPackages } = require('@manypkg/get-packages'); - -// Prepare a release of the provided packages, e.g. @backstage/core -async function main(args) { - if (args.includes('--help') || args.length === 0) { - const arg0 = path.relative(process.cwd(), process.argv[1]); - console.log(`Usage: ${process.argv0} ${arg0} ...`); - process.exit(1); - } - - const { packages } = await getPackages(__dirname); - const ignoreArgs = packages - .filter(p => !args.includes(p.packageJson.name)) - .flatMap(p => ['--ignore', p.packageJson.name]); - - const { status } = childProcess.spawnSync( - 'yarn', - ['changeset', 'version', ...ignoreArgs], - { - stdio: 'inherit', - }, - ); - if (status !== 0) { - return; - } - - childProcess.spawnSync( - 'yarn', - ['prettier', '--write', '{packages,plugins}/*/{package.json,CHANGELOG.md}'], - { - stdio: 'inherit', - }, - ); -} - -main(process.argv.slice(2)).catch(error => { - console.error(error.stack); - process.exit(1); -}); diff --git a/scripts/patch-release-for-pr.js b/scripts/patch-release-for-pr.js new file mode 100755 index 0000000000..be417e2911 --- /dev/null +++ b/scripts/patch-release-for-pr.js @@ -0,0 +1,170 @@ +#!/usr/bin/env node +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const fs = require('fs-extra'); +const path = require('path'); +const semver = require('semver'); +const { Octokit } = require('@octokit/rest'); +const { execFile: execFileCb } = require('child_process'); +const { promisify } = require('util'); + +const execFile = promisify(execFileCb); + +const owner = 'backstage'; +const repo = 'backstage'; +const rootDir = path.resolve(__dirname, '..'); + +const octokit = new Octokit({ + auth: process.env.GITHUB_TOKEN, +}); + +async function run(command, ...args) { + const { stdout, stderr } = await execFile(command, args, { + cwd: rootDir, + }); + + if (stderr) { + console.error(stderr); + } + + return stdout.trim(); +} + +/** + * Finds the current stable release version of the repo, looking at + * the current commit and backwards, finding the first commit were a + * stable version is present. + */ +async function findCurrentReleaseVersion() { + const rootPkgPath = path.resolve(rootDir, 'package.json'); + const pkg = await fs.readJson(rootPkgPath); + + if (!semver.prerelease(pkg.version)) { + return pkg.version; + } + + const { stdout: revListStr } = await execFile('git', [ + 'rev-list', + 'HEAD', + '--', + 'package.json', + ]); + const revList = revListStr.trim().split(/\r?\n/); + + for (const rev of revList) { + const { stdout: pkgJsonStr } = await execFile('git', [ + 'show', + `${rev}:package.json`, + ]); + if (pkgJsonStr) { + const pkgJson = JSON.parse(pkgJsonStr); + if (!semver.prerelease(pkgJson.version)) { + return pkgJson.version; + } + } + } + + throw new Error('No stable release found'); +} + +async function main(prNumberStr) { + const prNumber = parseInt(prNumberStr, 10); + if (!Number.isInteger(prNumber)) { + throw new Error('Must provide a PR number as the first argument'); + } + console.log(`PR number: ${prNumber}`); + + if (await run('git', 'status', '--porcelain')) { + throw new Error('Cannot run with a dirty working tree'); + } + + const release = await findCurrentReleaseVersion(); + console.log(`Patching release ${release}`); + + await run('git', 'fetch'); + + const patchBranch = `patch/v${release}`; + try { + await run('git', 'checkout', `origin/${patchBranch}`); + } catch { + await run('git', 'checkout', '-b', patchBranch, `v${release}`); + await run('git', 'push', 'origin', '-u', patchBranch); + } + + const { data } = await octokit.pulls.get({ + owner, + repo, + pull_number: prNumber, + }); + + const headSha = data.head.sha; + if (!headSha) { + throw new Error('head sha not available'); + } + const baseSha = data.base.sha; + if (!baseSha) { + throw new Error('base sha not available'); + } + const mergeBaseSha = await run('git', 'merge-base', headSha, baseSha); + + // Create new branch, apply changes from all commits on PR branch, commit, push + const branchName = `patch-release-pr-${prNumber}`; + await run('git', 'checkout', '-b', branchName); + + const logLines = await run( + 'git', + 'log', + `${mergeBaseSha}...${headSha}`, + '--reverse', + '--pretty=%H', + ); + for (const logSha of logLines.split(/\r?\n/)) { + await run('git', 'cherry-pick', '-n', logSha); + } + await run( + 'git', + 'commit', + '--signoff', + '--no-verify', + '-m', + `Patch from PR #${prNumber}`, + ); + + console.log('Running "yarn release" ...'); + await run('yarn', 'release'); + + await run('git', 'add', '.'); + await run( + 'git', + 'commit', + '--signoff', + '--no-verify', + '-m', + 'Generate Release', + ); + + await run('git', 'push', 'origin', '-u', branchName); + + console.log( + `https://github.com/backstage/backstage/compare/${patchBranch}...${branchName}?expand=1&body=This%20release%20fixes%20an%20issue%20where&title=Patch%20release%20of%20%23${prNumber}`, + ); +} + +main(process.argv.slice(2)).catch(error => { + console.error(error.stack || error); + process.exit(1); +}); diff --git a/scripts/prepare-release.js b/scripts/prepare-release.js index 962d54abb0..973f4fad58 100755 --- a/scripts/prepare-release.js +++ b/scripts/prepare-release.js @@ -209,7 +209,11 @@ async function applyPatchVersions(repo, patchVersions) { const deps = packageJson[depType]; for (const depName of Object.keys(deps ?? {})) { const currentRange = deps[depName]; - if (currentRange === '*' || currentRange === '') { + if ( + currentRange === '*' || + currentRange === '' || + currentRange.startsWith('workspace:') + ) { continue; } diff --git a/scripts/verify-lockfile-duplicates.js b/scripts/verify-lockfile-duplicates.js new file mode 100644 index 0000000000..590de0f93d --- /dev/null +++ b/scripts/verify-lockfile-duplicates.js @@ -0,0 +1,135 @@ +#!/usr/bin/env node +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable import/no-extraneous-dependencies */ + +const { execFile: execFileCb } = require('child_process'); +const { resolve: resolvePath, dirname: dirnamePath } = require('path'); +const { promisify } = require('util'); + +const execFile = promisify(execFileCb); + +async function findLockFiles() { + const projectRoot = resolvePath(__dirname, '..'); + + let files = process.argv.slice(2).filter(arg => !arg.startsWith('--')); + + for (const argumentFile of files) { + if (!argumentFile.match(/(?:^|[\/\\])yarn.lock$/)) { + throw new Error(`Not a yarn.lock file path argument: "${argumentFile}"`); + } + } + + if (!files.length) { + // List all lock files that are in the root or in an immediate subdirectory + files = ['yarn.lock', 'cypress/yarn.lock', 'microsite/yarn.lock']; + } + + return files.map(file => ({ + fileRelativeToProjectRoot: file, + directoryRelativeToProjectRoot: dirnamePath(file), + directoryAbsolute: resolvePath(projectRoot, dirnamePath(file)), + })); +} + +async function main() { + const lockFiles = await findLockFiles(); + + let fix = false; + for (const arg of process.argv) { + if (arg.startsWith('--')) { + if (arg === '--fix') { + fix = true; + } else { + throw new Error(`Unknown argument ${arg}`); + } + } + } + + for (const lockFile of lockFiles) { + console.log('Checking lock file', lockFile.fileRelativeToProjectRoot); + + let stdout; + let stderr; + let failed; + + try { + const result = await execFile( + 'yarn', + ['dedupe', ...(fix ? [] : ['--check'])], + { + shell: true, + cwd: lockFile.directoryAbsolute, + }, + ); + stdout = result.stdout?.trim(); + stderr = result.stderr?.trim(); + failed = false; + } catch (error) { + stdout = error.stdout?.trim(); + stderr = error.stderr?.trim(); + failed = true; + } + + if (stdout) { + console.log(stdout); + } + + if (stderr) { + console.error(stderr); + } + + if (failed) { + if (!fix) { + const command = `yarn dedupe${ + lockFile.directoryRelativeToProjectRoot === '.' + ? '' + : ` --cwd ${lockFile.directoryRelativeToProjectRoot}` + }`; + const padding = ' '.repeat(Math.max(0, 85 - 6 - command.length)); + console.error(''); + console.error( + '*************************************************************************************', + ); + console.error( + '* You have duplicate versions of some packages in a yarn.lock file. *', + ); + console.error( + '* To solve this, run the following command from the project root and commit all *', + ); + console.log( + '* yarn.lock changes. *', + ); + console.log( + '* *', + ); + console.log(`* ${command}${padding} *`); + console.error( + '*************************************************************************************', + ); + console.error(''); + } + + process.exit(1); + } + } +} + +main().catch(error => { + console.error(error.stack); + process.exit(1); +}); diff --git a/storybook/yarn.lock b/storybook/yarn.lock index be9a98e42a..77fbf8ca66 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -1528,18 +1528,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.12.11, @babel/types@npm:^7.12.7, @babel/types@npm:^7.18.10, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.4.4": - version: 7.18.10 - resolution: "@babel/types@npm:7.18.10" - dependencies: - "@babel/helper-string-parser": ^7.18.10 - "@babel/helper-validator-identifier": ^7.18.6 - to-fast-properties: ^2.0.0 - checksum: 11632c9b106e54021937a6498138014ebc9ad6c327a07b2af3ba8700773945aba4055fd136431cbe3a500d0f363cbf9c68eb4d6d38229897c5de9d06e14c85e8 - languageName: node - linkType: hard - -"@babel/types@npm:^7.8.3": +"@babel/types@npm:^7.12.11, @babel/types@npm:^7.12.7, @babel/types@npm:^7.18.10, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.18.13 resolution: "@babel/types@npm:7.18.13" dependencies: @@ -1985,7 +1974,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addons@npm:6.5.13, @storybook/addons@npm:^6.5.9": +"@storybook/addons@npm:6.5.13, @storybook/addons@npm:^6.0.0, @storybook/addons@npm:^6.5.9": version: 6.5.13 resolution: "@storybook/addons@npm:6.5.13" dependencies: @@ -2007,28 +1996,6 @@ __metadata: languageName: node linkType: hard -"@storybook/addons@npm:^6.0.0": - version: 6.5.12 - resolution: "@storybook/addons@npm:6.5.12" - dependencies: - "@storybook/api": 6.5.12 - "@storybook/channels": 6.5.12 - "@storybook/client-logger": 6.5.12 - "@storybook/core-events": 6.5.12 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.12 - "@storybook/theming": 6.5.12 - "@types/webpack-env": ^1.16.0 - core-js: ^3.8.2 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: c6242a80c7355544eb309603e77fdc3787d78ad983aba931f00812aeba75cc2cbd0e98c1ac0ce01441b58fabcdb671a9a799358f4bd6511cab289bc030d91f61 - languageName: node - linkType: hard - "@storybook/api@npm:6.5.10": version: 6.5.10 resolution: "@storybook/api@npm:6.5.10" @@ -2057,35 +2024,7 @@ __metadata: languageName: node linkType: hard -"@storybook/api@npm:6.5.12, @storybook/api@npm:^6.0.0": - version: 6.5.12 - resolution: "@storybook/api@npm:6.5.12" - dependencies: - "@storybook/channels": 6.5.12 - "@storybook/client-logger": 6.5.12 - "@storybook/core-events": 6.5.12 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.12 - "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.12 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - store2: ^2.12.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 3982cea5aaf851ccc19ff97ef82b7590d47839f0ebee28399e3b9381578edc130b4e46fe36431c62fa281949b2e0d5da2b1feafab0c2d24f70c4097d800b2679 - languageName: node - linkType: hard - -"@storybook/api@npm:6.5.13": +"@storybook/api@npm:6.5.13, @storybook/api@npm:^6.0.0": version: 6.5.13 resolution: "@storybook/api@npm:6.5.13" dependencies: @@ -2265,17 +2204,6 @@ __metadata: languageName: node linkType: hard -"@storybook/channels@npm:6.5.12": - version: 6.5.12 - resolution: "@storybook/channels@npm:6.5.12" - dependencies: - core-js: ^3.8.2 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - checksum: e6b240a6c62a68a485bf8f4db536df0504cfcbe9685654e5a5712b833917b9a620e91994bf2283a420e413511c967e92ead522c98ad7e6c0e88b3830ddfd4e30 - languageName: node - linkType: hard - "@storybook/channels@npm:6.5.13": version: 6.5.13 resolution: "@storybook/channels@npm:6.5.13" @@ -2318,7 +2246,7 @@ __metadata: languageName: node linkType: hard -"@storybook/client-logger@npm:6.5.10, @storybook/client-logger@npm:^6.4.0": +"@storybook/client-logger@npm:6.5.10": version: 6.5.10 resolution: "@storybook/client-logger@npm:6.5.10" dependencies: @@ -2328,17 +2256,7 @@ __metadata: languageName: node linkType: hard -"@storybook/client-logger@npm:6.5.12": - version: 6.5.12 - resolution: "@storybook/client-logger@npm:6.5.12" - dependencies: - core-js: ^3.8.2 - global: ^4.4.0 - checksum: bd11bc25115f9b4a965e378d7dac28f9152038173ab5debb1e116a7aba69c814752d2c8aa4092dd1fc3f60cd99d4896c9e74d5e6f3c85768e7633adaf5bd2bf2 - languageName: node - linkType: hard - -"@storybook/client-logger@npm:6.5.13": +"@storybook/client-logger@npm:6.5.13, @storybook/client-logger@npm:^6.4.0": version: 6.5.13 resolution: "@storybook/client-logger@npm:6.5.13" dependencies: @@ -2348,7 +2266,7 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:6.5.13": +"@storybook/components@npm:6.5.13, @storybook/components@npm:^6.0.0": version: 6.5.13 resolution: "@storybook/components@npm:6.5.13" dependencies: @@ -2367,25 +2285,6 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:^6.0.0": - version: 6.5.12 - resolution: "@storybook/components@npm:6.5.12" - dependencies: - "@storybook/client-logger": 6.5.12 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.12 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: fa469ae615d9146df7e23f01b85731d27e6400e2d94035db172deb1f61903d86c121d858558dd12307ecc6344d21b496db020731e73eff6ace3f82672b953a93 - languageName: node - linkType: hard - "@storybook/core-client@npm:6.5.13": version: 6.5.13 resolution: "@storybook/core-client@npm:6.5.13" @@ -2494,16 +2393,7 @@ __metadata: languageName: node linkType: hard -"@storybook/core-events@npm:6.5.12, @storybook/core-events@npm:^6.0.0": - version: 6.5.12 - resolution: "@storybook/core-events@npm:6.5.12" - dependencies: - core-js: ^3.8.2 - checksum: 82a4b9cb2a8599f3916db84b08b4cfbde8f56cb96a7afe641b3f144676fc7dc5a705e65f8844430b36ee6e6e14d6b2cb741622a8b39411276682219df5e04271 - languageName: node - linkType: hard - -"@storybook/core-events@npm:6.5.13": +"@storybook/core-events@npm:6.5.13, @storybook/core-events@npm:^6.0.0": version: 6.5.13 resolution: "@storybook/core-events@npm:6.5.13" dependencies: @@ -2913,22 +2803,6 @@ __metadata: languageName: node linkType: hard -"@storybook/router@npm:6.5.12": - version: 6.5.12 - resolution: "@storybook/router@npm:6.5.12" - dependencies: - "@storybook/client-logger": 6.5.12 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 545f4b767021b88f82eac69b9356fa5fa3a5866285c3a34fa762abc5743e3280895858aa5c820195d95a04c6768299191d4dd788a7d9fd3f17ff1d8236c0ba75 - languageName: node - linkType: hard - "@storybook/router@npm:6.5.13": version: 6.5.13 resolution: "@storybook/router@npm:6.5.13" @@ -3052,22 +2926,7 @@ __metadata: languageName: node linkType: hard -"@storybook/theming@npm:6.5.12, @storybook/theming@npm:^6.0.0": - version: 6.5.12 - resolution: "@storybook/theming@npm:6.5.12" - dependencies: - "@storybook/client-logger": 6.5.12 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: a982ebf88c7e1e21127febd17feebf26ac8d655f0c868bf110cbcaaef87eedb257300087618c525cb654808b590dc4b7b98dd6fec92fd76a040441d86c4b8289 - languageName: node - linkType: hard - -"@storybook/theming@npm:6.5.13": +"@storybook/theming@npm:6.5.13, @storybook/theming@npm:^6.0.0": version: 6.5.13 resolution: "@storybook/theming@npm:6.5.13" dependencies: @@ -3107,137 +2966,95 @@ __metadata: languageName: node linkType: hard -"@swc/core-android-arm-eabi@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-android-arm-eabi@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.122 - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@swc/core-android-arm64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-android-arm64@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@swc/core-darwin-arm64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-darwin-arm64@npm:1.3.9" +"@swc/core-darwin-arm64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-arm64@npm:1.3.16" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-darwin-x64@npm:1.3.9" +"@swc/core-darwin-x64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-x64@npm:1.3.16" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-freebsd-x64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-freebsd-x64@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@swc/core-linux-arm-gnueabihf@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-linux-arm-gnueabihf@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.16" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9" +"@swc/core-linux-arm64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.9" +"@swc/core-linux-arm64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.9" +"@swc/core-linux-x64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-x64-musl@npm:1.3.9" +"@swc/core-linux-x64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-musl@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-win32-arm64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.16" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-win32-ia32-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.16" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.9" +"@swc/core-win32-x64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.16" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.9": - version: 1.3.9 - resolution: "@swc/core@npm:1.3.9" + version: 1.3.16 + resolution: "@swc/core@npm:1.3.16" dependencies: - "@swc/core-android-arm-eabi": 1.3.9 - "@swc/core-android-arm64": 1.3.9 - "@swc/core-darwin-arm64": 1.3.9 - "@swc/core-darwin-x64": 1.3.9 - "@swc/core-freebsd-x64": 1.3.9 - "@swc/core-linux-arm-gnueabihf": 1.3.9 - "@swc/core-linux-arm64-gnu": 1.3.9 - "@swc/core-linux-arm64-musl": 1.3.9 - "@swc/core-linux-x64-gnu": 1.3.9 - "@swc/core-linux-x64-musl": 1.3.9 - "@swc/core-win32-arm64-msvc": 1.3.9 - "@swc/core-win32-ia32-msvc": 1.3.9 - "@swc/core-win32-x64-msvc": 1.3.9 + "@swc/core-darwin-arm64": 1.3.16 + "@swc/core-darwin-x64": 1.3.16 + "@swc/core-linux-arm-gnueabihf": 1.3.16 + "@swc/core-linux-arm64-gnu": 1.3.16 + "@swc/core-linux-arm64-musl": 1.3.16 + "@swc/core-linux-x64-gnu": 1.3.16 + "@swc/core-linux-x64-musl": 1.3.16 + "@swc/core-win32-arm64-msvc": 1.3.16 + "@swc/core-win32-ia32-msvc": 1.3.16 + "@swc/core-win32-x64-msvc": 1.3.16 dependenciesMeta: - "@swc/core-android-arm-eabi": - optional: true - "@swc/core-android-arm64": - optional: true "@swc/core-darwin-arm64": optional: true "@swc/core-darwin-x64": optional: true - "@swc/core-freebsd-x64": - optional: true "@swc/core-linux-arm-gnueabihf": optional: true "@swc/core-linux-arm64-gnu": @@ -3256,21 +3073,7 @@ __metadata: optional: true bin: swcx: run_swcx.js - checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa - languageName: node - linkType: hard - -"@swc/wasm@npm:1.2.122": - version: 1.2.122 - resolution: "@swc/wasm@npm:1.2.122" - checksum: 563345370c5ad18373d3b403590ab880fe52dcd8fc8c8601be263fcd9886520b28a7f4e46236cf49ca2b136c79d4ef50c960bc34b7cdc2068118b0d84dfca1f4 - languageName: node - linkType: hard - -"@swc/wasm@npm:1.2.130": - version: 1.2.130 - resolution: "@swc/wasm@npm:1.2.130" - checksum: 02203bfef3e382c64cbbd63c138c8fdf61865e74d923b317e9d9e9f33f5a3f0a9533b5fdbc9505e76d78e864be04a82fc847eb987a1e47ccac5850146c858292 + checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13 languageName: node linkType: hard @@ -7930,25 +7733,25 @@ __metadata: languageName: node linkType: hard -"loader-utils@npm:^1.1.0, loader-utils@npm:^1.2.3": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" +"loader-utils@npm:^1.2.3": + version: 1.4.2 + resolution: "loader-utils@npm:1.4.2" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 + checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 languageName: node linkType: hard -"loader-utils@npm:^2.0.0": - version: 2.0.2 - resolution: "loader-utils@npm:2.0.2" +"loader-utils@npm:^2.0.0, loader-utils@npm:^2.0.3": + version: 2.0.4 + resolution: "loader-utils@npm:2.0.4" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^2.1.2 - checksum: 9078d1ed47cadc57f4c6ddbdb2add324ee7da544cea41de3b7f1128e8108fcd41cd3443a85b7ee8d7d8ac439148aa221922774efe4cf87506d4fb054d5889303 + checksum: a5281f5fff1eaa310ad5e1164095689443630f3411e927f95031ab4fb83b4a98f388185bb1fe949e8ab8d4247004336a625e9255c22122b815bb9a4c5d8fc3b7 languageName: node linkType: hard @@ -8465,16 +8268,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^3.0.0, minipass@npm:^3.1.1": - version: 3.3.4 - resolution: "minipass@npm:3.3.4" - dependencies: - yallist: ^4.0.0 - checksum: 5d95a7738c54852ba78d484141e850c792e062666a2d0c681a5ac1021275beb7e1acb077e59f9523ff1defb80901aea4e30fac10ded9a20a25d819a42916ef1b - languageName: node - linkType: hard - -"minipass@npm:^3.1.6": +"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": version: 3.3.5 resolution: "minipass@npm:3.3.5" dependencies: @@ -9812,25 +9606,25 @@ __metadata: linkType: hard "react-hot-loader@npm:^4.13.0": - version: 4.13.0 - resolution: "react-hot-loader@npm:4.13.0" + version: 4.13.1 + resolution: "react-hot-loader@npm:4.13.1" dependencies: fast-levenshtein: ^2.0.6 global: ^4.3.0 hoist-non-react-statics: ^3.3.0 - loader-utils: ^1.1.0 + loader-utils: ^2.0.3 prop-types: ^15.6.1 react-lifecycles-compat: ^3.0.4 shallowequal: ^1.1.0 source-map: ^0.7.3 peerDependencies: - "@types/react": "^15.0.0 || ^16.0.0 || ^17.0.0 " - react: "^15.0.0 || ^16.0.0 || ^17.0.0 " - react-dom: "^15.0.0 || ^16.0.0 || ^17.0.0 " + "@types/react": ^15.0.0 || ^16.0.0 || ^17.0.0 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: effdbf4644ce912ae20ad94be62083970c74b26a59fe24ed0024cf73190a5b3edf59650cb693bdd7b70791df8ab8530de273d73b895c4831a91da8a76683e3a3 + checksum: f90890d5160dcb2bfae4022cba065d8e5c26b86f34c4604cbbdd39f5e4dfd82c05c317bb05ef3d4da2aa0be7e8e205c905daea1af40d3a7ef0d07c3d289da11c languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index c42aac2eec..3beb795108 100644 --- a/yarn.lock +++ b/yarn.lock @@ -86,30 +86,6 @@ __metadata: languageName: node linkType: hard -"@apollo/protobufjs@npm:1.2.2": - version: 1.2.2 - resolution: "@apollo/protobufjs@npm:1.2.2" - dependencies: - "@protobufjs/aspromise": ^1.1.2 - "@protobufjs/base64": ^1.1.2 - "@protobufjs/codegen": ^2.0.4 - "@protobufjs/eventemitter": ^1.1.0 - "@protobufjs/fetch": ^1.1.0 - "@protobufjs/float": ^1.0.2 - "@protobufjs/inquire": ^1.1.0 - "@protobufjs/path": ^1.1.2 - "@protobufjs/pool": ^1.1.0 - "@protobufjs/utf8": ^1.1.0 - "@types/long": ^4.0.0 - "@types/node": ^10.1.0 - long: ^4.0.0 - bin: - apollo-pbjs: bin/pbjs - apollo-pbts: bin/pbts - checksum: 3f3ec1f428cbcc53760daa6f1076c9043a5aa270b2c9a2ca9f97610eabd3ee1aea08dd36fac658bab83eb6607bc62340bbc6c13ba6bba3c6776df71d68b55929 - languageName: node - linkType: hard - "@apollo/protobufjs@npm:1.2.6": version: 1.2.6 resolution: "@apollo/protobufjs@npm:1.2.6" @@ -303,9 +279,9 @@ __metadata: languageName: node linkType: hard -"@asyncapi/react-component@npm:1.0.0-next.43": - version: 1.0.0-next.43 - resolution: "@asyncapi/react-component@npm:1.0.0-next.43" +"@asyncapi/react-component@npm:1.0.0-next.44": + version: 1.0.0-next.44 + resolution: "@asyncapi/react-component@npm:1.0.0-next.44" dependencies: "@asyncapi/avro-schema-parser": ^0.3.0 "@asyncapi/openapi-schema-parser": ^2.0.0 @@ -319,7 +295,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: d19adc2b6e674633457da28d38636df4cf9891f4038827b52f2737699d064bcf0d3be707e9f3284852d1bb507f3f36df9ec3bb02fd6f901cfda7a1f49ea9c5da + checksum: 1d96db3bc6a4655884969a7639467836376c028df1a00f8930adf4e1b6ecb43e6a2d61df5c68e63d6c105d319fecb3f2ac0e4146274a81a874fbde17f4dbac1c languageName: node linkType: hard @@ -330,6 +306,790 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/ie11-detection@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/ie11-detection@npm:2.0.2" + dependencies: + tslib: ^1.11.1 + checksum: 713293deea8eefd3ab43dc05e62228571d27754e7293f8ec2fd8a0c693fbbfc55213e6599387776e3cdbc951965dc62e24e92b9c4a853e4a50d00ae6a9f6b2bd + languageName: node + linkType: hard + +"@aws-crypto/sha256-browser@npm:2.0.0": + version: 2.0.0 + resolution: "@aws-crypto/sha256-browser@npm:2.0.0" + dependencies: + "@aws-crypto/ie11-detection": ^2.0.0 + "@aws-crypto/sha256-js": ^2.0.0 + "@aws-crypto/supports-web-crypto": ^2.0.0 + "@aws-crypto/util": ^2.0.0 + "@aws-sdk/types": ^3.1.0 + "@aws-sdk/util-locate-window": ^3.0.0 + "@aws-sdk/util-utf8-browser": ^3.0.0 + tslib: ^1.11.1 + checksum: 7bc1ff042d0c53a46c0fc3824bd97fb3ed1df7dc030b8a995889471052860b8c8ade469c97866fafd8249a3144d0f48b0f1054f357e2b403606009381c4b8f0e + languageName: node + linkType: hard + +"@aws-crypto/sha256-js@npm:2.0.0": + version: 2.0.0 + resolution: "@aws-crypto/sha256-js@npm:2.0.0" + dependencies: + "@aws-crypto/util": ^2.0.0 + "@aws-sdk/types": ^3.1.0 + tslib: ^1.11.1 + checksum: e4abf9baec6bed19d380f92a999a41ac5bdd8890dfd45971d29054c298854c5b7087e7de633413f2e64618ef8238ccf4c0b75797c73063c74bbba3cb5d8b2581 + languageName: node + linkType: hard + +"@aws-crypto/sha256-js@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/sha256-js@npm:2.0.2" + dependencies: + "@aws-crypto/util": ^2.0.2 + "@aws-sdk/types": ^3.110.0 + tslib: ^1.11.1 + checksum: 9125ec65a2b05fce908ac2289ba97b995a299f2d717684804211df8e8bcffd8cd9b8861582240655b88f2255c46fcee34026f75c057ffb22f44b6a76cd43f65a + languageName: node + linkType: hard + +"@aws-crypto/supports-web-crypto@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/supports-web-crypto@npm:2.0.2" + dependencies: + tslib: ^1.11.1 + checksum: 03d04d29292dc1b76db9bc6becd05f52fa79adee0ec084f971b0767f7e73250dd0422bea57636015f8c27f38aefcd1d9c58800a4749cf35339296c8d670f3ccb + languageName: node + linkType: hard + +"@aws-crypto/util@npm:^2.0.0, @aws-crypto/util@npm:^2.0.2": + version: 2.0.2 + resolution: "@aws-crypto/util@npm:2.0.2" + dependencies: + "@aws-sdk/types": ^3.110.0 + "@aws-sdk/util-utf8-browser": ^3.0.0 + tslib: ^1.11.1 + checksum: 13cb33a39005b09c062398d361043c2224bc8ba42b1432bad52e15bc4bf9ffad4facdddc394b3cc71b3fb8d86a7ec325fd1afa107b5fde0dab84a7e32d311d7f + languageName: node + linkType: hard + +"@aws-sdk/abort-controller@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/abort-controller@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 28f5bc16b5aba414e354df603bc8becd010aa8c9b3c79e527130723a39f21d5a3df98c3bafb3cea733d415a5b042af90098ffa9dfa29d400114c2f6f5292524e + languageName: node + linkType: hard + +"@aws-sdk/client-sqs@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sqs@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/client-sts": 3.183.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-node": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/md5-js": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-sdk-sqs": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + entities: 2.2.0 + fast-xml-parser: 3.19.0 + tslib: ^2.3.1 + checksum: fe0a7ba53cac4d52c25a4a4f1a1bb16438d5011347fcfec037df1d73379d750cd47b437f7a45aea2d4e29bc92587b51dd7631a06f5d6881e3b67b2d4c0dd2633 + languageName: node + linkType: hard + +"@aws-sdk/client-sso@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sso@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + tslib: ^2.3.1 + checksum: 6909329cf87c1a0c830fa9657e04c7e1ae496d7d79cc0a6813999503ae809f245f0b879af1d5564a5d97c2c69583c8a4df702d29ec7dc75934d98a0cdf017ad3 + languageName: node + linkType: hard + +"@aws-sdk/client-sts@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sts@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-node": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-sdk-sts": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + entities: 2.2.0 + fast-xml-parser: 3.19.0 + tslib: ^2.3.1 + checksum: d4492e537803d64e5fc0c5db8ac3a3788204aadc14b21e4fb407188feb58b35689c4a6878b4f13123a5f35f7e9fa01d95d427be168aeec9072aea881f2a92fb7 + languageName: node + linkType: hard + +"@aws-sdk/config-resolver@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/config-resolver@npm:3.183.0" + dependencies: + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-config-provider": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + checksum: 1be0ab79d5019f7502a7aee8c740f4e381ab7501ed639569526a4a7e1c70ad6bb36d642a8a2b18afe58c34497c6f2f8244dbf05211a0f6bc9a57e5e379c70b2b + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-env@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 4281e14c286cc5c57c69ba88c49fe1c1ff61f27923db5e8f852a84cce02b40fdc938f876ad08e72005deae9a28fab7400f747f63ca50f9c4d60e04e6c2705205 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-imds@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-imds@npm:3.183.0" + dependencies: + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + tslib: ^2.3.1 + checksum: e9fe1007b22825dc0c033beb2057b9f759d8cafec6e65d08ba4915bccb9b7d737eeccb3d06e9768a084b6726d9ea10778172b1bec695353c60276c1a5c21370e + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-ini@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.183.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/credential-provider-sso": 3.183.0 + "@aws-sdk/credential-provider-web-identity": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: c7784a3674c863dacc1305a08dd63cb16d1e7374250b0ceafa9feee8344de4228d7c32e84fbaa9d963adab69eb3938cd75b99554756da120cd9beae4693eded9 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.183.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/credential-provider-ini": 3.183.0 + "@aws-sdk/credential-provider-process": 3.183.0 + "@aws-sdk/credential-provider-sso": 3.183.0 + "@aws-sdk/credential-provider-web-identity": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: f23e1148054a96d68632284501ba01c4285cce1a2f4562817ec4b7fa315ff56e2f6b97fae0d2ae26fd52fca8c9f000be5d72a3582cff6c32ba10010f02a30977 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-process@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 3109e79ec2b4647f5e7f78c6dc2e10cd8a34a70147e7e90549153b7ff3ff12eda3499b3189d6fc1f3b99f461d5445e8017b44cd50029d30b0fc7437ad88a5f38 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-sso@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.183.0" + dependencies: + "@aws-sdk/client-sso": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 8775894ef50499361a4b49d846417c2c1e1ea90383730a32428154628358e7847f6f29dddd3cd04d3a4e15c1343fe10b051a92863055989ac3c4cb241e68f63a + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-web-identity@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: c39576c8f35137284fc69db8d94adcf07fa89d51153ee9710481262e205d485ff089a796e8a253aa14a0434dde91eadb65602fc614167a4f14301201ee840c08 + languageName: node + linkType: hard + +"@aws-sdk/fetch-http-handler@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/fetch-http-handler@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/querystring-builder": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + tslib: ^2.3.1 + checksum: 87c51d1dad8c469e32b99f6ed3729e753097cd4a9f8f417ec8681cf01e18b9a5dc6571f3cd1220293216bd4527b8499bb2ea1f821a240fde6d9560817c120066 + languageName: node + linkType: hard + +"@aws-sdk/hash-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/hash-node@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: fbed8757df633620807594535e3bb7d387576e0c2f89ad16dc7c98405a9d1d9743bea50148186de2f19cac67144b30f7f89e6c15317ddd7b8c0c8f61ca9556ef + languageName: node + linkType: hard + +"@aws-sdk/invalid-dependency@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/invalid-dependency@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: d928ca26d4390ad4f5e2c8198d16e14b675face6ad8c4a4eef699b54ce3f6cba584456659287b0e57e9f9019bc456b51dfa474671e11bf555fe04ed16174c10c + languageName: node + linkType: hard + +"@aws-sdk/is-array-buffer@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/is-array-buffer@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 717e508989821434a2ace4f690fc599f67b3f28ee9de5f06fce65a296fe11a68a5b97f30d66bfbf490d4a83259e4ffa1f0321231e4a54ce2440a9c6fdbacde24 + languageName: node + linkType: hard + +"@aws-sdk/md5-js@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/md5-js@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + tslib: ^2.3.1 + checksum: 5bd92465940ace6b3ca13342bd60eab42ffd5d74dfa65655c28e10bbf4aa0c32b2f9b4deb2050f3d092b8586e558bf248559af9c3cffb37810961169ad0797af + languageName: node + linkType: hard + +"@aws-sdk/middleware-content-length@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-content-length@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: bf3ec6872a925dbafd91e57334b6264e8446ca59eba598ee4bc7b37113c466300ac6b77ab314c4aa2859221f1f4e98beabbd365346e0815d591f276e642d1849 + languageName: node + linkType: hard + +"@aws-sdk/middleware-host-header@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: b4c4886976cffec614ff368daa995a69c765e737c8d366daa0033d781cf8e7483565bb3627ecd752698edc23dcf578de6657c9e8cb41c0fcd92631d17b7749b8 + languageName: node + linkType: hard + +"@aws-sdk/middleware-logger@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-logger@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 10ffb6af0f81b0144fef91af2bbeaeb680df2beff838f2a6ebcc260971fd6252a166e3bf3501c1fc00f6f8f203117ff6e2b4baebb7a6d8cd8504b7e1f392bd6d + languageName: node + linkType: hard + +"@aws-sdk/middleware-recursion-detection@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 461117e0dc8c38750942035a07163817bc8e89f377211f5fb52d4314acae4e7e6cb49be04193c508112833535b33814c1609196cb65e38cff1122043398ad89e + languageName: node + linkType: hard + +"@aws-sdk/middleware-retry@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-retry@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/service-error-classification": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + uuid: ^8.3.2 + checksum: 76fa3f9fe5f1c67bbfa792611289edf0afa2d0271073039931ac9ea46b3f432d74692d2db55443f40b7e97014898454f6d4bd8d2f2f5714a4281428b7464efac + languageName: node + linkType: hard + +"@aws-sdk/middleware-sdk-sqs@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-hex-encoding": 3.183.0 + tslib: ^2.3.1 + checksum: 0bb914b2e7a5391f5b22a5262a5c299fa7e3eb22076d00c4cfffb449e97404b4830a77bb742e8f3110d66f15ae9aad81ea740238799cc35bb8d328eaf13f3fe2 + languageName: node + linkType: hard + +"@aws-sdk/middleware-sdk-sts@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-sdk-sts@npm:3.183.0" + dependencies: + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 1969d6128d24cc7d8ff199c2900d805281928668f4dc3ffd128065ccfe515f9f7467a265af276592009bd285847cb9298f8ba4b1dfbe33971c3e7de80986b422 + languageName: node + linkType: hard + +"@aws-sdk/middleware-serde@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-serde@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 7495bb2adceab2c686588697fd9dd50a859706a8d33d98d9907ffc8f9ef78af141f2654cdac8d7b28b1f0544dcf2e52f25d109f5da1348102234ab5b4e79b256 + languageName: node + linkType: hard + +"@aws-sdk/middleware-signing@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-signing@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + checksum: 8025499acfefc072511adbc5084a1ed3cfe9cd9e514c58045425c87538af72ad3adfc134f7d0a059ff52832da392b4679b62d4ad28e477b866a20e78370f0758 + languageName: node + linkType: hard + +"@aws-sdk/middleware-stack@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-stack@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 03136847b96b0e4baba9b64f53a6c6b5738b1fa2c645edb3f47c1f85082791549b423ea791af33e9da3507cd56fbcbd052f1ba773a9f45ea42a3647277e85264 + languageName: node + linkType: hard + +"@aws-sdk/middleware-user-agent@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 8d1001d6d30f0f56aa440c541f6dcee9aad9190837e7a9653aef35448ff13e644cb7a441373192134ac86b5741fa64a120add07202cb97674018bd44612acdf7 + languageName: node + linkType: hard + +"@aws-sdk/node-config-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/node-config-provider@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 673fb105de8d11ddd1c3e636c7ed01ef4fbe412a7d96543d9db69149dfad64d33adf5b96b106763c058190841ea497f220e1b75ca438dbda7b34729f00b9e823 + languageName: node + linkType: hard + +"@aws-sdk/node-http-handler@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/node-http-handler@npm:3.183.0" + dependencies: + "@aws-sdk/abort-controller": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/querystring-builder": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: a24ee8cc4e3b63fdec0ebb671caa1e634af488befa7c93a28bb733bb532934c221f6c47707db20264af91ca84336a50b98427b425329b89aeac2a6d2be9537ff + languageName: node + linkType: hard + +"@aws-sdk/property-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/property-provider@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 6e8616e5f7efa9f46bdf62118dfc586e61dcdf0bc99f82305759020ce3d25fc1d2db71c62cfd4417a757a138b1a539cf305b584e6e7ade9bce9975fbe66fd326 + languageName: node + linkType: hard + +"@aws-sdk/protocol-http@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/protocol-http@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 13b255bcb37b70853d93374f972d743c80f33ac16188c41b512536c2dbec4d7beb55226bfac6d809981d63bbc87f6bf345334238f187da2faa9feaef5001e0a7 + languageName: node + linkType: hard + +"@aws-sdk/querystring-builder@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/querystring-builder@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-uri-escape": 3.183.0 + tslib: ^2.3.1 + checksum: a3de19863ccee4e8c9d5bbd719688ee1ffea02c3d90aad5e9c3eb04bed942ff8e5be0bfbc21ed03a968481abe2a2b1093e93b986b4111c468a9f3d3466b61f83 + languageName: node + linkType: hard + +"@aws-sdk/querystring-parser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/querystring-parser@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: f05a03c46317c97f1b775f7c5be19365cf464396edc6b23c93efd5289ff1a8658883f7c9dde2cc7b74bb42b57f257bc212abae5d62100d23cdec5409fbffe468 + languageName: node + linkType: hard + +"@aws-sdk/service-error-classification@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/service-error-classification@npm:3.183.0" + checksum: 8c015163aee9ec4d789daa8605e5b9424dfda81d3f609a2c34d800cb36ee78f4a3af02d1738c7e75f9a62cd1ef8ec4307f77457eecba3de4c6565a981484bca4 + languageName: node + linkType: hard + +"@aws-sdk/shared-ini-file-loader@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/shared-ini-file-loader@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 317fd0d8012559754f82b88fb386d2a01c19be1d3a0b6da3a6436f71701ed8cd8fbe3f5aa869fd7bbfb8dfb148cd9de02aa68e93001200c76ba9e0691e135773 + languageName: node + linkType: hard + +"@aws-sdk/signature-v4@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/signature-v4@npm:3.183.0" + dependencies: + "@aws-sdk/is-array-buffer": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-hex-encoding": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + "@aws-sdk/util-uri-escape": 3.183.0 + tslib: ^2.3.1 + checksum: 6639a4925b194171907fc1cf61101470836f5a8fa363f3fcd7b70bbaa4c756f43e13ad93b575885218a68192c375295d359a7e91db370816bd8f39f9c158ba36 + languageName: node + linkType: hard + +"@aws-sdk/smithy-client@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/smithy-client@npm:3.183.0" + dependencies: + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 70866adfd91fb35721bcd8667d9a4638e306de6ddc22be37a5b3ea19dfc2a1404a7325992f7f56d635a3bfd3b0ffa159d32f17df35c47ada4724ad8d5bb8d1ce + languageName: node + linkType: hard + +"@aws-sdk/types@npm:3.183.0, @aws-sdk/types@npm:^3.1.0, @aws-sdk/types@npm:^3.110.0": + version: 3.183.0 + resolution: "@aws-sdk/types@npm:3.183.0" + checksum: ab6e888ef8f6d5f5c047dbe0899ac94ad4aa83b9ae1b1fd7a3b88eacec61ab912f215fda65c71f783418d569d1088641806f6b98c9a28ddae04cc70d0eeccea7 + languageName: node + linkType: hard + +"@aws-sdk/url-parser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/url-parser@npm:3.183.0" + dependencies: + "@aws-sdk/querystring-parser": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 54c99d47e927368db12b6aa1fe4331a27461502355e0c18e99d8e05d9a114529d0b15965ff885cae8e19e49692ad44bf3c323ffdc535d7129deac900f286d1d5 + languageName: node + linkType: hard + +"@aws-sdk/util-base64-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-base64-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 2c3a4dc7e285b146285ac23de155de5e885d96aa46b29f9c830b6f12541032c6a42be7fd412ec019ddb83e6f155f561d04065b99159515d26d28c0968965dcf2 + languageName: node + linkType: hard + +"@aws-sdk/util-base64-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-base64-node@npm:3.183.0" + dependencies: + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: d8d0330aa768f816411a7b2343c500728501775d2f8d7c121d52d8484cbdd938102f3049e69e28574c838416ead0cb742494140609287b8d462bfb041218600d + languageName: node + linkType: hard + +"@aws-sdk/util-body-length-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-body-length-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 294074e20e4eb46ea992fc9d50fac0b97875d1d09efa706d5298e34f4200226c90bb33bbe96c41c7e91a43fbe44e6cfc0654d09fcdb823fe579545ada65701d9 + languageName: node + linkType: hard + +"@aws-sdk/util-body-length-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-body-length-node@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 60697959c63731d6b4b334bed91d08c4e38e09c0ad95000509641370249c76c5df1ffa0a7cab7418d250a526f49e660f0c67cea28547e442ac47feb7623413b8 + languageName: node + linkType: hard + +"@aws-sdk/util-buffer-from@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-buffer-from@npm:3.183.0" + dependencies: + "@aws-sdk/is-array-buffer": 3.183.0 + tslib: ^2.3.1 + checksum: 5f16145cf68b0756f0930990cfba57ac343c83c6e9dc48bc8d4f488cd66548a9e186e702fa94ba33b69d852c2d019eedf4116ac676cf0dfb701081e39e0776dd + languageName: node + linkType: hard + +"@aws-sdk/util-config-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-config-provider@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 8af6bf5ba31ec0a2fcf994f0a13bde5ff948bcdba02d153cdeea2105ea5eaf934368456bc92f35bfa42a7475cd4d2d2b9a644dfb8b4c2670ae2f103c045dc8b4 + languageName: node + linkType: hard + +"@aws-sdk/util-defaults-mode-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-defaults-mode-browser@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + bowser: ^2.11.0 + tslib: ^2.3.1 + checksum: 8ff54acf1684dd9d82ca13a522c5d2d7ee305511a2748f6e8ef7dc43e668798269e51455ac81b905a5b000a704fd5536f178c84425b8c431500e6a8dc1418135 + languageName: node + linkType: hard + +"@aws-sdk/util-defaults-mode-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-defaults-mode-node@npm:3.183.0" + dependencies: + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 40665d251844c4add23e358d9171add7180e0f1fcd4bd99601f4bdd03daa2259fed2567fa200152e14c4d7b1acc1126997f5b4e74c569ee1032f9fee16e6b582 + languageName: node + linkType: hard + +"@aws-sdk/util-hex-encoding@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-hex-encoding@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 1bf9577d96d01c13a3118e5d767c1e16b1f4f1c574168d78e128e0342edac30c87776340e9e14deb1e9adf539a6b2f953338adabc097fb143e870889698a6308 + languageName: node + linkType: hard + +"@aws-sdk/util-locate-window@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/util-locate-window@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: c29899b440c148aa44a5d9322e06e4cf21644e47bee10555cf8db104d9d76b3985fa4da6e8ca92c137b0b739f7504a7d106e9da49e1d189b84f51f45c21b2204 + languageName: node + linkType: hard + +"@aws-sdk/util-middleware@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-middleware@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: e1a433aebae5e74b365ecb4a57e3c583e7b89697f24b0c9edde93b8ba358e92256550329efb7c6924c0a5037e1bad2b7a1c8ed1b6d02e1aaaa35bca502923752 + languageName: node + linkType: hard + +"@aws-sdk/util-uri-escape@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-uri-escape@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 9d5f30821cdad15ed6912f7406f83b5b5a45358b208a9374ea944313d9853da8f4ec9881aefa5d6fe78caeaefbb0d103c8485a32f7c25e8b2cae193ea2233bb8 + languageName: node + linkType: hard + +"@aws-sdk/util-user-agent-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + bowser: ^2.11.0 + tslib: ^2.3.1 + checksum: 21349881a4069a09fb0f8c0f5a6d69e6659255008861817c5d9dada61bf032f0bd7d5735f01dbddbc310d228ea843fbec6ada9f83a4197909efd6ebadb364f6b + languageName: node + linkType: hard + +"@aws-sdk/util-user-agent-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.183.0" + dependencies: + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + peerDependencies: + aws-crt: ">=1.0.0" + peerDependenciesMeta: + aws-crt: + optional: true + checksum: 727d46842053f8f19789fee1550e235adff399559ef6c9b8dd0fe9edd7ac629a9b5c5849377553bfff37deba1ba9889d0c313f059f27cfc40a33895990c1f894 + languageName: node + linkType: hard + +"@aws-sdk/util-utf8-browser@npm:3.183.0, @aws-sdk/util-utf8-browser@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/util-utf8-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: f1c9cbafc3dcf5b04264c3708509117d5e6f6b373fb30712a0cd9d09966a2cdead0a91067a8e9513abac9b082971fd40519e421a2e046b3653ce1ede136197c2 + languageName: node + linkType: hard + +"@aws-sdk/util-utf8-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-utf8-node@npm:3.183.0" + dependencies: + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: c37f2bd388783c33c981afcd5a6a80481cc4e019f42bc5ab10ba2dfb039a4684acb4fa30df579cb3a5b509f61b1261870b30cd966c179029adb2a42672c0a871 + languageName: node + linkType: hard + "@azure/abort-controller@npm:^1.0.0": version: 1.0.2 resolution: "@azure/abort-controller@npm:1.0.2" @@ -373,7 +1133,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-auth@npm:^1.1.4, @azure/core-auth@npm:^1.4.0": +"@azure/core-auth@npm:^1.1.4, @azure/core-auth@npm:^1.3.0, @azure/core-auth@npm:^1.4.0": version: 1.4.0 resolution: "@azure/core-auth@npm:1.4.0" dependencies: @@ -383,32 +1143,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-auth@npm:^1.3.0": - version: 1.3.2 - resolution: "@azure/core-auth@npm:1.3.2" - dependencies: - "@azure/abort-controller": ^1.0.0 - tslib: ^2.2.0 - checksum: 8b27de6f8a82a63643524757ef774b1637b0d5c7769b387c73bebeb918717e7193ad1d2413638fb02b28de8199f261c1a902e3d04f75d1ef684af33529d9e98d - languageName: node - linkType: hard - -"@azure/core-client@npm:^1.4.0": - version: 1.5.0 - resolution: "@azure/core-client@npm:1.5.0" - dependencies: - "@azure/abort-controller": ^1.0.0 - "@azure/core-asynciterator-polyfill": ^1.0.0 - "@azure/core-auth": ^1.3.0 - "@azure/core-rest-pipeline": ^1.5.0 - "@azure/core-tracing": 1.0.0-preview.13 - "@azure/logger": ^1.0.0 - tslib: ^2.2.0 - checksum: dc51cdeae0788a14c57fed1b420e9d86d9b6cd29a1b7a3cecec5d8fad7664e4857415568cf4dd363fd3a845f0f4ee39904390d4f2e927206a8d50f87d66089a5 - languageName: node - linkType: hard - -"@azure/core-client@npm:^1.5.0": +"@azure/core-client@npm:^1.4.0, @azure/core-client@npm:^1.5.0": version: 1.6.1 resolution: "@azure/core-client@npm:1.6.1" dependencies: @@ -458,16 +1193,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-paging@npm:^1.1.1": - version: 1.1.3 - resolution: "@azure/core-paging@npm:1.1.3" - dependencies: - "@azure/core-asynciterator-polyfill": ^1.0.0 - checksum: 4864a6daaf0b30dbc59b0e9974d89a578f938ab2a1e1dce301efc89ff51d234fffbd3625b6caef7e3a02f04b2607abad587eb9f5bd2f84c9bdef68257c0ef63e - languageName: node - linkType: hard - -"@azure/core-paging@npm:^1.2.0": +"@azure/core-paging@npm:^1.1.1, @azure/core-paging@npm:^1.2.0": version: 1.3.0 resolution: "@azure/core-paging@npm:1.3.0" dependencies: @@ -476,24 +1202,7 @@ __metadata: languageName: node linkType: hard -"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.5.0": - version: 1.5.0 - resolution: "@azure/core-rest-pipeline@npm:1.5.0" - dependencies: - "@azure/abort-controller": ^1.0.0 - "@azure/core-auth": ^1.3.0 - "@azure/core-tracing": 1.0.0-preview.13 - "@azure/logger": ^1.0.0 - form-data: ^4.0.0 - http-proxy-agent: ^4.0.1 - https-proxy-agent: ^5.0.0 - tslib: ^2.2.0 - uuid: ^8.3.0 - checksum: 1503305db569f4d66353d7a93630c9f87995620312f9f05c262102e40c0f929e134aa221b2bf8f8b49f259fb0119c84a07a6a5ef2ead7f37d213b1c3f164f7fa - languageName: node - linkType: hard - -"@azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1": +"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1": version: 1.9.2 resolution: "@azure/core-rest-pipeline@npm:1.9.2" dependencies: @@ -652,7 +1361,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.18.6": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.18.6, @babel/code-frame@npm:^7.8.3": version: 7.18.6 resolution: "@babel/code-frame@npm:7.18.6" dependencies: @@ -661,44 +1370,14 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.8.3": - version: 7.16.7 - resolution: "@babel/code-frame@npm:7.16.7" - dependencies: - "@babel/highlight": ^7.16.7 - checksum: db2f7faa31bc2c9cf63197b481b30ea57147a5fc1a6fab60e5d6c02cdfbf6de8e17b5121f99917b3dabb5eeb572da078312e70697415940383efc140d4e0808b - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.16.4": - version: 7.16.8 - resolution: "@babel/compat-data@npm:7.16.8" - checksum: 10da2dac5ea9589c251412b00920889910e476c1ab24cd7095577635bc3a27c785151c89db4e26285fd39f509510ec29ab9d7e721f4fc16e4aec221cacde784b - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.17.7": - version: 7.17.7 - resolution: "@babel/compat-data@npm:7.17.7" - checksum: bf13476676884ce9afc199747ff82f3bcd6d42a9cfb01ce91bdb762b83ea11ec619b6ec532d1a80469ab14f191f33b5d4b9f8796fa8be3bc728d42b0c5e737e3 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.18.8": - version: 7.18.8 - resolution: "@babel/compat-data@npm:7.18.8" - checksum: 3096aafad74936477ebdd039bcf342fba84eb3100e608f3360850fb63e1efa1c66037c4824f814d62f439ab47d25164439343a6e92e9b4357024fdf571505eb9 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.19.1": +"@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.18.8, @babel/compat-data@npm:^7.19.1": version: 7.19.1 resolution: "@babel/compat-data@npm:7.19.1" checksum: f985887ea08a140e4af87a94d3fb17af0345491eb97f5a85b1840255c2e2a97429f32a8fd12a7aae9218af5f1024f1eb12a5cd280d2d69b2337583c17ea506ba languageName: node linkType: hard -"@babel/core@npm:^7.11.6": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.14.0, @babel/core@npm:^7.18.5": version: 7.19.1 resolution: "@babel/core@npm:7.19.1" dependencies: @@ -721,98 +1400,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.12.3": - version: 7.17.8 - resolution: "@babel/core@npm:7.17.8" - dependencies: - "@ampproject/remapping": ^2.1.0 - "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.17.7 - "@babel/helper-compilation-targets": ^7.17.7 - "@babel/helper-module-transforms": ^7.17.7 - "@babel/helpers": ^7.17.8 - "@babel/parser": ^7.17.8 - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.17.3 - "@babel/types": ^7.17.0 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.1.2 - semver: ^6.3.0 - checksum: 0e686b1be444d25494424065238931f2b3df908bf072b72bab973acfd6d27a481fc280c9cd8a3c6fe2c46beee50e0d2307468d8b15b64dc4036f025e75f6609d - languageName: node - linkType: hard - -"@babel/core@npm:^7.13.16, @babel/core@npm:^7.14.0": - version: 7.16.12 - resolution: "@babel/core@npm:7.16.12" - dependencies: - "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.16.8 - "@babel/helper-compilation-targets": ^7.16.7 - "@babel/helper-module-transforms": ^7.16.7 - "@babel/helpers": ^7.16.7 - "@babel/parser": ^7.16.12 - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.16.10 - "@babel/types": ^7.16.8 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.1.2 - semver: ^6.3.0 - source-map: ^0.5.0 - checksum: 29b56f3cb7c329fc038a2efaccf64ac3025835676b3d90f57f2265b6acd477a970114d09021b38d019ac8f20b2bb1596a9e79ce1f820d6b8cf0e4a802891817c - languageName: node - linkType: hard - -"@babel/core@npm:^7.18.5": - version: 7.18.9 - resolution: "@babel/core@npm:7.18.9" - dependencies: - "@ampproject/remapping": ^2.1.0 - "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.18.9 - "@babel/helper-compilation-targets": ^7.18.9 - "@babel/helper-module-transforms": ^7.18.9 - "@babel/helpers": ^7.18.9 - "@babel/parser": ^7.18.9 - "@babel/template": ^7.18.6 - "@babel/traverse": ^7.18.9 - "@babel/types": ^7.18.9 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.1 - semver: ^6.3.0 - checksum: 64b9088b03fdf659b334864ef93bed85d60c17b27fcbd72970f8eb9e0d3266ffa5a1926960f648f2db36b0bafec615f947ea5117d200599a0661b9f0a9cdf323 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.16.8, @babel/generator@npm:^7.7.2": - version: 7.16.8 - resolution: "@babel/generator@npm:7.16.8" - dependencies: - "@babel/types": ^7.16.8 - jsesc: ^2.5.1 - source-map: ^0.5.0 - checksum: 83af38b34735605c9d5f774c87a46c2cffaf666b28e9eeba883b2d7076412257e5c2264c26d9740ce44da6955fdaf857659391db02c012714a2a6dc19e403105 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.17.3, @babel/generator@npm:^7.17.7": - version: 7.17.7 - resolution: "@babel/generator@npm:7.17.7" - dependencies: - "@babel/types": ^7.17.0 - jsesc: ^2.5.1 - source-map: ^0.5.0 - checksum: e7344b9b4559115f2754ecc2ae9508412ea6a8f617544cd3d3f17cabc727bd30630765f96c8a4ebc8901ded1492a3a6c23d695a4f1e8f3042f860b30c891985c - languageName: node - linkType: hard - -"@babel/generator@npm:^7.18.13": +"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.19.0, @babel/generator@npm:^7.7.2": version: 7.19.3 resolution: "@babel/generator@npm:7.19.3" dependencies: @@ -823,38 +1411,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/generator@npm:7.18.9" - dependencies: - "@babel/types": ^7.18.9 - "@jridgewell/gen-mapping": ^0.3.2 - jsesc: ^2.5.1 - checksum: 1c271e0c6f33e59f7845d88a1b0b9b0dce88164e80dec9274a716efa54c260e405e9462b160843e73f45382bf5b24d8e160e0121207e480c29b30e2ed0eb16d4 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/generator@npm:7.19.0" - dependencies: - "@babel/types": ^7.19.0 - "@jridgewell/gen-mapping": ^0.3.2 - jsesc: ^2.5.1 - checksum: aa3d5785cf8f8e81672dcc61aef351188efeadb20d9f66d79113d82cbcf3bbbdeb829989fa14582108572ddbc4e4027bdceb06ccaf5ec40fa93c2dda8fbcd4aa - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.16.0, @babel/helper-annotate-as-pure@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-annotate-as-pure@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: d235be963fed5d48a8a4cfabc41c3f03fad6a947810dbcab9cebed7f819811457e10d99b4b2e942ad71baa7ee8e3cd3f5f38a4e4685639ddfddb7528d9a07179 - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.18.6": +"@babel/helper-annotate-as-pure@npm:^7.16.0, @babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" dependencies: @@ -873,49 +1430,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-compilation-targets@npm:7.16.7" - dependencies: - "@babel/compat-data": ^7.16.4 - "@babel/helper-validator-option": ^7.16.7 - browserslist: ^4.17.5 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 7238aaee78c011a42fb5ca92e5eff098752f7b314c2111d7bb9cdd58792fcab1b9c819b59f6a0851dc210dc09dc06b30d130a23982753e70eb3111bc65204842 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.17.7": - version: 7.17.7 - resolution: "@babel/helper-compilation-targets@npm:7.17.7" - dependencies: - "@babel/compat-data": ^7.17.7 - "@babel/helper-validator-option": ^7.16.7 - browserslist: ^4.17.5 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 24bf851539d5ec8e73779304b5d1ad5b0be09a74459ecc7d9baee9a0fa38ad016e9eaf4b5704504ae8da32f91ce0e31857bbbd9686854caeffd38f58226d3760 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helper-compilation-targets@npm:7.18.9" - dependencies: - "@babel/compat-data": ^7.18.8 - "@babel/helper-validator-option": ^7.18.6 - browserslist: ^4.20.2 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 2a9d71e124e098a9f45de4527ddd1982349d231827d341e00da9dfb967e260ecc7662c8b62abee4a010fb34d5f07a8d2155c974e0bc1928144cee5644910621d - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.19.1": +"@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-compilation-targets@npm:7.19.1" dependencies: @@ -929,23 +1444,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.16.7": - version: 7.16.10 - resolution: "@babel/helper-create-class-features-plugin@npm:7.16.10" - dependencies: - "@babel/helper-annotate-as-pure": ^7.16.7 - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-member-expression-to-functions": ^7.16.7 - "@babel/helper-optimise-call-expression": ^7.16.7 - "@babel/helper-replace-supers": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 2ab266aac7f94403311f63a17d32abb718ff040339bcae19880091de3fdb4e8d7196cb4e680f01a92924eb1a00a143364456e452c511c0b7b6e0b1a4b0e696da - languageName: node - linkType: hard - "@babel/helper-create-class-features-plugin@npm:^7.18.6": version: 7.18.9 resolution: "@babel/helper-create-class-features-plugin@npm:7.18.9" @@ -963,18 +1461,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.16.7" - dependencies: - "@babel/helper-annotate-as-pure": ^7.16.7 - regexpu-core: ^4.7.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: f6015e0b81deddcbf09fde6c39d3acd55aa3ad45cbf04dae5e2ce2432cd5a63c4a0fa67eaeaa13c6cc526e7618234b9d252c924a5c99a01e6ce8ae882d485f38 - languageName: node - linkType: hard - "@babel/helper-create-regexp-features-plugin@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.18.6" @@ -1005,15 +1491,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-environment-visitor@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: c03a10105d9ebd1fe632a77356b2e6e2f3c44edba9a93b0dc3591b6a66bd7a2e323dd9502f9ce96fc6401234abff1907aa877b6674f7826b61c953f7c8204bbe - languageName: node - linkType: hard - "@babel/helper-environment-visitor@npm:^7.18.6, @babel/helper-environment-visitor@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-environment-visitor@npm:7.18.9" @@ -1030,28 +1507,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-function-name@npm:7.16.7" - dependencies: - "@babel/helper-get-function-arity": ^7.16.7 - "@babel/template": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: fc77cbe7b10cfa2a262d7a37dca575c037f20419dfe0c5d9317f589599ca24beb5f5c1057748011159149eaec47fe32338c6c6412376fcded68200df470161e1 - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helper-function-name@npm:7.18.9" - dependencies: - "@babel/template": ^7.18.6 - "@babel/types": ^7.18.9 - checksum: d04c44e0272f887c0c868651be7fc3c5690531bea10936f00d4cca3f6d5db65e76dfb49e8d553c42ae1fe1eba61ccce9f3d93ba2df50a66408c8d4c3cc61cf0c - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.19.0": +"@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0": version: 7.19.0 resolution: "@babel/helper-function-name@npm:7.19.0" dependencies: @@ -1061,24 +1517,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-get-function-arity@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-get-function-arity@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: 25d969fb207ff2ad5f57a90d118f6c42d56a0171022e200aaa919ba7dc95ae7f92ec71cdea6c63ef3629a0dc962ab4c78e09ca2b437185ab44539193f796e0c3 - languageName: node - linkType: hard - -"@babel/helper-hoist-variables@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-hoist-variables@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: 6ae1641f4a751cd9045346e3f61c3d9ec1312fd779ab6d6fecfe2a96e59a481ad5d7e40d2a840894c13b3fd6114345b157f9e3062fc5f1580f284636e722de60 - languageName: node - linkType: hard - "@babel/helper-hoist-variables@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-hoist-variables@npm:7.18.6" @@ -1088,15 +1526,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-member-expression-to-functions@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: e275378022278a7e7974a3f65566690f1804ac88c5f4e848725cf936f61cd1e2557e88cfb6cb4fea92ae5a95ad89d78dbccc9a53715d4363f84c9fd109272c18 - languageName: node - linkType: hard - "@babel/helper-member-expression-to-functions@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-member-expression-to-functions@npm:7.18.9" @@ -1106,16 +1535,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-module-imports@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: ddd2c4a600a2e9a4fee192ab92bf35a627c5461dbab4af31b903d9ba4d6b6e59e0ff3499fde4e2e9a0eebe24906f00b636f8b4d9bd72ff24d50e6618215c3212 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.18.6": +"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-module-imports@npm:7.18.6" dependencies: @@ -1124,55 +1544,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-module-transforms@npm:7.16.7" - dependencies: - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-module-imports": ^7.16.7 - "@babel/helper-simple-access": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/helper-validator-identifier": ^7.16.7 - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: 6e930ce776c979f299cdbeaf80187f4ab086d75287b96ecc1c6896d392fcb561065f0d6219fc06fa79b4ceb4bbdc1a9847da8099aba9b077d0a9e583500fb673 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.17.7": - version: 7.17.7 - resolution: "@babel/helper-module-transforms@npm:7.17.7" - dependencies: - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-module-imports": ^7.16.7 - "@babel/helper-simple-access": ^7.17.7 - "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/helper-validator-identifier": ^7.16.7 - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.17.3 - "@babel/types": ^7.17.0 - checksum: 0b8f023aa7ff82dc4864349d54c4557865ad8ba54d78f6d78a86b05ca40f65c2d60acb4a54c5c309e7a4356beb9a89b876e54af4b3c4801ad25f62ec3721f0ae - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.18.6, @babel/helper-module-transforms@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helper-module-transforms@npm:7.18.9" - dependencies: - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-module-imports": ^7.18.6 - "@babel/helper-simple-access": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/helper-validator-identifier": ^7.18.6 - "@babel/template": ^7.18.6 - "@babel/traverse": ^7.18.9 - "@babel/types": ^7.18.9 - checksum: af08c60ea239ff3d40eda542fceaab69de17e713f131e80ead08c975ba7a47dd55d439cb48cfb14ae7ec96704a10c989ff5a5240e52a39101cb44a49467ce058 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.19.0": +"@babel/helper-module-transforms@npm:^7.18.6, @babel/helper-module-transforms@npm:^7.18.9, @babel/helper-module-transforms@npm:^7.19.0": version: 7.19.0 resolution: "@babel/helper-module-transforms@npm:7.19.0" dependencies: @@ -1188,15 +1560,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-optimise-call-expression@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: 925feb877d5a30a71db56e2be498b3abbd513831311c0188850896c4c1ada865eea795dce5251a1539b0f883ef82493f057f84286dd01abccc4736acfafe15ea - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" @@ -1206,14 +1569,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.13.0, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.16.7 - resolution: "@babel/helper-plugin-utils@npm:7.16.7" - checksum: d08dd86554a186c2538547cd537552e4029f704994a9201d41d82015c10ed7f58f9036e8d1527c3760f042409163269d308b0b3706589039c5f1884619c6d4ce - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.13.0, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.18.9 resolution: "@babel/helper-plugin-utils@npm:7.18.9" checksum: ebae876cd60f1fe238c7210986093845fa5c4cad5feeda843ea4d780bf068256717650376d3af2a5e760f2ed6a35c065ae144f99c47da3e54aa6cba99d8804e0 @@ -1234,19 +1590,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-replace-supers@npm:7.16.7" - dependencies: - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-member-expression-to-functions": ^7.16.7 - "@babel/helper-optimise-call-expression": ^7.16.7 - "@babel/traverse": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: e5c0b6eb3dad8410a6255f93b580dde9b3c1564646c6ef751de59d5b2a65b5caa80cc9e568155f04bbae895ad0f54305c2e833dbd971a4f641f970c90b3d892b - languageName: node - linkType: hard - "@babel/helper-replace-supers@npm:^7.18.6, @babel/helper-replace-supers@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-replace-supers@npm:7.18.9" @@ -1260,24 +1603,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-simple-access@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: 8d22c46c5ec2ead0686c4d5a3d1d12b5190c59be676bfe0d9d89df62b437b51d1a3df2ccfb8a77dded2e585176ebf12986accb6d45a18cff229eef3b10344f4b - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.17.7": - version: 7.17.7 - resolution: "@babel/helper-simple-access@npm:7.17.7" - dependencies: - "@babel/types": ^7.17.0 - checksum: 58a9bfd054720024f6ff47fbb113c96061dc2bd31a5e5285756bd3c2e83918c6926900e00150d0fb175d899494fe7d69bf2a8b278c32ef6f6bea8d032e6a3831 - languageName: node - linkType: hard - "@babel/helper-simple-access@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-simple-access@npm:7.18.6" @@ -1287,15 +1612,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.16.0": - version: 7.16.0 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.16.0" - dependencies: - "@babel/types": ^7.16.0 - checksum: b9ed2896eb253e6a85f472b0d4098ed80403758ad1a4e34b02b11e8276e3083297526758b1a3e6886e292987266f10622d7dbced3508cc22b296a74903b41cfb - languageName: node - linkType: hard - "@babel/helper-skip-transparent-expression-wrappers@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.18.9" @@ -1305,15 +1621,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-split-export-declaration@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: e10aaf135465c55114627951b79115f24bc7af72ecbb58d541d66daf1edaee5dde7cae3ec8c3639afaf74526c03ae3ce723444e3b5b3dc77140c456cd84bcaa1 - languageName: node - linkType: hard - "@babel/helper-split-export-declaration@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-split-export-declaration@npm:7.18.6" @@ -1330,28 +1637,14 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.16.7, @babel/helper-validator-identifier@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-validator-identifier@npm:7.18.6" - checksum: e295254d616bbe26e48c196a198476ab4d42a73b90478c9842536cf910ead887f5af6b5c4df544d3052a25ccb3614866fa808dc1e3a5a4291acd444e243c0648 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.19.1": +"@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-validator-identifier@npm:7.19.1" checksum: 0eca5e86a729162af569b46c6c41a63e18b43dbe09fda1d2a3c8924f7d617116af39cac5e4cd5d431bb760b4dca3c0970e0c444789b1db42bcf1fa41fbad0a3a languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-validator-option@npm:7.16.7" - checksum: c5ccc451911883cc9f12125d47be69434f28094475c1b9d2ada7c3452e6ac98a1ee8ddd364ca9e3f9855fcdee96cdeafa32543ebd9d17fee7a1062c202e80570 - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.18.6": +"@babel/helper-validator-option@npm:^7.16.7, @babel/helper-validator-option@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-validator-option@npm:7.18.6" checksum: f9cc6eb7cc5d759c5abf006402180f8d5e4251e9198197428a97e05d65eb2f8ae5a0ce73b1dfd2d35af41d0eb780627a64edf98a4e71f064eeeacef8de58f2cf @@ -1370,39 +1663,6 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helpers@npm:7.16.7" - dependencies: - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: 75504c76b66a29b91f954fcc0867dfe275a4cfba5b44df6d64405df74ea72f967fccfa63d62c31c423c5502d113290000c581e0e4858a214f0303d7ecf55c29f - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.17.8": - version: 7.17.8 - resolution: "@babel/helpers@npm:7.17.8" - dependencies: - "@babel/template": ^7.16.7 - "@babel/traverse": ^7.17.3 - "@babel/types": ^7.17.0 - checksum: 463dad58119fefebf2d0201bfa53ec9607aa00356908895640fc07589747fb3c2e0dfee4019f3e8c9781e57c9aa5dff4c72ec8d1b031c4ed8349f90b6aefe99d - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helpers@npm:7.18.9" - dependencies: - "@babel/template": ^7.18.6 - "@babel/traverse": ^7.18.9 - "@babel/types": ^7.18.9 - checksum: d0bd8255d36bfc65dc52ce75f7fea778c70287da2d64981db4c84fbdf9581409ecbd6433deff1c81da3a5acf26d7e4c364b3a4445efacf88f4f48e77c5b34d8d - languageName: node - linkType: hard - "@babel/helpers@npm:^7.19.0": version: 7.19.0 resolution: "@babel/helpers@npm:7.19.0" @@ -1414,18 +1674,7 @@ __metadata: languageName: node linkType: hard -"@babel/highlight@npm:^7.0.0": - version: 7.16.10 - resolution: "@babel/highlight@npm:7.16.10" - dependencies: - "@babel/helper-validator-identifier": ^7.16.7 - chalk: ^2.0.0 - js-tokens: ^4.0.0 - checksum: 1f1bdd752a90844f4efc22166a46303fb651ba0fd75a06daba3ebae2575ab3edc1da9827c279872a3aaf305f50a18473c5fa1966752726a2b253065fd4c0745e - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.16.7, @babel/highlight@npm:^7.18.6": +"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" dependencies: @@ -1436,16 +1685,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.10, @babel/parser@npm:^7.16.12, @babel/parser@npm:^7.16.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.17.3, @babel/parser@npm:^7.17.8": - version: 7.17.9 - resolution: "@babel/parser@npm:7.17.9" - bin: - parser: ./bin/babel-parser.js - checksum: ea59c985ebfae7c0299c8ea63ed34903202f51665db8d59c55b4366e20270b74d7367a2c211fdd2db20f25750df89adcc85ab6c8692061c6459a88efb79f43e6 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.18.10, @babel/parser@npm:^7.19.1": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.18.10, @babel/parser@npm:^7.19.1, @babel/parser@npm:^7.9.4": version: 7.19.1 resolution: "@babel/parser@npm:7.19.1" bin: @@ -1454,24 +1694,6 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.18.6, @babel/parser@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/parser@npm:7.18.9" - bin: - parser: ./bin/babel-parser.js - checksum: 81a966b334e3ef397e883c64026265a5ae0ad435a86f52a84f60a5ee1efc0738c1f42c55e0dc5f191cc6a83ba0c61350433eee417bf1dff160ca5f3cfde244c6 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.9.4": - version: 7.18.13 - resolution: "@babel/parser@npm:7.18.13" - bin: - parser: ./bin/babel-parser.js - checksum: 8b41c35607668495d67d9a7c5f61768aaab26acf887efdadc2781aed54046981480ef40aeda0b84d61aed02cf0c4ff4b028d5f83ab85e17e2ddff318f9243b8b - languageName: node - linkType: hard - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" @@ -1510,19 +1732,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.0.0, @babel/plugin-proposal-class-properties@npm:^7.13.0": - version: 7.16.7 - resolution: "@babel/plugin-proposal-class-properties@npm:7.16.7" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3977e841e17b45b47be749b9a5b67b9e8b25ff0840f9fdad3f00cbcb35db4f5ff15f074939fe19b01207a29688c432cc2c682351959350834d62920b7881f803 - languageName: node - linkType: hard - -"@babel/plugin-proposal-class-properties@npm:^7.18.6": +"@babel/plugin-proposal-class-properties@npm:^7.0.0, @babel/plugin-proposal-class-properties@npm:^7.13.0, @babel/plugin-proposal-class-properties@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" dependencies: @@ -1595,19 +1805,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.13.8": - version: 7.16.7 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bfafc2701697b5c763dbbb65dd97b56979bfb0922e35be27733699a837aeff22316313ddfdd0fb45129efa3f86617219b77110d05338bc4dca4385d8ce83dd19 - languageName: node - linkType: hard - -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.13.8, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" dependencies: @@ -1631,22 +1829,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-object-rest-spread@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.16.7" - dependencies: - "@babel/compat-data": ^7.16.4 - "@babel/helper-compilation-targets": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2d3740e4df6d3f51d57862100c45c000104571aa98b7f798fdfc05ae0c12b9e7cc9b55f4a28612d626e29f3369a1481a0ee8a0241b23508b9d3da00c55f99d41 - languageName: node - linkType: hard - -"@babel/plugin-proposal-object-rest-spread@npm:^7.18.9": +"@babel/plugin-proposal-object-rest-spread@npm:^7.0.0, @babel/plugin-proposal-object-rest-spread@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.18.9" dependencies: @@ -1673,20 +1856,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-optional-chaining@npm:^7.13.12": - version: 7.16.7 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-skip-transparent-expression-wrappers": ^7.16.0 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: e4a6c1ac7e6817b92a673ea52ab0b7dc1fb39d29fb0820cd414e10ae2cd132bd186b4238dcca881a29fc38fe9d38ed24fc111ba22ca20086481682d343f4f130 - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-chaining@npm:^7.18.9": +"@babel/plugin-proposal-optional-chaining@npm:^7.13.12, @babel/plugin-proposal-optional-chaining@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-proposal-optional-chaining@npm:7.18.9" dependencies: @@ -1725,7 +1895,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-unicode-property-regex@npm:^7.18.6": +"@babel/plugin-proposal-unicode-property-regex@npm:^7.18.6, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": version: 7.18.6 resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" dependencies: @@ -1737,18 +1907,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": - version: 7.16.7 - resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.16.7" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2b8a33713d456183f0b7d011011e7bd932c08cc06216399a7b2015ab39284b511993dc10a89bbb15d1d728e6a2ef42ca08c3202619aa148cbd48052422ea3995 - languageName: node - linkType: hard - "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -1859,18 +2017,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/plugin-syntax-jsx@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: cd9b0e53c50e8ddb0afaf0f42e0b221a94e4f59aee32a591364266a31195c48cac5fef288d02c1c935686bda982d2e0f1ed61cceb995fc9f6fb09ef5ebecdd2b - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2": +"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.18.6 resolution: "@babel/plugin-syntax-jsx@npm:7.18.6" dependencies: @@ -1969,18 +2116,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.16.7, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.16.7 - resolution: "@babel/plugin-syntax-typescript@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 661e636060609ede9a402e22603b01784c21fabb0a637e65f561c8159351fe0130bbc11fdefe31902107885e3332fc34d95eb652ac61d3f61f2d61f5da20609e - languageName: node - linkType: hard - -"@babel/plugin-syntax-typescript@npm:^7.18.6": +"@babel/plugin-syntax-typescript@npm:^7.18.6, @babel/plugin-syntax-typescript@npm:^7.7.2": version: 7.18.6 resolution: "@babel/plugin-syntax-typescript@npm:7.18.6" dependencies: @@ -1991,18 +2127,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2a6aa982c6fc80f4de7ccd973507ce5464fab129987cb6661136a7b9b6a020c2b329b912cbc46a68d39b5a18451ba833dcc8d1ca8d615597fec98624ac2add54 - languageName: node - linkType: hard - -"@babel/plugin-transform-arrow-functions@npm:^7.18.6": +"@babel/plugin-transform-arrow-functions@npm:^7.0.0, @babel/plugin-transform-arrow-functions@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-arrow-functions@npm:7.18.6" dependencies: @@ -2026,18 +2151,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 591e9f75437bb32ebf9506d28d5c9659c66c0e8e0c19b12924d808d898e68309050aadb783ccd70bb4956555067326ecfa17a402bc77eb3ece3c6863d40b9016 - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoped-functions@npm:^7.18.6": +"@babel/plugin-transform-block-scoped-functions@npm:^7.0.0, @babel/plugin-transform-block-scoped-functions@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.18.6" dependencies: @@ -2048,18 +2162,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-block-scoping@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f93b5441af573fc274655f1707aeb4f67a43e926b58f56d89cc35a27877ae0bf198648603cbc19f442579489138f93c3838905895f109aa356996dbc3ed97a68 - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoping@npm:^7.18.9": +"@babel/plugin-transform-block-scoping@npm:^7.0.0, @babel/plugin-transform-block-scoping@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-block-scoping@npm:7.18.9" dependencies: @@ -2070,25 +2173,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-classes@npm:7.16.7" - dependencies: - "@babel/helper-annotate-as-pure": ^7.16.7 - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-optimise-call-expression": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-replace-supers": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - globals: ^11.1.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 791526a1bf3c4659b94d619536e3181d3ad54887d50539066628c6e695789a3bb264dc1fbc8540169d62a222f623df54defb490c1811ae63bad1e3557d6b3bb0 - languageName: node - linkType: hard - -"@babel/plugin-transform-classes@npm:^7.18.9": +"@babel/plugin-transform-classes@npm:^7.0.0, @babel/plugin-transform-classes@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-classes@npm:7.18.9" dependencies: @@ -2106,18 +2191,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-computed-properties@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 28b17f7cfe643f45920b76dc040cab40d4e54eccf5074fba2658c484feacda9b4885b3854ffaf26292189783fdecc97211519c61831b6708fcbf739cfbcbf31c - languageName: node - linkType: hard - -"@babel/plugin-transform-computed-properties@npm:^7.18.9": +"@babel/plugin-transform-computed-properties@npm:^7.0.0, @babel/plugin-transform-computed-properties@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-computed-properties@npm:7.18.9" dependencies: @@ -2128,18 +2202,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-destructuring@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d1c2e15e7be2a7c57ac8ec4df06fbb706c7ecc872ab7bc2193606e6d6a01929b6d5a1bb41540e41180e42a5ce0e70dce22e7896cb6578dd581d554f77780971b - languageName: node - linkType: hard - -"@babel/plugin-transform-destructuring@npm:^7.18.9": +"@babel/plugin-transform-destructuring@npm:^7.0.0, @babel/plugin-transform-destructuring@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-destructuring@npm:7.18.9" dependencies: @@ -2150,7 +2213,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.18.6": +"@babel/plugin-transform-dotall-regex@npm:^7.18.6, @babel/plugin-transform-dotall-regex@npm:^7.4.4": version: 7.18.6 resolution: "@babel/plugin-transform-dotall-regex@npm:7.18.6" dependencies: @@ -2162,18 +2225,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.4.4": - version: 7.16.7 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.16.7" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 554570dddfd5bfd87ab307be520f69a3d4ed2d2db677c165971b400d4c96656d0c165b318e69f1735612dcd12e04c0ee257697dc26800e8a572ca73bc05fa0f4 - languageName: node - linkType: hard - "@babel/plugin-transform-duplicate-keys@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-duplicate-keys@npm:7.18.9" @@ -2209,18 +2260,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-for-of@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 35c9264ee4bef814818123d70afe8b2f0a85753a0a9dc7b73f93a71cadc5d7de852f1a3e300a7c69a491705805704611de1e2ccceb5686f7828d6bca2e5a7306 - languageName: node - linkType: hard - -"@babel/plugin-transform-for-of@npm:^7.18.8": +"@babel/plugin-transform-for-of@npm:^7.0.0, @babel/plugin-transform-for-of@npm:^7.18.8": version: 7.18.8 resolution: "@babel/plugin-transform-for-of@npm:7.18.8" dependencies: @@ -2231,20 +2271,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-function-name@npm:7.16.7" - dependencies: - "@babel/helper-compilation-targets": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4d97d0b84461cdd5d5aa2d010cdaf30f1f83a92a0dedd3686cbc7e90dc1249a70246f5bac0c1f3cd3f1dbfb03f7aac437776525a0c90cafd459776ea4fcc6bde - languageName: node - linkType: hard - -"@babel/plugin-transform-function-name@npm:^7.18.9": +"@babel/plugin-transform-function-name@npm:^7.0.0, @babel/plugin-transform-function-name@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-function-name@npm:7.18.9" dependencies: @@ -2257,18 +2284,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-literals@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a9565d999fc7a72a391ef843cf66028c38ca858537c7014d9ea8ea587a59e5f952d9754bdcca6ca0446e84653e297d417d4faedccb9e4221af1aa30f25d918e0 - languageName: node - linkType: hard - -"@babel/plugin-transform-literals@npm:^7.18.9": +"@babel/plugin-transform-literals@npm:^7.0.0, @babel/plugin-transform-literals@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-literals@npm:7.18.9" dependencies: @@ -2279,18 +2295,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: fdf5b22abab2b770e69348ce7f99796c3e0e1e7ce266afdbe995924284704930fa989323bdbda7070db8adb45a72f39eaa1dbebf18b67fc44035ec00c6ae3300 - languageName: node - linkType: hard - -"@babel/plugin-transform-member-expression-literals@npm:^7.18.6": +"@babel/plugin-transform-member-expression-literals@npm:^7.0.0, @babel/plugin-transform-member-expression-literals@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.18.6" dependencies: @@ -2314,21 +2319,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.0.0, @babel/plugin-transform-modules-commonjs@npm:^7.13.8": - version: 7.16.8 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.16.8" - dependencies: - "@babel/helper-module-transforms": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-simple-access": ^7.16.7 - babel-plugin-dynamic-import-node: ^2.3.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c0ac00f5457e12cac7825b14725b6fc787bef78945181469ff79f07ef0fd7df021cb00fe1d3a9f35fc9bc92ae59e6e3fc9075a70b627dfe10e00d0907892aace - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-commonjs@npm:^7.18.6": +"@babel/plugin-transform-modules-commonjs@npm:^7.0.0, @babel/plugin-transform-modules-commonjs@npm:^7.13.8, @babel/plugin-transform-modules-commonjs@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-modules-commonjs@npm:7.18.6" dependencies: @@ -2392,19 +2383,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-object-super@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-replace-supers": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 46e3c879f4a93e904f2ecf83233d40c48c832bdbd82a67cab1f432db9aa51702e40d9e51e5800613e12299974f90f4ed3869e1273dbca8642984266320c5f341 - languageName: node - linkType: hard - -"@babel/plugin-transform-object-super@npm:^7.18.6": +"@babel/plugin-transform-object-super@npm:^7.0.0, @babel/plugin-transform-object-super@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-object-super@npm:7.18.6" dependencies: @@ -2416,18 +2395,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.0.0, @babel/plugin-transform-parameters@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/plugin-transform-parameters@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4d6904376db82d0b35f0a6cce08f630daf8608d94e903d6c7aff5bd742b251651bd1f88cdf9f16cad98aba5fc7c61da8635199364865fad6367d5ae37cf56cc1 - languageName: node - linkType: hard - -"@babel/plugin-transform-parameters@npm:^7.18.8": +"@babel/plugin-transform-parameters@npm:^7.0.0, @babel/plugin-transform-parameters@npm:^7.18.8": version: 7.18.8 resolution: "@babel/plugin-transform-parameters@npm:7.18.8" dependencies: @@ -2438,18 +2406,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-property-literals@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b5674458991a9b0e8738989d70faa88c7f98ed3df923c119f1225069eed72fe5e0ce947b1adc91e378f5822fbdeb7a672f496fd1c75c4babcc88169e3a7c3229 - languageName: node - linkType: hard - -"@babel/plugin-transform-property-literals@npm:^7.18.6": +"@babel/plugin-transform-property-literals@npm:^7.0.0, @babel/plugin-transform-property-literals@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-property-literals@npm:7.18.6" dependencies: @@ -2471,18 +2428,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-react-display-name@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 483154413671ab0a25ae37520b7cf5bfab0958c484a3707c6799b1f1436d1e51481bcc03fbfcdbf90bf6b46818d931ae35e515141d8354c3287351b4467376ba - languageName: node - linkType: hard - -"@babel/plugin-transform-react-display-name@npm:^7.18.6": +"@babel/plugin-transform-react-display-name@npm:^7.0.0, @babel/plugin-transform-react-display-name@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-react-display-name@npm:7.18.6" dependencies: @@ -2504,22 +2450,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-react-jsx@npm:7.16.7" - dependencies: - "@babel/helper-annotate-as-pure": ^7.16.7 - "@babel/helper-module-imports": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/plugin-syntax-jsx": ^7.16.7 - "@babel/types": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 0e82346d7c99b4467946d535a8c626a988e5670f65a15dee8520ce9cf4f0147c99decc1cbb4bd352083eaafd259ee3e4299854cac6304a83666d488edf4e58f6 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx@npm:^7.18.6": +"@babel/plugin-transform-react-jsx@npm:^7.0.0, @babel/plugin-transform-react-jsx@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-react-jsx@npm:7.18.6" dependencies: @@ -2569,18 +2500,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: ca381ecf8f48696512172deca40af46b1f64e3497186fdc2c9009286d8f06b468c4d61cdc392dc8b0c165298117dda67be9e2ff0e99d7691b0503f1240d4c62b - languageName: node - linkType: hard - -"@babel/plugin-transform-shorthand-properties@npm:^7.18.6": +"@babel/plugin-transform-shorthand-properties@npm:^7.0.0, @babel/plugin-transform-shorthand-properties@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.18.6" dependencies: @@ -2591,19 +2511,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-spread@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-skip-transparent-expression-wrappers": ^7.16.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 6e961af1a70586bb72dd85e8296cee857c5dadd73225fccd0fe261c0d98652a82d69c65f3e9dc31ce019a12e9677262678479b96bd2d9140ddf6514618362828 - languageName: node - linkType: hard - -"@babel/plugin-transform-spread@npm:^7.18.9": +"@babel/plugin-transform-spread@npm:^7.0.0, @babel/plugin-transform-spread@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-spread@npm:7.18.9" dependencies: @@ -2626,18 +2534,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.0.0": - version: 7.16.7 - resolution: "@babel/plugin-transform-template-literals@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b55a519dd8b957247ebad3cab21918af5adca4f6e6c87819501cfe3d4d4bccda25bc296c7dfc8a30909b4ad905902aeb9d55ad955cb9f5cbc74b42dab32baa18 - languageName: node - linkType: hard - -"@babel/plugin-transform-template-literals@npm:^7.18.9": +"@babel/plugin-transform-template-literals@npm:^7.0.0, @babel/plugin-transform-template-literals@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-template-literals@npm:7.18.9" dependencies: @@ -2659,19 +2556,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.16.7": - version: 7.16.8 - resolution: "@babel/plugin-transform-typescript@npm:7.16.8" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.16.7 - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/plugin-syntax-typescript": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a76d0afcbd550208cf2e7cdedb4f2d3ca3fa287640a4858a5ee0a28270b784d7d20d5a51b5997dc84514e066a5ebef9e0a0f74ed9fffae09e73984786dd08036 - languageName: node - linkType: hard - "@babel/plugin-transform-typescript@npm:^7.18.6": version: 7.18.8 resolution: "@babel/plugin-transform-typescript@npm:7.18.8" @@ -2837,20 +2721,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.13.0": - version: 7.16.7 - resolution: "@babel/preset-typescript@npm:7.16.7" - dependencies: - "@babel/helper-plugin-utils": ^7.16.7 - "@babel/helper-validator-option": ^7.16.7 - "@babel/plugin-transform-typescript": ^7.16.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 44e2f3fa302befe0dc50a01b79e5aa8c27a9c7047c46df665beae97201173030646ddf7c83d7d3ed3724fc38151745b11693e7b4502c81c4cd67781ff5677da5 - languageName: node - linkType: hard - -"@babel/preset-typescript@npm:^7.17.12": +"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.17.12": version: 7.18.6 resolution: "@babel/preset-typescript@npm:7.18.6" dependencies: @@ -2878,17 +2749,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime-corejs3@npm:^7.10.2, @babel/runtime-corejs3@npm:^7.11.2": - version: 7.17.2 - resolution: "@babel/runtime-corejs3@npm:7.17.2" - dependencies: - core-js-pure: ^3.20.2 - regenerator-runtime: ^0.13.4 - checksum: fc7ba261913c66347434051c74b00f320fb5fda7c72f4a4378045b39e31a39420bba2b2cf3fd59367834b43689215b12cb0587a599c95e9619562e1ebec071a7 - languageName: node - linkType: hard - -"@babel/runtime-corejs3@npm:^7.18.9": +"@babel/runtime-corejs3@npm:^7.10.2, @babel/runtime-corejs3@npm:^7.11.2, @babel/runtime-corejs3@npm:^7.18.9": version: 7.18.9 resolution: "@babel/runtime-corejs3@npm:7.18.9" dependencies: @@ -2898,16 +2759,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.17.7 - resolution: "@babel/runtime@npm:7.17.7" - dependencies: - regenerator-runtime: ^0.13.4 - checksum: d9ec9e2c5ebbf503ac865ebd70d0216443d0fa8380bab572aa44ccf8fafde8b8b9846badfdbba3572f79075c9a196845aa3f42a435fd34ec832acd2bc1467d37 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.18.9": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.18.9 resolution: "@babel/runtime@npm:7.18.9" dependencies: @@ -2916,27 +2768,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/runtime@npm:7.18.6" - dependencies: - regenerator-runtime: ^0.13.4 - checksum: 8b707b64ae0524db617d0c49933b258b96376a38307dc0be8fb42db5697608bcc1eba459acce541e376cff5ed5c5287d24db5780bd776b7c75ba2c2e26ff8a2c - languageName: node - linkType: hard - -"@babel/template@npm:^7.16.7, @babel/template@npm:^7.3.3": - version: 7.16.7 - resolution: "@babel/template@npm:7.16.7" - dependencies: - "@babel/code-frame": ^7.16.7 - "@babel/parser": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: 10cd112e89276e00f8b11b55a51c8b2f1262c318283a980f4d6cdb0286dc05734b9aaeeb9f3ad3311900b09bc913e02343fcaa9d4a4f413964aaab04eb84ac4a - languageName: node - linkType: hard - -"@babel/template@npm:^7.18.10": +"@babel/template@npm:^7.18.10, @babel/template@npm:^7.18.6, @babel/template@npm:^7.3.3": version: 7.18.10 resolution: "@babel/template@npm:7.18.10" dependencies: @@ -2947,72 +2779,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/template@npm:7.18.6" - dependencies: - "@babel/code-frame": ^7.18.6 - "@babel/parser": ^7.18.6 - "@babel/types": ^7.18.6 - checksum: cb02ed804b7b1938dbecef4e01562013b80681843dd391933315b3dd9880820def3b5b1bff6320d6e4c6a1d63d1d5799630d658ec6b0369c5505e7e4029c38fb - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.10, @babel/traverse@npm:^7.16.7, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": - version: 7.16.10 - resolution: "@babel/traverse@npm:7.16.10" - dependencies: - "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.16.8 - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-hoist-variables": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/parser": ^7.16.10 - "@babel/types": ^7.16.8 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 58f52314f8a02157cd3004712e703e6b22dff57cee4bc1ab1954c511c6f885fd7763ea68d2d5f006891bc7b77b1f2e9c8c7cb0354f580c8343d5559ed971d087 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.17.3": - version: 7.17.3 - resolution: "@babel/traverse@npm:7.17.3" - dependencies: - "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.17.3 - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-hoist-variables": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/parser": ^7.17.3 - "@babel/types": ^7.17.0 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 780d7ecf711758174989794891af08d378f81febdb8932056c0d9979524bf0298e28f8e7708a872d7781151506c28f56c85c63ea3f1f654662c2fcb8a3eb9fdc - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/traverse@npm:7.18.9" - dependencies: - "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.18.9 - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.18.9 - "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.18.9 - "@babel/types": ^7.18.9 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 0445a51952ea1664a5719d9b1f8bf04be6f1933bcf54915fecc544c844a5dad2ac56f3b555723bbf741ef680d7fd64f6a5d69cfd08d518a4089c79a734270162 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.19.0, @babel/traverse@npm:^7.19.1": +"@babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.19.0, @babel/traverse@npm:^7.19.1, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": version: 7.19.1 resolution: "@babel/traverse@npm:7.19.1" dependencies: @@ -3030,38 +2797,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.16.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.16.8, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.16.8 - resolution: "@babel/types@npm:7.16.8" - dependencies: - "@babel/helper-validator-identifier": ^7.16.7 - to-fast-properties: ^2.0.0 - checksum: 4f6a187b2924df70e21d6e6c0822f91b1b936fe060bc92bb477b93bd8a712c88fe41a73f85c0ec53b033353374fe33e773b04ffc340ad36afd8f647dd05c4ee1 - languageName: node - linkType: hard - -"@babel/types@npm:^7.17.0": - version: 7.17.0 - resolution: "@babel/types@npm:7.17.0" - dependencies: - "@babel/helper-validator-identifier": ^7.16.7 - to-fast-properties: ^2.0.0 - checksum: 12e5a287986fe557188e87b2c5202223f1dc83d9239a196ab936fdb9f8c1eb0be717ff19f934b5fad4e29a75586d5798f74bed209bccea1c20376b9952056f0e - languageName: node - linkType: hard - -"@babel/types@npm:^7.18.10, @babel/types@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/types@npm:7.19.0" - dependencies: - "@babel/helper-string-parser": ^7.18.10 - "@babel/helper-validator-identifier": ^7.18.6 - to-fast-properties: ^2.0.0 - checksum: 9b346715a68aeede70ba9c685a144b0b26c53bcd595d448e24c8fa8df4d5956a5712e56ebadb7c85dcc32f218ee42788e37b93d50d3295c992072224cb3ef3fe - languageName: node - linkType: hard - -"@babel/types@npm:^7.18.13, @babel/types@npm:^7.19.3": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.10, @babel/types@npm:^7.18.13, @babel/types@npm:^7.18.4, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.19.0, @babel/types@npm:^7.19.3, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.19.3 resolution: "@babel/types@npm:7.19.3" dependencies: @@ -3072,27 +2808,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.18.4, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/types@npm:7.18.9" - dependencies: - "@babel/helper-validator-identifier": ^7.18.6 - to-fast-properties: ^2.0.0 - checksum: f0e0147267895fd8a5b82133e711ce7ce99941f3ce63647e0e3b00656a7afe48a8aa48edbae27543b701794d2b29a562a08f51f88f41df401abce7c3acc5e13a - languageName: node - linkType: hard - -"@babel/types@npm:^7.8.3": - version: 7.18.13 - resolution: "@babel/types@npm:7.18.13" - dependencies: - "@babel/helper-string-parser": ^7.18.10 - "@babel/helper-validator-identifier": ^7.18.6 - to-fast-properties: ^2.0.0 - checksum: abc3ad1f3b6864df0ea0e778bcdf7d2c5ee2293811192962d50e8a8c05c1aeec90a48275f53b2a45aad882ed8bef9477ae1f8e70ac1d44d039e14930d1388dcc - languageName: node - linkType: hard - "@backstage/app-defaults@workspace:^, @backstage/app-defaults@workspace:packages/app-defaults": version: 0.0.0-use.local resolution: "@backstage/app-defaults@workspace:packages/app-defaults" @@ -3147,8 +2862,9 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/types": "workspace:^" "@google-cloud/storage": ^6.0.0 - "@keyv/redis": ^2.2.3 - "@kubernetes/client-node": ^0.17.0 + "@keyv/memcache": ^1.3.5 + "@keyv/redis": ^2.5.3 + "@kubernetes/client-node": 0.17.0 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 "@types/archiver": ^5.1.0 @@ -3188,8 +2904,7 @@ __metadata: http-errors: ^2.0.0 isomorphic-git: ^1.8.0 jose: ^4.6.0 - keyv: ^4.0.3 - keyv-memcache: ^1.2.5 + keyv: ^4.5.2 knex: ^2.0.0 lodash: ^4.17.21 logform: ^2.3.2 @@ -3198,7 +2913,7 @@ __metadata: minimist: ^1.2.5 mock-fs: ^5.1.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 mysql2: ^2.2.5 node-abort-controller: ^3.0.1 node-fetch: ^2.6.7 @@ -3209,7 +2924,7 @@ __metadata: selfsigned: ^2.0.0 stoppable: ^1.1.0 supertest: ^6.1.3 - tar: ^6.1.2 + tar: ^6.1.12 uuid: ^8.3.2 winston: ^3.2.1 yauzl: ^2.10.0 @@ -3283,7 +2998,7 @@ __metadata: "@backstage/config": "workspace:^" better-sqlite3: ^7.5.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 mysql2: ^2.2.5 pg: ^8.3.0 testcontainers: ^8.1.2 @@ -3291,17 +3006,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@npm:^1.1.1": - version: 1.1.1 - resolution: "@backstage/catalog-client@npm:1.1.1" - dependencies: - "@backstage/catalog-model": ^1.1.2 - "@backstage/errors": ^1.1.2 - cross-fetch: ^3.1.5 - checksum: 788c357e5a783ce46e4dcd805b302ffe2b407ad9bb04e49ee6b6aa8fb42adfd9cae8a57e2d18cd4c81ef22011990a5eb6518f3f44fb812485d7c99226db26e1d - languageName: node - linkType: hard - "@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" @@ -3310,26 +3014,11 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft -"@backstage/catalog-model@npm:^1.1.2": - version: 1.1.2 - resolution: "@backstage/catalog-model@npm:1.1.2" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/errors": ^1.1.2 - "@backstage/types": ^1.0.0 - ajv: ^8.10.0 - json-schema: ^0.4.0 - lodash: ^4.17.21 - uuid: ^8.0.0 - checksum: d53e5db9f1662b6c2bd48b3b1fed97751b5bf8805575feb12ed2b6f600048d676f954fe4cfa214536d09f984535f0524a24c6330e08c4d255064d0eb62678bc1 - languageName: node - linkType: hard - -"@backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.2, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3422,7 +3111,7 @@ __metadata: css-loader: ^6.5.1 del: ^6.0.0 diff: ^5.0.0 - esbuild: ^0.14.10 + esbuild: ^0.15.0 esbuild-loader: ^2.18.0 eslint: ^8.6.0 eslint-config-prettier: ^8.3.0 @@ -3452,7 +3141,7 @@ __metadata: mini-css-extract-plugin: ^2.4.2 minimatch: 5.1.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 node-libs-browser: ^2.2.1 nodemon: ^2.0.2 @@ -3474,7 +3163,7 @@ __metadata: style-loader: ^3.3.1 sucrase: ^3.20.2 swc-loader: ^0.2.3 - tar: ^6.1.2 + tar: ^6.1.12 terser-webpack-plugin: ^5.1.3 ts-node: ^10.0.0 type-fest: ^2.0.0 @@ -3506,7 +3195,7 @@ __metadata: "@types/node": ^16.11.26 chalk: ^4.0.0 commander: ^9.1.0 - jscodeshift: ^0.13.0 + jscodeshift: ^0.14.0 jscodeshift-add-imports: ^1.0.10 ts-node: ^10.0.0 bin: @@ -3535,7 +3224,7 @@ __metadata: json-schema-merge-allof: ^0.8.1 json-schema-traverse: ^1.0.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 typescript-json-schema: ^0.54.0 yaml: ^2.0.0 @@ -3543,17 +3232,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@npm:^1.0.3": - version: 1.0.3 - resolution: "@backstage/config@npm:1.0.3" - dependencies: - "@backstage/types": ^1.0.0 - lodash: ^4.17.21 - checksum: 1026f741ac019043f46965eeb93c796110b7b98add181562a975e3ef9bf27332ea7841cd174a358a55c1edced892fc8b644263caf14f6c6d244b550a1176e1ad - languageName: node - linkType: hard - -"@backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.0.3, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -3583,14 +3262,14 @@ __metadata: "@types/prop-types": ^15.7.3 "@types/zen-observable": ^0.8.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 react-router-beta: "npm:react-router@6.0.0-beta.0" react-router-dom-beta: "npm:react-router-dom@6.0.0-beta.0" react-router-dom-stable: "npm:react-router-dom@^6.3.0" react-router-stable: "npm:react-router@^6.3.0" react-use: ^17.2.4 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 zod: ^3.11.6 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -3696,7 +3375,7 @@ __metadata: history: ^5.0.0 immer: ^9.0.1 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 pluralize: ^8.0.0 prop-types: ^15.7.2 qs: ^6.9.4 @@ -3711,7 +3390,7 @@ __metadata: react-virtualized-auto-sizer: ^1.0.6 react-window: ^1.8.6 remark-gfm: ^3.0.1 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 zod: ^3.11.6 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -3722,25 +3401,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@npm:^1.0.7": - version: 1.0.7 - resolution: "@backstage/core-plugin-api@npm:1.0.7" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/types": ^1.0.0 - "@backstage/version-bridge": ^1.0.1 - history: ^5.0.0 - prop-types: ^15.7.2 - zen-observable: ^0.8.15 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: ce07e5ec1f4f21a5e879e3ab2eb271721cc0eadd685a7457098afca1d8106140883fbc7c3cf7b436c594614152a88fcba7466df0900d9fa8e958baab2f8b1a6a - languageName: node - linkType: hard - -"@backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.0.7, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -3759,9 +3420,9 @@ __metadata: "@types/zen-observable": ^0.8.0 cross-fetch: ^3.1.5 history: ^5.0.0 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -3816,7 +3477,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.0.0 react-use: ^17.2.4 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -3826,18 +3487,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@npm:^1.1.2": - version: 1.1.2 - resolution: "@backstage/errors@npm:1.1.2" - dependencies: - "@backstage/types": ^1.0.0 - cross-fetch: ^3.1.5 - serialize-error: ^8.0.1 - checksum: 1e8b58b8059af8e83ebc1c8fea94227ec887a55e3adc32ab959fa86ac20bed745703a5e046b17505c05e7306c1835834756d27cfc0cbeea2021cb9631656ed22 - languageName: node - linkType: hard - -"@backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.2, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -3848,26 +3498,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.5": - version: 1.1.5 - resolution: "@backstage/integration-react@npm:1.1.5" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/core-components": ^0.11.2 - "@backstage/core-plugin-api": ^1.0.7 - "@backstage/integration": ^1.3.2 - "@backstage/theme": ^0.2.16 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 - react-use: ^17.2.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - checksum: 2f50416e0ca7635a59b5bf4bf89b4cf8d91a755e7ba2e4be75fb338011f98533213f984ac2def7ff65fccd51d7a94ba064c59b47d0d1d41c2a4b51f54ed68992 - languageName: node - linkType: hard - -"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@^1.1.5, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -3887,29 +3518,13 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 languageName: unknown linkType: soft -"@backstage/integration@npm:^1.3.2": - version: 1.3.2 - resolution: "@backstage/integration@npm:1.3.2" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/errors": ^1.1.2 - "@octokit/auth-app": ^4.0.0 - "@octokit/rest": ^19.0.3 - cross-fetch: ^3.1.5 - git-url-parse: ^13.0.0 - lodash: ^4.17.21 - luxon: ^3.0.0 - checksum: 960f0ea564021082f8b6e10a59782f6ffb80550dbd8a1b62e52d8b03bf72345759f0d744ef7c41434d32ad3987d4dd89e18645f818be6c00cd53e541c0a041a1 - languageName: node - linkType: hard - "@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" @@ -3926,7 +3541,7 @@ __metadata: git-url-parse: ^13.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -3947,7 +3562,7 @@ __metadata: "@types/supertest": ^2.0.8 luxon: ^3.0.0 marked: ^4.0.14 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.5 supertest: ^6.1.3 winston: ^3.2.1 @@ -3993,7 +3608,7 @@ __metadata: "@types/node": "*" cross-fetch: ^3.1.5 git-url-parse: ^13.0.0 - msw: ^0.47.0 + msw: ^0.48.0 octokit: ^2.0.0 react-markdown: ^8.0.0 react-use: ^17.2.4 @@ -4017,7 +3632,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 winston: ^3.2.1 yn: ^4.0.0 @@ -4046,7 +3661,7 @@ __metadata: "@types/node": ^16.11.26 "@types/object-hash": ^2.2.1 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 object-hash: ^3.0.0 react-use: ^17.2.4 peerDependencies: @@ -4076,7 +3691,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4104,7 +3719,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-ga: ^3.3.0 react-use: ^17.2.4 peerDependencies: @@ -4130,7 +3745,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: @@ -4155,7 +3770,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-api-docs@workspace:plugins/api-docs" dependencies: - "@asyncapi/react-component": 1.0.0-next.43 + "@asyncapi/react-component": 1.0.0-next.44 "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" @@ -4179,7 +3794,7 @@ __metadata: graphql: ^16.0.0 graphql-ws: ^5.4.1 isomorphic-form-data: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 swagger-ui-react: ^4.11.1 peerDependencies: @@ -4210,7 +3825,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 use-deep-compare-effect: ^1.8.1 peerDependencies: @@ -4242,7 +3857,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 winston: ^3.2.1 @@ -4293,10 +3908,10 @@ __metadata: luxon: ^3.0.0 minimatch: ^5.0.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-cache: ^5.1.2 node-fetch: ^2.6.7 - openid-client: ^5.1.3 + openid-client: ^5.2.1 passport: ^0.6.0 passport-auth0: ^1.4.3 passport-bitbucket-oauth2: ^0.1.2 @@ -4327,7 +3942,7 @@ __metadata: express: ^4.17.1 jose: ^4.6.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4348,7 +3963,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 mime-types: ^2.1.27 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.1.0 supertest: ^6.1.6 winston: ^3.2.1 @@ -4389,7 +4004,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.27.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4412,7 +4027,7 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 yn: ^4.0.0 @@ -4450,7 +4065,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4501,7 +4116,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4565,7 +4180,7 @@ __metadata: "@backstage/integration": "workspace:^" "@openapitools/openapi-generator-cli": ^2.4.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 ts-morph: ^15.0.0 languageName: unknown linkType: soft @@ -4594,7 +4209,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.6 react-use: ^17.2.4 recharts: ^2.0.0 @@ -4650,7 +4265,7 @@ __metadata: "@types/lodash": ^4.14.151 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4665,14 +4280,19 @@ __metadata: "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" "@backstage/backend-test-utils": "workspace:^" + "@backstage/catalog-client": "workspace:^" + "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 + p-limit: ^3.1.0 uuid: ^8.0.0 winston: ^3.2.1 languageName: unknown @@ -4695,7 +4315,7 @@ __metadata: "@backstage/plugin-catalog-node": "workspace:^" "@types/node-fetch": ^2.5.12 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4718,7 +4338,7 @@ __metadata: "@backstage/types": "workspace:^" "@types/lodash": ^4.14.151 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 languageName: unknown @@ -4742,7 +4362,7 @@ __metadata: "@types/fs-extra": ^9.0.1 fs-extra: 10.1.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4772,7 +4392,7 @@ __metadata: git-url-parse: ^13.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4799,7 +4419,7 @@ __metadata: "@types/uuid": ^8.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4845,7 +4465,7 @@ __metadata: "@types/node-fetch": ^2.5.12 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.0.2 qs: ^6.9.4 @@ -4913,7 +4533,7 @@ __metadata: knex: ^2.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.0.2 prom-client: ^14.0.1 @@ -4927,18 +4547,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@npm:^1.0.7": - version: 1.0.7 - resolution: "@backstage/plugin-catalog-common@npm:1.0.7" - dependencies: - "@backstage/catalog-model": ^1.1.2 - "@backstage/plugin-permission-common": ^0.7.0 - "@backstage/plugin-search-common": ^1.1.0 - checksum: 8a229ccbea8ce2bd0863dbf3694ac7f59690097d2607b92ea38aff78d6e5d2ac21f6d16c1a9b5bf7c09901ca7eb52d21e73480f4b1646d0aa94db8c589a3dcd5 - languageName: node - linkType: hard - -"@backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.7, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5003,7 +4612,7 @@ __metadata: graphql-modules: ^2.0.0 graphql-tag: ^2.11.0 graphql-type-json: ^0.3.2 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 languageName: unknown @@ -5039,7 +4648,7 @@ __metadata: git-url-parse: ^13.0.0 js-base64: ^3.6.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-hook-form: ^7.12.2 react-use: ^17.2.4 yaml: ^2.0.0 @@ -5066,41 +4675,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.2.0": - version: 1.2.0 - resolution: "@backstage/plugin-catalog-react@npm:1.2.0" - dependencies: - "@backstage/catalog-client": ^1.1.1 - "@backstage/catalog-model": ^1.1.2 - "@backstage/core-components": ^0.11.2 - "@backstage/core-plugin-api": ^1.0.7 - "@backstage/errors": ^1.1.2 - "@backstage/integration": ^1.3.2 - "@backstage/plugin-catalog-common": ^1.0.7 - "@backstage/plugin-permission-common": ^0.7.0 - "@backstage/plugin-permission-react": ^0.4.6 - "@backstage/theme": ^0.2.16 - "@backstage/types": ^1.0.0 - "@backstage/version-bridge": ^1.0.1 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 - classnames: ^2.2.6 - jwt-decode: ^3.1.0 - lodash: ^4.17.21 - qs: ^6.9.4 - react-use: ^17.2.4 - yaml: ^2.0.0 - zen-observable: ^0.8.15 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: c2875ac0af1e3e051b2faf018bd46b9a1843c2fd67fcfd1a09a7931ad7fbd6adf591200d184f40194702aa6f21757c7bb70636861d25ef2f1e670fca0cb0a7cf - languageName: node - linkType: hard - -"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.2.0, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -5137,7 +4712,7 @@ __metadata: react-test-renderer: ^16.13.1 react-use: ^17.2.4 yaml: ^2.0.0 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -5177,7 +4752,7 @@ __metadata: lodash: ^4.17.21 react-helmet: 6.1.0 react-use: ^17.2.4 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -5252,7 +4827,7 @@ __metadata: humanize-duration: ^3.27.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5283,7 +4858,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -5317,7 +4892,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.27.1 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5343,7 +4918,7 @@ __metadata: express-promise-router: ^4.1.0 express-xml-bodyparser: ^0.3.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 uuid: ^8.3.2 winston: ^3.2.1 @@ -5380,7 +4955,7 @@ __metadata: cross-fetch: ^3.1.5 highlight.js: ^10.6.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 recharts: ^2.0.0 peerDependencies: @@ -5411,7 +4986,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 rc-progress: 3.4.0 react-use: ^17.2.4 peerDependencies: @@ -5443,9 +5018,9 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 jsonschema: ^1.2.6 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: react: ^16.13.1 || ^17.0.0 languageName: unknown @@ -5470,6 +5045,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-cost-insights-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" @@ -5485,12 +5061,12 @@ __metadata: "@types/recharts": ^1.8.14 "@types/regression": ^2.0.0 "@types/yup": ^0.29.13 - canvas: ^2.6.1 + canvas: ^2.10.2 classnames: ^2.2.6 cross-fetch: ^3.1.5 history: ^5.0.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 pluralize: ^8.0.0 qs: ^6.9.4 react-use: ^17.2.4 @@ -5524,7 +5100,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" express: ^4.18.1 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@backstage/plugin-catalog-react": "workspace:^" @@ -5532,6 +5108,135 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-events-backend-module-aws-sqs@workspace:plugins/events-backend-module-aws-sqs": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-aws-sqs@workspace:plugins/events-backend-module-aws-sqs" + dependencies: + "@aws-sdk/client-sqs": ^3.0.0 + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-tasks": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/types": "workspace:^" + aws-sdk-client-mock: ^2.0.0 + luxon: ^3.0.0 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-azure@workspace:plugins/events-backend-module-azure": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-azure@workspace:plugins/events-backend-module-azure" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-bitbucket-cloud@workspace:plugins/events-backend-module-bitbucket-cloud": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-bitbucket-cloud@workspace:plugins/events-backend-module-bitbucket-cloud" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-gerrit@workspace:plugins/events-backend-module-gerrit": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-gerrit@workspace:plugins/events-backend-module-gerrit" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-github@workspace:plugins/events-backend-module-github": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-github@workspace:plugins/events-backend-module-github" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-gitlab@workspace:plugins/events-backend-module-gitlab": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-gitlab@workspace:plugins/events-backend-module-gitlab" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-test-utils@workspace:^, @backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend@workspace:^, @backstage/plugin-events-backend@workspace:plugins/events-backend": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend@workspace:plugins/events-backend" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@types/express": ^4.17.6 + express: ^4.17.1 + express-promise-router: ^4.1.0 + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-node@workspace:^, @backstage/plugin-events-node@workspace:plugins/events-node": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-node@workspace:plugins/events-node" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/cli": "workspace:^" + "@types/express": ^4.17.6 + express: ^4.17.1 + languageName: unknown + linkType: soft + "@backstage/plugin-explore-react@workspace:^, @backstage/plugin-explore-react@workspace:plugins/explore-react": version: 0.0.0-use.local resolution: "@backstage/plugin-explore-react@workspace:plugins/explore-react" @@ -5545,7 +5250,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -5573,7 +5278,7 @@ __metadata: "@types/node": ^16.11.26 classnames: ^2.2.6 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -5604,7 +5309,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5634,7 +5339,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.0.2 react-use: ^17.2.4 peerDependencies: @@ -5671,7 +5376,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 material-ui-popup-state: ^1.9.3 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5698,7 +5403,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 peerDependencies: react: ^16.13.1 || ^17.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 @@ -5729,7 +5434,7 @@ __metadata: "@types/recharts": ^1.8.15 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 recharts: ^2.0.0 @@ -5764,7 +5469,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5799,7 +5504,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5832,7 +5537,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 octokit: ^2.0.4 react-use: ^17.4.0 peerDependencies: @@ -5864,7 +5569,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^4.0.0 react-use: ^17.2.4 peerDependencies: @@ -5892,7 +5597,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5926,7 +5631,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: @@ -5957,7 +5662,7 @@ __metadata: graphiql: ^1.5.12 graphql: ^16.0.0 graphql-ws: ^5.4.1 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5983,7 +5688,7 @@ __metadata: graphql: ^16.0.0 graphql-modules: ^2.0.0 helmet: ^6.0.0 - msw: ^0.47.0 + msw: ^0.48.0 reflect-metadata: ^0.1.13 supertest: ^6.1.3 winston: ^3.2.1 @@ -5991,31 +5696,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home@npm:^0.4.26": - version: 0.4.26 - resolution: "@backstage/plugin-home@npm:0.4.26" - dependencies: - "@backstage/catalog-model": ^1.1.2 - "@backstage/config": ^1.0.3 - "@backstage/core-components": ^0.11.2 - "@backstage/core-plugin-api": ^1.0.7 - "@backstage/plugin-catalog-react": ^1.2.0 - "@backstage/plugin-stack-overflow": ^0.1.6 - "@backstage/theme": ^0.2.16 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 - lodash: ^4.17.21 - react-use: ^17.2.4 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: bb20f2538a1e155bbb7c5587fe953ecaacd6f0384b951dcd862be7a2fa277ed80d793336953cc778b6a574ee898064a5aab436b3c61d3695944084c748449095 - languageName: node - linkType: hard - -"@backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": +"@backstage/plugin-home@^0.4.26, @backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": version: 0.0.0-use.local resolution: "@backstage/plugin-home@workspace:plugins/home" dependencies: @@ -6039,7 +5720,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -6074,7 +5755,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.26.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6100,7 +5781,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 jenkins: ^1.0.0 - msw: ^0.47.0 + msw: ^0.48.0 promise-any-polyfill: ^1.0.1 supertest: ^6.1.6 winston: ^3.2.1 @@ -6143,7 +5824,7 @@ __metadata: "@types/testing-library__jest-dom": ^5.9.1 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6198,7 +5879,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 jest-when: ^3.1.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6220,7 +5901,7 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-kubernetes-common": "workspace:^" "@google-cloud/container": ^4.0.0 - "@kubernetes/client-node": ^0.17.0 + "@kubernetes/client-node": 0.17.0 "@types/aws4": ^1.5.1 "@types/express": ^4.17.6 "@types/luxon": ^3.0.0 @@ -6249,7 +5930,7 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" - "@kubernetes/client-node": ^0.17.0 + "@kubernetes/client-node": 0.17.0 languageName: unknown linkType: soft @@ -6268,7 +5949,7 @@ __metadata: "@backstage/plugin-kubernetes-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" - "@kubernetes/client-node": ^0.17.0 + "@kubernetes/client-node": 0.17.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.57 @@ -6283,7 +5964,7 @@ __metadata: js-yaml: ^4.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6315,7 +5996,7 @@ __metadata: "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6365,7 +6046,36 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + +"@backstage/plugin-org-react@workspace:plugins/org-react": + version: 0.0.0-use.local + resolution: "@backstage/plugin-org-react@workspace:plugins/org-react" + dependencies: + "@backstage/catalog-client": "workspace:^" + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": ^4.0.0-alpha.57 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/node": "*" + cross-fetch: ^3.1.5 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6394,7 +6104,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.1.0 pluralize: ^8.0.0 qs: ^6.10.1 @@ -6430,7 +6140,7 @@ __metadata: classnames: ^2.2.6 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -6450,7 +6160,7 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.6 winston: ^3.2.1 @@ -6482,7 +6192,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6508,7 +6218,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.6 winston: ^3.2.1 @@ -6517,20 +6227,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@npm:^0.7.0": - version: 0.7.0 - resolution: "@backstage/plugin-permission-common@npm:0.7.0" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/errors": ^1.1.2 - "@backstage/types": ^1.0.0 - cross-fetch: ^3.1.5 - uuid: ^8.0.0 - zod: ^3.11.6 - checksum: e71705494b55efacf234a46abe162f241ebecb231a6a4c76d7134bb629c1b7d1ffdead8f9725ea515a818ce376a99d2121dc7ef1c8d0badd955fdb1d4cd405cf - languageName: node - linkType: hard - "@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" @@ -6540,7 +6236,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 uuid: ^8.0.0 zod: ^3.11.6 languageName: unknown @@ -6561,31 +6257,13 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 zod: ^3.11.6 zod-to-json-schema: ^3.18.1 languageName: unknown linkType: soft -"@backstage/plugin-permission-react@npm:^0.4.6": - version: 0.4.6 - resolution: "@backstage/plugin-permission-react@npm:0.4.6" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/core-plugin-api": ^1.0.7 - "@backstage/plugin-permission-common": ^0.7.0 - cross-fetch: ^3.1.5 - react-use: ^17.2.4 - swr: ^1.1.2 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 7c8c619d1c0465ac6f48a5f841127f75fb3689c6b7948777f093b11a7a65ac1308cb30ab46658591e8463ccd8dac7bdbc098c4922b9fa858b307f2113ef2acef - languageName: node - linkType: hard - "@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" @@ -6627,7 +6305,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 uuid: ^8.2.0 @@ -6675,7 +6353,7 @@ __metadata: "@types/node": "*" cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-hook-form: ^7.13.0 react-use: ^17.2.4 @@ -6703,7 +6381,7 @@ __metadata: express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 uuid: ^8.0.0 winston: ^3.2.1 @@ -6731,7 +6409,7 @@ __metadata: fs-extra: 10.1.0 lodash: ^4.17.21 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 winston: ^3.2.1 @@ -6763,7 +6441,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: @@ -6790,7 +6468,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: 10.1.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 winston: ^3.2.1 yn: ^4.0.0 languageName: unknown @@ -6866,7 +6544,7 @@ __metadata: command-exists: ^1.2.9 compression: ^1.7.4 cors: ^2.8.5 - esbuild: ^0.14.1 + esbuild: ^0.15.0 express: ^4.17.1 express-promise-router: ^4.1.0 fs-extra: 10.1.0 @@ -6881,7 +6559,7 @@ __metadata: luxon: ^3.0.0 mock-fs: ^5.1.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 nunjucks: ^3.2.3 octokit: ^2.0.0 @@ -6893,7 +6571,7 @@ __metadata: vm2: ^3.9.11 winston: ^3.2.1 yaml: ^2.0.0 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 zod: ^3.11.6 languageName: unknown linkType: soft @@ -6939,11 +6617,11 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.57 "@react-hookz/web": ^15.0.0 "@rjsf/core": ^3.2.1 - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.10" + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12" "@rjsf/material-ui": ^3.2.1 - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.10" - "@rjsf/utils": ^5.0.0-beta.10 - "@rjsf/validator-ajv8": ^5.0.0-beta.10 + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12" + "@rjsf/utils": ^5.0.0-beta.12 + "@rjsf/validator-ajv8": ^5.0.0-beta.12 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -6962,12 +6640,14 @@ __metadata: json-schema-library: ^7.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 use-immer: ^0.7.0 yaml: ^2.0.0 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 + zod: ^3.11.6 + zod-to-json-schema: ^3.18.1 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -7064,16 +6744,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-search-common@npm:^1.1.0": - version: 1.1.0 - resolution: "@backstage/plugin-search-common@npm:1.1.0" - dependencies: - "@backstage/plugin-permission-common": ^0.7.0 - "@backstage/types": ^1.0.0 - checksum: c14e91b5e180c345d47077e678a5b1b9a86620350171f5cafe799e24a815c07952bf817e2b8759019227c07ea93dcf0608ba321afa7ead68c4281e01f6b3b3de - languageName: node - linkType: hard - "@backstage/plugin-search-common@workspace:^, @backstage/plugin-search-common@workspace:plugins/search-common": version: 0.0.0-use.local resolution: "@backstage/plugin-search-common@workspace:plugins/search-common" @@ -7142,7 +6812,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7178,7 +6848,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: @@ -7208,11 +6878,11 @@ __metadata: "@types/node": ^16.11.26 "@types/zen-observable": ^0.8.2 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-hook-form: ^7.12.2 react-use: ^17.2.4 uuid: ^8.3.2 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: react: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 @@ -7232,7 +6902,7 @@ __metadata: "@types/supertest": ^2.0.12 express: ^4.18.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.2.4 winston: ^3.2.1 @@ -7262,7 +6932,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 rc-progress: 3.4.0 react-use: ^17.2.4 peerDependencies: @@ -7294,7 +6964,7 @@ __metadata: classnames: ^2.2.6 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7315,30 +6985,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-stack-overflow@npm:^0.1.6": - version: 0.1.6 - resolution: "@backstage/plugin-stack-overflow@npm:0.1.6" - dependencies: - "@backstage/config": ^1.0.3 - "@backstage/core-components": ^0.11.2 - "@backstage/core-plugin-api": ^1.0.7 - "@backstage/plugin-home": ^0.4.26 - "@backstage/plugin-search-common": ^1.1.0 - "@backstage/theme": ^0.2.16 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@testing-library/jest-dom": ^5.10.1 - cross-fetch: ^3.1.5 - lodash: ^4.17.21 - qs: ^6.9.4 - react-use: ^17.2.4 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - checksum: e7900ed037f34746e4156106d4579f0474f272fa46b5320ece2e5a7fec967aacc8fc90194802369460648a15b4a78103f68745261b666668cde6957b255ba166 - languageName: node - linkType: hard - "@backstage/plugin-stack-overflow@workspace:^, @backstage/plugin-stack-overflow@workspace:plugins/stack-overflow": version: 0.0.0-use.local resolution: "@backstage/plugin-stack-overflow@workspace:plugins/stack-overflow" @@ -7361,7 +7007,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7472,7 +7118,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7506,7 +7152,7 @@ __metadata: color: ^4.0.1 cross-fetch: ^3.1.5 d3-force: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 react-use: ^17.2.4 peerDependencies: @@ -7538,7 +7184,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 testing-library__dom: ^7.29.4-beta.1 peerDependencies: @@ -7574,7 +7220,7 @@ __metadata: fs-extra: 10.1.0 knex: ^2.0.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.1.0 supertest: ^6.1.3 @@ -7608,7 +7254,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 git-url-parse: ^13.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7712,14 +7358,14 @@ __metadata: "@types/dompurify": ^2.2.2 "@types/event-source-polyfill": ^1.0.0 "@types/node": ^16.11.26 - canvas: ^2.6.1 + canvas: ^2.10.2 cross-fetch: ^3.1.5 dompurify: ^2.2.9 event-source-polyfill: 1.0.25 git-url-parse: ^13.0.0 jss: ~10.8.2 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-helmet: 6.1.0 react-use: ^17.2.4 peerDependencies: @@ -7747,7 +7393,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 leasot: ^12.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 winston: ^3.2.1 yn: ^4.0.0 @@ -7776,7 +7422,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7828,9 +7474,9 @@ __metadata: "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 peerDependencies: react: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 @@ -7855,7 +7501,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 helmet: ^6.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.1.0 supertest: ^6.1.6 @@ -7886,7 +7532,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7916,7 +7562,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 recharts: ^2.0.0 peerDependencies: @@ -7932,7 +7578,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@types/node": ^16.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -7955,8 +7601,8 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 - zen-observable: ^0.8.15 + msw: ^0.48.0 + zen-observable: ^0.9.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 react: ^16.13.1 || ^17.0.0 @@ -7975,21 +7621,14 @@ __metadata: languageName: unknown linkType: soft -"@backstage/types@npm:^1.0.0": - version: 1.0.0 - resolution: "@backstage/types@npm:1.0.0" - checksum: 03a9809a8666a9caef2d14d6a521bfdbcde734e9af734f1918ebd25715c6a9d6ba99094a509b7fc59f19bac2c50bcc99fdd5216e64523f2831ada44859f63b38 - languageName: node - linkType: hard - -"@backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/types@^1.0.0, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: "@backstage/cli": "workspace:^" "@types/zen-observable": ^0.8.0 luxon: ^3.0.0 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 languageName: unknown linkType: soft @@ -8028,9 +7667,9 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^6.1.1": - version: 6.1.1 - resolution: "@changesets/apply-release-plan@npm:6.1.1" +"@changesets/apply-release-plan@npm:^6.1.2": + version: 6.1.2 + resolution: "@changesets/apply-release-plan@npm:6.1.2" dependencies: "@babel/runtime": ^7.10.4 "@changesets/config": ^2.2.0 @@ -8045,7 +7684,7 @@ __metadata: prettier: ^2.7.1 resolve-from: ^5.0.0 semver: ^5.4.1 - checksum: 34da2d52eced00bc5f51c8e8ce16c0e487743219f057da2b3e6c6597bb2d50498f3996c779e4fc29b19d357c9b700d82310d723395ba09350b9a139c9e0e0d23 + checksum: efe2cdc493cb2182140b73ff76e34ee7c90887bfa2f42b4ec07db0107ec94b9c0e95519912dafcf9eb530ad2414487fbd61ca6e6d5f853fe383db93856d0d362 languageName: node linkType: hard @@ -8073,11 +7712,11 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.25.0 - resolution: "@changesets/cli@npm:2.25.0" + version: 2.25.2 + resolution: "@changesets/cli@npm:2.25.2" dependencies: "@babel/runtime": ^7.10.4 - "@changesets/apply-release-plan": ^6.1.1 + "@changesets/apply-release-plan": ^6.1.2 "@changesets/assemble-release-plan": ^5.2.2 "@changesets/changelog-git": ^0.1.13 "@changesets/config": ^2.2.0 @@ -8089,7 +7728,7 @@ __metadata: "@changesets/pre": ^1.0.13 "@changesets/read": ^0.5.8 "@changesets/types": ^5.2.0 - "@changesets/write": ^0.2.1 + "@changesets/write": ^0.2.2 "@manypkg/get-packages": ^1.1.3 "@types/is-ci": ^3.0.0 "@types/semver": ^6.0.0 @@ -8111,7 +7750,7 @@ __metadata: tty-table: ^4.1.5 bin: changeset: bin.js - checksum: 54439bdfa7ca115964482f6323e9475b5917d68c2e0752a272ed133b863fce51eeba86366d8740a275dc0b891af8e272602da69d04144f40e4bf3531f48fe8fb + checksum: 815c69cb6cee75ede88361582581d94a860d96335e7bab179481cd5e2bb1e60cc39662dccd2b2b87818e9c63a84ff9eb469ed27f13b6adf4401a699e49beb79c languageName: node linkType: hard @@ -8250,16 +7889,16 @@ __metadata: languageName: node linkType: hard -"@changesets/write@npm:^0.2.1": - version: 0.2.1 - resolution: "@changesets/write@npm:0.2.1" +"@changesets/write@npm:^0.2.2": + version: 0.2.2 + resolution: "@changesets/write@npm:0.2.2" dependencies: "@babel/runtime": ^7.10.4 "@changesets/types": ^5.2.0 fs-extra: ^7.0.1 human-id: ^1.0.2 prettier: ^2.7.1 - checksum: 98b4d9c12fe13177860407557979d475361076a596103895440f52b2724f7004d6c98af39105fda0eaa52ceca8c0dc0ec9c8ab10eec7a0cb9bf83301f2ca48b3 + checksum: e23fb4a88e12af32db59d2f1866380ec4a50e7fa55cb55d860619f0735c5078ed170f832125672bb007b7a0cced67d9304a1b81260a7224af6afe0e3957dc999 languageName: node linkType: hard @@ -8293,8 +7932,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.3.0 - resolution: "@codemirror/language@npm:6.3.0" + version: 6.3.1 + resolution: "@codemirror/language@npm:6.3.1" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 @@ -8302,7 +7941,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 996d6aad1a4cfb455f3459951d5ecfb67ff5240cc29397b3b801e569fcda24f87364aa7e42b63e85ecf62af80eaecd01258303dbf5b5f0b1eba31daa9a5bd258 + checksum: 349b9806e1e2ce5d99ba1f5815cc4772e6032f68c95718594e8335196ef0686bc6378db7cdd5f0fda57ba068eebf0ee413bb336e32cc1ff958a743190a0266da languageName: node linkType: hard @@ -8357,13 +7996,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.4.0 - resolution: "@codemirror/view@npm:6.4.0" + version: 6.4.2 + resolution: "@codemirror/view@npm:6.4.2" dependencies: "@codemirror/state": ^6.0.0 style-mod: ^4.0.0 w3c-keyname: ^2.2.4 - checksum: 57ed7d9d51907f1ea549a2a158872fb7affa6cdff72e29e214f8437b7142ea2a2431ac3c780cbc0187dfff7cb5fd1055a45a887ea9b8c2a09d8430c60ebe9083 + checksum: c79982563ad90adf1d7504b28bb1304a73f669c69634a1630b51521e4023b3630c15601daf2857683b34a86cac4ca24dc5b538a9d944616617f99c1a7da7faa6 languageName: node linkType: hard @@ -8538,32 +8177,23 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.15.8": - version: 0.15.8 - resolution: "@esbuild/android-arm@npm:0.15.8" - dependencies: - esbuild-wasm: 0.15.8 +"@esbuild/android-arm@npm:0.15.13": + version: 0.15.13 + resolution: "@esbuild/android-arm@npm:0.15.13" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.14.54": - version: 0.14.54 - resolution: "@esbuild/linux-loong64@npm:0.14.54" +"@esbuild/linux-loong64@npm:0.15.13": + version: 0.15.13 + resolution: "@esbuild/linux-loong64@npm:0.15.13" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.15.8": - version: 0.15.8 - resolution: "@esbuild/linux-loong64@npm:0.15.8" - conditions: os=linux & cpu=loong64 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^1.3.2": - version: 1.3.2 - resolution: "@eslint/eslintrc@npm:1.3.2" +"@eslint/eslintrc@npm:^1.3.3": + version: 1.3.3 + resolution: "@eslint/eslintrc@npm:1.3.3" dependencies: ajv: ^6.12.4 debug: ^4.3.2 @@ -8574,7 +8204,7 @@ __metadata: js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: 2074dca47d7e1c5c6323ff353f690f4b25d3ab53fe7d27337e2592d37a894cf60ca0e85ca66b50ff2db0bc7e630cc1e9c7347d65bb185b61416565584c38999c + checksum: f03e9d6727efd3e0719da2051ea80c0c73d20e28c171121527dbb868cd34232ca9c1d0525a66e517a404afea26624b1e47895b6a92474678418c2f50c9566694 languageName: node linkType: hard @@ -8587,14 +8217,7 @@ __metadata: languageName: node linkType: hard -"@gar/promisify@npm:^1.0.1": - version: 1.1.2 - resolution: "@gar/promisify@npm:1.1.2" - checksum: d05081e0887a49c178b75ee3067bd6ee086f73c154d121b854fb2e044e8a89cb1cbb6de3a0dd93a519b80f0531fda68b099dd7256205f7fbb3490324342f2217 - languageName: node - linkType: hard - -"@gar/promisify@npm:^1.1.3": +"@gar/promisify@npm:^1.0.1, @gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 @@ -8697,8 +8320,8 @@ __metadata: linkType: hard "@google-cloud/storage@npm:^6.0.0": - version: 6.5.3 - resolution: "@google-cloud/storage@npm:6.5.3" + version: 6.7.0 + resolution: "@google-cloud/storage@npm:6.7.0" dependencies: "@google-cloud/paginator": ^3.0.7 "@google-cloud/projectify": ^3.0.0 @@ -8717,7 +8340,7 @@ __metadata: retry-request: ^5.0.0 teeny-request: ^8.0.0 uuid: ^8.0.0 - checksum: 9b88a5bff4e8401dbd18223fe570882df632cbb0e515e7f3eca33dbea16568168b2c0397b02ad8030e6d114b6d73109283d17a49762f1833f077424bf90a676d + checksum: 269224b965eb6a4c0c47b5df7cc21a6110ded2596c649ea94737ad622410b10a91fc0a1b765667c7bb64e44a98dad35abc5d342173b13b10f174ab0ce211f434 languageName: node linkType: hard @@ -8755,21 +8378,21 @@ __metadata: linkType: hard "@graphql-codegen/cli@npm:^2.3.1": - version: 2.13.7 - resolution: "@graphql-codegen/cli@npm:2.13.7" + version: 2.13.12 + resolution: "@graphql-codegen/cli@npm:2.13.12" dependencies: "@babel/generator": ^7.18.13 "@babel/template": ^7.18.10 "@babel/types": ^7.18.13 - "@graphql-codegen/core": 2.6.2 - "@graphql-codegen/plugin-helpers": ^2.6.2 + "@graphql-codegen/core": 2.6.6 + "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-tools/apollo-engine-loader": ^7.3.6 "@graphql-tools/code-file-loader": ^7.3.1 "@graphql-tools/git-loader": ^7.2.1 "@graphql-tools/github-loader": ^7.3.6 "@graphql-tools/graphql-file-loader": ^7.5.0 "@graphql-tools/json-file-loader": ^7.4.1 - "@graphql-tools/load": ^7.7.1 + "@graphql-tools/load": 7.8.0 "@graphql-tools/prisma-loader": ^7.2.7 "@graphql-tools/url-loader": ^7.13.2 "@graphql-tools/utils": ^8.9.0 @@ -8801,43 +8424,43 @@ __metadata: graphql-code-generator: cjs/bin.js graphql-codegen: cjs/bin.js graphql-codegen-esm: esm/bin.js - checksum: c025e311c072c1d992451f27625c863eef1236e5f01e2aeb6f00e67a60e99c7812a13481481a8fc6ea2967fffd77433d582f10365244d677608fdc7aa13bbe29 + checksum: 367d4687e1d4bf44f0a7f3cb4e71656774f006512883a51ceae905495b2e76819e6b49dfe63e3effe59abb990a4c17bb985878a4592bf2ff959dc822723c1370 languageName: node linkType: hard -"@graphql-codegen/core@npm:2.6.2": - version: 2.6.2 - resolution: "@graphql-codegen/core@npm:2.6.2" +"@graphql-codegen/core@npm:2.6.6": + version: 2.6.6 + resolution: "@graphql-codegen/core@npm:2.6.6" dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 + "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-tools/schema": ^9.0.0 - "@graphql-tools/utils": ^8.8.0 + "@graphql-tools/utils": ^9.1.1 tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 3d078e9caa11baf7ceaa4d67b29a6be32f50a183c1fa6f228a3ade62902b9b91cdea2c94d99adbadf10ec38a7f2df9f16cd366dc7b4febf95336e3b4a7eb9160 + checksum: 4a506dfb7dad577510b0358444ad5c5080459c00e1740099212d28c08fc4f02824014602172b95a61c6092cc97b3838fafd02b3e2eadf99dd9b6fa390464935a languageName: node linkType: hard "@graphql-codegen/graphql-modules-preset@npm:^2.3.2": - version: 2.5.4 - resolution: "@graphql-codegen/graphql-modules-preset@npm:2.5.4" + version: 2.5.5 + resolution: "@graphql-codegen/graphql-modules-preset@npm:2.5.5" dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 - "@graphql-codegen/visitor-plugin-common": 2.13.0 + "@graphql-codegen/plugin-helpers": ^2.7.2 + "@graphql-codegen/visitor-plugin-common": 2.13.1 "@graphql-tools/utils": ^8.8.0 change-case-all: 1.0.14 parse-filepath: ^1.0.2 tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: d3e9b90c475c1a093149038b0dea448ebbb25bf9cf853d1947427bed741d739f140daca8f3861da63bfee6f6958c25f1b1081ce4365c7db1efe6527bb9b9c1dc + checksum: d499001af49d0a829c6adcbc211d252e8d5a42ba1635c32265ad99d187666425150c99815d48e591ca66e811a2b09860a5f59ba02484a3a3f0dcf4dcba8a6fb8 languageName: node linkType: hard -"@graphql-codegen/plugin-helpers@npm:^2.6.2": - version: 2.6.2 - resolution: "@graphql-codegen/plugin-helpers@npm:2.6.2" +"@graphql-codegen/plugin-helpers@npm:^2.6.2, @graphql-codegen/plugin-helpers@npm:^2.7.2": + version: 2.7.2 + resolution: "@graphql-codegen/plugin-helpers@npm:2.7.2" dependencies: "@graphql-tools/utils": ^8.8.0 change-case-all: 1.0.14 @@ -8847,7 +8470,7 @@ __metadata: tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 972b5d6e13d8cdfde5fe3d79b79e7e0af7c3931619a10d48b931e1d101e95694e29fa83d66e25df1427827faf841f5884b5a677bb659a5de08ece95854a25736 + checksum: 66e0d507ad5db60b67092ebf7632d464d56ab446ac8fd87c293e00d9016944912d8cf9199e3e026b0a9247a50f50c4118a44f49e13675db64211652cd6259b05 languageName: node linkType: hard @@ -8865,56 +8488,41 @@ __metadata: linkType: hard "@graphql-codegen/typescript-resolvers@npm:^2.4.3": - version: 2.7.5 - resolution: "@graphql-codegen/typescript-resolvers@npm:2.7.5" + version: 2.7.6 + resolution: "@graphql-codegen/typescript-resolvers@npm:2.7.6" dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 - "@graphql-codegen/typescript": ^2.7.5 - "@graphql-codegen/visitor-plugin-common": 2.13.0 + "@graphql-codegen/plugin-helpers": ^2.7.2 + "@graphql-codegen/typescript": ^2.8.1 + "@graphql-codegen/visitor-plugin-common": 2.13.1 "@graphql-tools/utils": ^8.8.0 auto-bind: ~4.0.0 tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 7384bbb42bdf43157b6133812c2e84bb162ab5b52add05bed86a4f3c149bf3ab1f178bb5a7d51c661ba354296b2fa9e4983ee42b373c3815fdc6ee391a9e5307 + checksum: f552f74aa264c0f9024834d6d1c126f9f1a69dccf7278525c7609ad1820daf87607447f30351506fe3728a855690928ba7775edbbbff0fee610a2ce02913a98e languageName: node linkType: hard -"@graphql-codegen/typescript@npm:^2.4.2": - version: 2.8.0 - resolution: "@graphql-codegen/typescript@npm:2.8.0" +"@graphql-codegen/typescript@npm:^2.4.2, @graphql-codegen/typescript@npm:^2.8.1": + version: 2.8.1 + resolution: "@graphql-codegen/typescript@npm:2.8.1" dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 + "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-codegen/schema-ast": ^2.5.1 - "@graphql-codegen/visitor-plugin-common": 2.13.0 + "@graphql-codegen/visitor-plugin-common": 2.13.1 auto-bind: ~4.0.0 tslib: ~2.4.0 peerDependencies: graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 45550613384c930d046f1ca8bfd73c25e1219fc45315b1885017e08577a517547d5af86908162f61eee0670689df5c926b5e394b318d5c3d94ee5eef5ac1bc52 + checksum: 2b5466190e385c557eed6210b861fb9e632fb61b90bd0f97ff983f359c0ad8106228667c9ff2201842100417a07cfaffa91794ef03058a151df256d733363fa2 languageName: node linkType: hard -"@graphql-codegen/typescript@npm:^2.7.5": - version: 2.7.5 - resolution: "@graphql-codegen/typescript@npm:2.7.5" +"@graphql-codegen/visitor-plugin-common@npm:2.13.1": + version: 2.13.1 + resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.1" dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 - "@graphql-codegen/schema-ast": ^2.5.1 - "@graphql-codegen/visitor-plugin-common": 2.13.0 - auto-bind: ~4.0.0 - tslib: ~2.4.0 - peerDependencies: - graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 0eb51d2bb826284cfed29fdaee0fc57694932627f0146394711d3f012377bccb19592270f6c04f775ec06ec87e1a05a0c85064ca186ea0e50a306ec058674fad - languageName: node - linkType: hard - -"@graphql-codegen/visitor-plugin-common@npm:2.13.0": - version: 2.13.0 - resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.0" - dependencies: - "@graphql-codegen/plugin-helpers": ^2.6.2 + "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-tools/optimize": ^1.3.0 "@graphql-tools/relay-operation-optimizer": ^6.5.0 "@graphql-tools/utils": ^8.8.0 @@ -8926,7 +8534,7 @@ __metadata: tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 1d7491d626059529faca2eda5466aa8b05bf2cc9a768175043461d0ec4793b4cbda2fb762ef44e6c8d094f951960569f2adf177af74156f4a74f33c6d5ae77bf + checksum: 0c329aa6e435602f2f6c1569ec2091b7850f58cc5dca7ac763c38c82588545ec1110c1de587f5f3949b11ff96f94401d1e63e329607d78424583b276fd08f1ae languageName: node linkType: hard @@ -8944,34 +8552,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/batch-execute@npm:8.4.6": - version: 8.4.6 - resolution: "@graphql-tools/batch-execute@npm:8.4.6" - dependencies: - "@graphql-tools/utils": 8.6.9 - dataloader: 2.1.0 - tslib: ~2.3.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 613b47b15b6055e2f7e9fa28b8a9751faf30f4e8e30f348446fcacdb300015adeea126436f3f0c9d1798a6df925dff3d99175ec826763c3308db1f08f8db3000 - languageName: node - linkType: hard - -"@graphql-tools/batch-execute@npm:8.5.0": - version: 8.5.0 - resolution: "@graphql-tools/batch-execute@npm:8.5.0" - dependencies: - "@graphql-tools/utils": 8.8.0 - dataloader: 2.1.0 - tslib: ^2.4.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 9bb0363f4c0c6e6c919c38965164b1e9241aaa1caf071a6f70e93c62d48e7784eec2b4d87b6df02f9d84bbf63e8c981ade6aa8e86eb69f099aac5fb4484deacd - languageName: node - linkType: hard - "@graphql-tools/batch-execute@npm:8.5.1": version: 8.5.1 resolution: "@graphql-tools/batch-execute@npm:8.5.1" @@ -9001,39 +8581,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/delegate@npm:8.7.7": - version: 8.7.7 - resolution: "@graphql-tools/delegate@npm:8.7.7" - dependencies: - "@graphql-tools/batch-execute": 8.4.6 - "@graphql-tools/schema": 8.3.10 - "@graphql-tools/utils": 8.6.9 - dataloader: 2.1.0 - graphql-executor: 0.0.23 - tslib: ~2.3.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 1f06d645c6382eee72bf779949cb631688c20f0a9260c729810a87cf3afae13166ae1ef34aa80de4895c06a0128da910de933d900835aa8a81f39e3ccfa9bbfe - languageName: node - linkType: hard - -"@graphql-tools/delegate@npm:8.8.0": - version: 8.8.0 - resolution: "@graphql-tools/delegate@npm:8.8.0" - dependencies: - "@graphql-tools/batch-execute": 8.5.0 - "@graphql-tools/schema": 8.5.0 - "@graphql-tools/utils": 8.8.0 - dataloader: 2.1.0 - tslib: ~2.4.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: ceeb69345556d7d8ddb3d8862ba4d7cf970c962b26ef6ed6835d2915ceb450e92ab1aa4f8dda6efa53f0b27992f8a866aa956eb15086eb8aa381267d011e0ccc - languageName: node - linkType: hard - "@graphql-tools/delegate@npm:8.8.1": version: 8.8.1 resolution: "@graphql-tools/delegate@npm:8.8.1" @@ -9081,22 +8628,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/graphql-file-loader@npm:^7.3.7": - version: 7.4.0 - resolution: "@graphql-tools/graphql-file-loader@npm:7.4.0" - dependencies: - "@graphql-tools/import": 6.7.0 - "@graphql-tools/utils": 8.8.0 - globby: ^11.0.3 - tslib: ^2.4.0 - unixify: ^1.0.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: e6221b78dfd15e2a73cd34d039780173dee7464276b9fd78ee3494c5a894f0904cabd27084a531c252c01f84aaba763b7f089bc10b268f0f18a01e266093eec2 - languageName: node - linkType: hard - -"@graphql-tools/graphql-file-loader@npm:^7.5.0": +"@graphql-tools/graphql-file-loader@npm:^7.3.7, @graphql-tools/graphql-file-loader@npm:^7.5.0": version: 7.5.0 resolution: "@graphql-tools/graphql-file-loader@npm:7.5.0" dependencies: @@ -9126,19 +8658,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/import@npm:6.7.0": - version: 6.7.0 - resolution: "@graphql-tools/import@npm:6.7.0" - dependencies: - "@graphql-tools/utils": 8.8.0 - resolve-from: 5.0.0 - tslib: ^2.4.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 9c2f3404b1d40f37e611f1866a1f569b41cc56b07a95a822d19b25cac00341868324457f239dc9856e19cac50e27142d25f948de5e10051838af9913c565821f - languageName: node - linkType: hard - "@graphql-tools/import@npm:6.7.1": version: 6.7.1 resolution: "@graphql-tools/import@npm:6.7.1" @@ -9152,21 +8671,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/json-file-loader@npm:^7.3.7": - version: 7.4.0 - resolution: "@graphql-tools/json-file-loader@npm:7.4.0" - dependencies: - "@graphql-tools/utils": 8.8.0 - globby: ^11.0.3 - tslib: ^2.4.0 - unixify: ^1.0.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 20bca3e92b049fc7937d4a07376f8231f44cca5eacfa1d8cdd0b35cbe3981502d388f366fd13174f26bfa9a252deeb689aaba385d092d588476a2f2f0b4fdb4d - languageName: node - linkType: hard - -"@graphql-tools/json-file-loader@npm:^7.4.1": +"@graphql-tools/json-file-loader@npm:^7.3.7, @graphql-tools/json-file-loader@npm:^7.4.1": version: 7.4.1 resolution: "@graphql-tools/json-file-loader@npm:7.4.1" dependencies: @@ -9180,31 +8685,17 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/load@npm:^7.5.5": - version: 7.7.0 - resolution: "@graphql-tools/load@npm:7.7.0" +"@graphql-tools/load@npm:7.8.0, @graphql-tools/load@npm:^7.5.5": + version: 7.8.0 + resolution: "@graphql-tools/load@npm:7.8.0" dependencies: - "@graphql-tools/schema": 8.5.0 - "@graphql-tools/utils": 8.8.0 + "@graphql-tools/schema": 9.0.4 + "@graphql-tools/utils": 8.12.0 p-limit: 3.1.0 tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 91f2b4f3e72b2991aee6f562aebd5024f2279e5336879322c44e1dafb38af407944a178c55234c39157635d0179798d022e937e960273bd86b752fd316cbaf73 - languageName: node - linkType: hard - -"@graphql-tools/load@npm:^7.7.1": - version: 7.7.1 - resolution: "@graphql-tools/load@npm:7.7.1" - dependencies: - "@graphql-tools/schema": 8.5.1 - "@graphql-tools/utils": 8.9.0 - p-limit: 3.1.0 - tslib: ^2.4.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 4abaab346dab9547f547fe619476e5de54698121174f579f3473f2d5678891c249482a3e56f9b748400d5062c9bd3b5d5d5e56885555e5a3422cafa2afd6022e + checksum: 24ade442e13429d087ceac905cef4e6a14d0961e2b231adf91180a4d674de08ac6de66e6103c3e118b6ccf24065492bb69f5c99cb336e71a579ab382c8574791 languageName: node linkType: hard @@ -9220,18 +8711,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/merge@npm:8.3.0, @graphql-tools/merge@npm:^8.2.6": - version: 8.3.0 - resolution: "@graphql-tools/merge@npm:8.3.0" - dependencies: - "@graphql-tools/utils": 8.8.0 - tslib: ^2.4.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: f2239149d8a816d1158c5bf9f2507662faf7f77eeb8d6f6962111f69d7aedab1557f6cd8beac75bf62f0caf56a3c98ba83608207cd0614ad3119c68390d86bbe - languageName: node - linkType: hard - "@graphql-tools/merge@npm:8.3.1": version: 8.3.1 resolution: "@graphql-tools/merge@npm:8.3.1" @@ -9244,6 +8723,18 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/merge@npm:8.3.11, @graphql-tools/merge@npm:^8.2.6": + version: 8.3.11 + resolution: "@graphql-tools/merge@npm:8.3.11" + dependencies: + "@graphql-tools/utils": 9.1.0 + tslib: ^2.4.0 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 3cd16577f1ea1bcc389d232fa620adc0fefc91a6b42b48e7bb5e7bb67b67d206d409a9a8d60cac4d8cd5f0f1c5353369f7c5eb4054b44ce2277545e1fd1de17f + languageName: node + linkType: hard + "@graphql-tools/merge@npm:8.3.6": version: 8.3.6 resolution: "@graphql-tools/merge@npm:8.3.6" @@ -9323,7 +8814,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:8.3.10, @graphql-tools/schema@npm:^8.0.0, @graphql-tools/schema@npm:^8.3.1": +"@graphql-tools/schema@npm:8.3.10": version: 8.3.10 resolution: "@graphql-tools/schema@npm:8.3.10" dependencies: @@ -9337,21 +8828,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:8.5.0": - version: 8.5.0 - resolution: "@graphql-tools/schema@npm:8.5.0" - dependencies: - "@graphql-tools/merge": 8.3.0 - "@graphql-tools/utils": 8.8.0 - tslib: ^2.4.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 8eeefdd66e2fe674990039f81733a868ee589057cb44832e65fe99a8b17ab0c6b40dabf41a840b3458a4eb63665fb9603029269d6d919f916ae97e213a4434ba - languageName: node - linkType: hard - -"@graphql-tools/schema@npm:8.5.1": +"@graphql-tools/schema@npm:8.5.1, @graphql-tools/schema@npm:^8.0.0, @graphql-tools/schema@npm:^8.3.1": version: 8.5.1 resolution: "@graphql-tools/schema@npm:8.5.1" dependencies: @@ -9365,7 +8842,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:^9.0.0": +"@graphql-tools/schema@npm:9.0.4": version: 9.0.4 resolution: "@graphql-tools/schema@npm:9.0.4" dependencies: @@ -9379,7 +8856,21 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/url-loader@npm:7.13.2, @graphql-tools/url-loader@npm:^7.13.2": +"@graphql-tools/schema@npm:^9.0.0": + version: 9.0.9 + resolution: "@graphql-tools/schema@npm:9.0.9" + dependencies: + "@graphql-tools/merge": 8.3.11 + "@graphql-tools/utils": 9.1.0 + tslib: ^2.4.0 + value-or-promise: 1.0.11 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 23620a993eff57723302315100d947b81664d6a1e00010ff293b3649f51ab423946d73920cce0ce822b7f7f42b99ea23240902ff47df3d252639613c0df7b971 + languageName: node + linkType: hard + +"@graphql-tools/url-loader@npm:7.13.2, @graphql-tools/url-loader@npm:^7.13.2, @graphql-tools/url-loader@npm:^7.9.7": version: 7.13.2 resolution: "@graphql-tools/url-loader@npm:7.13.2" dependencies: @@ -9404,32 +8895,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/url-loader@npm:^7.9.7": - version: 7.12.1 - resolution: "@graphql-tools/url-loader@npm:7.12.1" - dependencies: - "@graphql-tools/delegate": 8.8.0 - "@graphql-tools/utils": 8.8.0 - "@graphql-tools/wrap": 8.5.0 - "@n1ru4l/graphql-live-query": ^0.9.0 - "@types/ws": ^8.0.0 - cross-undici-fetch: ^0.4.11 - dset: ^3.1.2 - extract-files: ^11.0.0 - graphql-ws: ^5.4.1 - isomorphic-ws: ^5.0.0 - meros: ^1.1.4 - sync-fetch: ^0.4.0 - tslib: ^2.4.0 - value-or-promise: ^1.0.11 - ws: ^8.3.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 8b49650f08a175f006519d9c771cd20e0d8462e5c07c58e3e9acad76b56fca22a74cb452898d83535f5113030fe37d453d37554a4ece09d6baceb029788d545e - languageName: node - linkType: hard - -"@graphql-tools/utils@npm:8.12.0": +"@graphql-tools/utils@npm:8.12.0, @graphql-tools/utils@npm:^8.6.5, @graphql-tools/utils@npm:^8.8.0, @graphql-tools/utils@npm:^8.9.0": version: 8.12.0 resolution: "@graphql-tools/utils@npm:8.12.0" dependencies: @@ -9451,7 +8917,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:8.8.0, @graphql-tools/utils@npm:^8.6.5, @graphql-tools/utils@npm:^8.8.0": +"@graphql-tools/utils@npm:8.8.0": version: 8.8.0 resolution: "@graphql-tools/utils@npm:8.8.0" dependencies: @@ -9462,7 +8928,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:8.9.0, @graphql-tools/utils@npm:^8.9.0": +"@graphql-tools/utils@npm:8.9.0": version: 8.9.0 resolution: "@graphql-tools/utils@npm:8.9.0" dependencies: @@ -9473,22 +8939,29 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/wrap@npm:8.5.0": - version: 8.5.0 - resolution: "@graphql-tools/wrap@npm:8.5.0" +"@graphql-tools/utils@npm:9.1.0": + version: 9.1.0 + resolution: "@graphql-tools/utils@npm:9.1.0" dependencies: - "@graphql-tools/delegate": 8.8.0 - "@graphql-tools/schema": 8.5.0 - "@graphql-tools/utils": 8.8.0 tslib: ^2.4.0 - value-or-promise: 1.0.11 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: d2eaed461dad099f3f8b56ba9172b58967def4ebd32b2eacf906b9447025220a2f0a0782b42a087e5579383a67c8029cd451643ec8b751bff8ea778cdc0399da + checksum: dcf08df3bd1715e25e3b80bf2dd332376239ebcd2a9b93f4d6b72a7bd3feffe2207b9683bb8fcaed9d0d1286f701d0686fe99ac803b91c0df54509b869c0554d languageName: node linkType: hard -"@graphql-tools/wrap@npm:8.5.1": +"@graphql-tools/utils@npm:^9.1.1": + version: 9.1.1 + resolution: "@graphql-tools/utils@npm:9.1.1" + dependencies: + tslib: ^2.4.0 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 5a5120417c00b0f8a834b69dca9b7496022f8b1ed3719c2cf7de8253ff639ecc0f4a8e2bcaf0193ce44bd59431098180e94bdd96406e9f260e058b16c0e26975 + languageName: node + linkType: hard + +"@graphql-tools/wrap@npm:8.5.1, @graphql-tools/wrap@npm:^8.3.1": version: 8.5.1 resolution: "@graphql-tools/wrap@npm:8.5.1" dependencies: @@ -9503,21 +8976,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/wrap@npm:^8.3.1": - version: 8.4.16 - resolution: "@graphql-tools/wrap@npm:8.4.16" - dependencies: - "@graphql-tools/delegate": 8.7.7 - "@graphql-tools/schema": 8.3.10 - "@graphql-tools/utils": 8.6.9 - tslib: ~2.3.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: d369133824f44fbb5d0ab8d3dcd27c98594e082514acbaf6bb0fc0d178c34d214a80079235b3f26a8d04f860276782087d24bc9a10c016eaa60b6896781c8786 - languageName: node - linkType: hard - "@graphql-typed-document-node/core@npm:^3.1.0": version: 3.1.1 resolution: "@graphql-typed-document-node/core@npm:3.1.1" @@ -9527,16 +8985,6 @@ __metadata: languageName: node linkType: hard -"@grpc/grpc-js@npm:~1.6.0": - version: 1.6.7 - resolution: "@grpc/grpc-js@npm:1.6.7" - dependencies: - "@grpc/proto-loader": ^0.6.4 - "@types/node": ">=12.12.47" - checksum: 2668b08c2eec433970561384b22cf81443106835077ff1d8b7989cb5519fb7d2284c7a46b6ae94968f3b488ffbd9326ba9b4fbe4971a185d3b89eb0ee99e4fcd - languageName: node - linkType: hard - "@grpc/grpc-js@npm:~1.7.0": version: 1.7.0 resolution: "@grpc/grpc-js@npm:1.7.0" @@ -9547,21 +8995,6 @@ __metadata: languageName: node linkType: hard -"@grpc/proto-loader@npm:^0.6.4": - version: 0.6.12 - resolution: "@grpc/proto-loader@npm:0.6.12" - dependencies: - "@types/long": ^4.0.1 - lodash.camelcase: ^4.3.0 - long: ^4.0.0 - protobufjs: ^6.10.0 - yargs: ^16.2.0 - bin: - proto-loader-gen-types: build/bin/proto-loader-gen-types.js - checksum: 19bb53811e650e9a975cafa1e0cb084870235cff957695a38a8429c4a71435d584740c1d780fb51882ff4d4863cb9c81393d4dc25c55f5078be283f5ea5289a9 - languageName: node - linkType: hard - "@grpc/proto-loader@npm:^0.7.0": version: 0.7.2 resolution: "@grpc/proto-loader@npm:0.7.2" @@ -9593,21 +9026,14 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.10.4": - version: 0.10.4 - resolution: "@humanwhocodes/config-array@npm:0.10.4" +"@humanwhocodes/config-array@npm:^0.11.6": + version: 0.11.7 + resolution: "@humanwhocodes/config-array@npm:0.11.7" dependencies: "@humanwhocodes/object-schema": ^1.2.1 debug: ^4.1.1 - minimatch: ^3.0.4 - checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300 - languageName: node - linkType: hard - -"@humanwhocodes/gitignore-to-minimatch@npm:^1.0.2": - version: 1.0.2 - resolution: "@humanwhocodes/gitignore-to-minimatch@npm:1.0.2" - checksum: aba5c40c9e3770ed73a558b0bfb53323842abfc2ce58c91d7e8b1073995598e6374456d38767be24ab6176915f0a8d8b23eaae5c85e2b488c0dccca6d795e2ad + minimatch: ^3.0.5 + checksum: cf506dc45d9488af7fbf108ea6ac2151ba1a25e6d2b94b9b4fc36d2c1e4099b89ff560296dbfa13947e44604d4ca4a90d97a4fb167370bf8dd01a6ca2b6d83ac languageName: node linkType: hard @@ -9680,7 +9106,7 @@ __metadata: "@types/uuid": ^8.0.0 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 uuid: ^8.3.2 winston: ^3.2.1 @@ -9699,7 +9125,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -9721,7 +9147,7 @@ __metadata: "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -9987,19 +9413,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^27.2.5": - version: 27.2.5 - resolution: "@jest/types@npm:27.2.5" - dependencies: - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^16.0.0 - chalk: ^4.0.0 - checksum: 322603c24354a5333b5b7a670464422a46e0244a5a96a35552a7018eb4ac2e84c3b7657336b0ea6aa114963f9b6d0da8b8f6f963cb044fea9e7bc04d464b0ab1 - languageName: node - linkType: hard - "@jest/types@npm:^27.5.1": version: 27.5.1 resolution: "@jest/types@npm:27.5.1" @@ -10540,17 +9953,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.0": - version: 0.3.4 - resolution: "@jridgewell/trace-mapping@npm:0.3.4" - dependencies: - "@jridgewell/resolve-uri": ^3.0.3 - "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: ab8bce84bbbc8c34f3ba8325ed926f8f2d3098983c10442a80c55764c4eb6e47d5b92d8ff20a0dd868c3e76a3535651fd8a0138182c290dbfc8396195685c37b - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15": +"@jridgewell/trace-mapping@npm:^0.3.0, @jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.15 resolution: "@jridgewell/trace-mapping@npm:0.3.15" dependencies: @@ -10560,16 +9963,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.14 - resolution: "@jridgewell/trace-mapping@npm:0.3.14" - dependencies: - "@jridgewell/resolve-uri": ^3.0.3 - "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: b9537b9630ffb631aef9651a085fe361881cde1772cd482c257fe3c78c8fd5388d681f504a9c9fe1081b1c05e8f75edf55ee10fdb58d92bbaa8dbf6a7bd6b18c - languageName: node - linkType: hard - "@jsdevtools/ono@npm:^7.1.3": version: 7.1.3 resolution: "@jsdevtools/ono@npm:7.1.3" @@ -10584,16 +9977,26 @@ __metadata: languageName: node linkType: hard -"@keyv/redis@npm:^2.2.3": - version: 2.5.2 - resolution: "@keyv/redis@npm:2.5.2" +"@keyv/memcache@npm:^1.3.5": + version: 1.3.5 + resolution: "@keyv/memcache@npm:1.3.5" dependencies: - ioredis: ^5.2.3 - checksum: 2439e5097c6d4bf14e316b7a19d532287d43c5860f0614569f125a3c0a0a8c322610ed26b86b941b9aa9243ebf1e265c1d3f99a43da42d2150d02fc8fd2d94dd + json-buffer: ^3.0.1 + memjs: ^1.3.0 + checksum: c457863aeff1c5886c273eafa5fd79a4287cae1d9d3721b6ce5aa699033428ec8930db044224a6ab63d951cdac2408850737d0adc65f0a502bf04cd7dbe0d15e languageName: node linkType: hard -"@kubernetes/client-node@npm:^0.17.0": +"@keyv/redis@npm:^2.5.3": + version: 2.5.3 + resolution: "@keyv/redis@npm:2.5.3" + dependencies: + ioredis: ^5.2.4 + checksum: db6be54624320f5d03856985fee5151601fa278d63ef98feac12f89188fbf86b972e7f5ca3ece0d6137c81038b1eb3c42805beaf51c4c963cca35c2b7d68be92 + languageName: node + linkType: hard + +"@kubernetes/client-node@npm:0.17.0": version: 0.17.0 resolution: "@kubernetes/client-node@npm:0.17.0" dependencies: @@ -11031,17 +10434,7 @@ __metadata: languageName: node linkType: hard -"@mswjs/cookies@npm:^0.2.0": - version: 0.2.0 - resolution: "@mswjs/cookies@npm:0.2.0" - dependencies: - "@types/set-cookie-parser": ^2.4.0 - set-cookie-parser: ^2.4.6 - checksum: 218d169df02cda261e68e0203812a68affa6396d0041b23c70c4865cf757bebc47ffe3f66df39b94f666f004da42cb9b56e61f089b21c59e6cb88abce8537f19 - languageName: node - linkType: hard - -"@mswjs/cookies@npm:^0.2.2": +"@mswjs/cookies@npm:^0.2.0, @mswjs/cookies@npm:^0.2.2": version: 0.2.2 resolution: "@mswjs/cookies@npm:0.2.2" dependencies: @@ -11151,30 +10544,30 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.scandir@npm:2.1.3": - version: 2.1.3 - resolution: "@nodelib/fs.scandir@npm:2.1.3" +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" dependencies: - "@nodelib/fs.stat": 2.0.3 + "@nodelib/fs.stat": 2.0.5 run-parallel: ^1.1.9 - checksum: 0054efbba1385629886fe017d99f7045cb8300d6de1923f7a37e05e480c853abbedaff90f6a6b88fd0d406e1cd1e97fb60bd4e059b44468b174f46bef2e21dd1 + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 languageName: node linkType: hard -"@nodelib/fs.stat@npm:2.0.3, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.3 - resolution: "@nodelib/fs.stat@npm:2.0.3" - checksum: d3612efceea83fb0bec4e64967888ff0c3e5fbbae96121bc526bbbe5529f32fc6f8a785b550f397d20f09c84dc1e5a6c8e9fd7f9b8b62387a8f80f680be8430e +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.4 - resolution: "@nodelib/fs.walk@npm:1.2.4" +"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: - "@nodelib/fs.scandir": 2.1.3 + "@nodelib/fs.scandir": 2.1.5 fastq: ^1.6.0 - checksum: a971d1dcc1cf593e25651738e915be201053b63775c39c1ee221d2adee6316503ad6043136ceda0e099724875f2d72ea04b3b57c0e3a20b7f280bd3e951ae2e4 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 languageName: node linkType: hard @@ -11292,16 +10685,7 @@ __metadata: languageName: node linkType: hard -"@npmcli/move-file@npm:^1.0.1": - version: 1.0.1 - resolution: "@npmcli/move-file@npm:1.0.1" - dependencies: - mkdirp: ^1.0.4 - checksum: 878b39fc1f0b4c0b434ef0a97b80149fb74c5ec06246280238a2bc5f562a3c5e758e31f583c6431eb916537c1505697e4ac7b9f9e68cb28951bf7eb8150de5f0 - languageName: node - linkType: hard - -"@npmcli/move-file@npm:^1.1.0": +"@npmcli/move-file@npm:^1.0.1, @npmcli/move-file@npm:^1.1.0": version: 1.1.2 resolution: "@npmcli/move-file@npm:1.1.2" dependencies: @@ -11506,7 +10890,7 @@ __metadata: languageName: node linkType: hard -"@octokit/core@npm:^4.0.0": +"@octokit/core@npm:^4.0.0, @octokit/core@npm:^4.0.4": version: 4.0.5 resolution: "@octokit/core@npm:4.0.5" dependencies: @@ -11521,21 +10905,6 @@ __metadata: languageName: node linkType: hard -"@octokit/core@npm:^4.0.4": - version: 4.0.4 - resolution: "@octokit/core@npm:4.0.4" - dependencies: - "@octokit/auth-token": ^3.0.0 - "@octokit/graphql": ^5.0.0 - "@octokit/request": ^6.0.0 - "@octokit/request-error": ^3.0.0 - "@octokit/types": ^6.0.3 - before-after-hook: ^2.2.0 - universal-user-agent: ^6.0.0 - checksum: c9ae1e5706ab568a725cc5dba314049fbd37d77f1595dd2c19733abddfd72f4e1d46d6980e212d845dde4625ce5f170af951ac0eb0d7bc09e56a159b88cbe5dd - languageName: node - linkType: hard - "@octokit/endpoint@npm:^6.0.1": version: 6.0.12 resolution: "@octokit/endpoint@npm:6.0.12" @@ -11570,13 +10939,13 @@ __metadata: linkType: hard "@octokit/graphql@npm:^5.0.0": - version: 5.0.1 - resolution: "@octokit/graphql@npm:5.0.1" + version: 5.0.4 + resolution: "@octokit/graphql@npm:5.0.4" dependencies: "@octokit/request": ^6.0.0 - "@octokit/types": ^7.0.0 + "@octokit/types": ^8.0.0 universal-user-agent: ^6.0.0 - checksum: 310549c2d7966adb46428e943cd99cb766519819bd4945d8349d3ec0642e4ee39d9194e1b0a87a5404951c04c247fafb4a8456ed4c839c64bfb4042aa4a6812c + checksum: 8cf65cf7e6608cf3cbc96a2fa902172b4d5dc30e88ee0bae3711bf467a25b828b10cce1aaabb7f82a7580bfbcf7028b91d1dd1a894940945e38ca2deb6509754 languageName: node linkType: hard @@ -11641,13 +11010,6 @@ __metadata: languageName: node linkType: hard -"@octokit/openapi-types@npm:^11.2.0": - version: 11.2.0 - resolution: "@octokit/openapi-types@npm:11.2.0" - checksum: eb373ea496bc96bf0233505a0916eb38cb193d1829cab935e1cf1fd21839c402a1d835d3c0326290c756c0ed980a64d0ae73ad3c5d5decde9000f0828aa7ff52 - languageName: node - linkType: hard - "@octokit/openapi-types@npm:^12.11.0": version: 12.11.0 resolution: "@octokit/openapi-types@npm:12.11.0" @@ -11669,13 +11031,6 @@ __metadata: languageName: node linkType: hard -"@octokit/openapi-types@npm:^7.3.2": - version: 7.4.0 - resolution: "@octokit/openapi-types@npm:7.4.0" - checksum: a480cd1fb3d167b9a55e9cc1a8112086b00a0be67e4010d4b05009ed2fff9e70d21ffad293fbbf5f35c66e64b263eb61277f99926044c6b4d956ada6791eb89e - languageName: node - linkType: hard - "@octokit/plugin-paginate-rest@npm:^2.6.2": version: 2.7.0 resolution: "@octokit/plugin-paginate-rest@npm:2.7.0" @@ -11709,16 +11064,7 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-request-log@npm:^1.0.2": - version: 1.0.2 - resolution: "@octokit/plugin-request-log@npm:1.0.2" - peerDependencies: - "@octokit/core": ">=3" - checksum: b28fc7b588b8a205396b01b6be61c2aeac6f2a67180aec1d8185b3e0df7eae7b355a8dddcab8dd3b250de0eba90bdd7fa1daff5ec76ff03491f7707b3544a79f - languageName: node - linkType: hard - -"@octokit/plugin-request-log@npm:^1.0.4": +"@octokit/plugin-request-log@npm:^1.0.2, @octokit/plugin-request-log@npm:^1.0.4": version: 1.0.4 resolution: "@octokit/plugin-request-log@npm:1.0.4" peerDependencies: @@ -11856,16 +11202,7 @@ __metadata: languageName: node linkType: hard -"@octokit/types@npm:^6.0.0, @octokit/types@npm:^6.0.1, @octokit/types@npm:^6.10.0, @octokit/types@npm:^6.12.2, @octokit/types@npm:^6.14.2, @octokit/types@npm:^6.16.2, @octokit/types@npm:^6.8.2": - version: 6.16.4 - resolution: "@octokit/types@npm:6.16.4" - dependencies: - "@octokit/openapi-types": ^7.3.2 - checksum: 872dadb1566b874724e6b30a14cf91ae1a9f8664aaaa9d1bb94ce78466291d8cc83ca47aa5bb5baa6260e71fe42100c84f7d52c2df52938dbc9c86359c38cb70 - languageName: node - linkType: hard - -"@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.16.1, @octokit/types@npm:^6.39.0": +"@octokit/types@npm:^6.0.0, @octokit/types@npm:^6.0.1, @octokit/types@npm:^6.0.3, @octokit/types@npm:^6.10.0, @octokit/types@npm:^6.12.2, @octokit/types@npm:^6.14.2, @octokit/types@npm:^6.16.1, @octokit/types@npm:^6.16.2, @octokit/types@npm:^6.27.1, @octokit/types@npm:^6.39.0, @octokit/types@npm:^6.8.2": version: 6.41.0 resolution: "@octokit/types@npm:6.41.0" dependencies: @@ -11874,15 +11211,6 @@ __metadata: languageName: node linkType: hard -"@octokit/types@npm:^6.27.1": - version: 6.34.0 - resolution: "@octokit/types@npm:6.34.0" - dependencies: - "@octokit/openapi-types": ^11.2.0 - checksum: f122b9aee8f6baddd515e34a0913e73b21d4bc82d6ee59d77a8aaf01b4a02c10867dd013003d087a83dc96db23511893669015af6d30c27cece185e21cf1df89 - languageName: node - linkType: hard - "@octokit/types@npm:^7.0.0": version: 7.0.0 resolution: "@octokit/types@npm:7.0.0" @@ -11970,14 +11298,15 @@ __metadata: linkType: hard "@opensearch-project/opensearch@npm:^2.0.0": - version: 2.0.0 - resolution: "@opensearch-project/opensearch@npm:2.0.0" + version: 2.1.0 + resolution: "@opensearch-project/opensearch@npm:2.1.0" dependencies: + aws4: ^1.11.0 debug: ^4.3.1 hpagent: ^0.1.1 ms: ^2.1.3 secure-json-parse: ^2.4.0 - checksum: 7e0e7ae6ac8b6789f7fac59d66ef8afb960cdff46a5d201d9fb447270b808a5e0fd725b75e5fc647974b1b86e5a048e1e9d79aed04b11a424e14ec30079f2e44 + checksum: 900b90f35d5b960fe60979168e21e9e5b6089a8e3dd9341b5d86c7f7aa7671cbfd937fbec311a6cfe195c113db755e699d3678ee0cbf454e9a9de1189d8cc935 languageName: node linkType: hard @@ -12046,8 +11375,8 @@ __metadata: linkType: hard "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.7": - version: 0.5.8 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.8" + version: 0.5.9 + resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.9" dependencies: ansi-html-community: ^0.0.8 common-path-prefix: ^3.0.0 @@ -12055,7 +11384,7 @@ __metadata: error-stack-parser: ^2.0.6 find-up: ^5.0.0 html-entities: ^2.1.0 - loader-utils: ^2.0.0 + loader-utils: ^2.0.3 schema-utils: ^3.0.0 source-map: ^0.7.3 peerDependencies: @@ -12080,7 +11409,7 @@ __metadata: optional: true webpack-plugin-serve: optional: true - checksum: 48d8b2813dfba7d482e58a2b0161b79e3a5d608603f1a3c34d709ecc2e6e08f8b14f79934c57849d06f153eb327f18e3d8e1539f978e40ca91539c342f27b8ae + checksum: 446c0add9ecf17ed9911bf310bf22ab64f4b3d0ce334e68a3fcac5efee782ef4d7b6260997efaf720c7a2ea39086db89629e4aa07fb18558387d8dc8f0f31da2 languageName: node linkType: hard @@ -12180,9 +11509,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.10": - version: 5.0.0-beta.10 - resolution: "@rjsf/core@npm:5.0.0-beta.10" +"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/core@npm:5.0.0-beta.12" dependencies: lodash: ^4.17.15 lodash-es: ^4.17.15 @@ -12191,7 +11520,7 @@ __metadata: peerDependencies: "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: c3e8852c8fedc6ae23da610033e0bded1bd198cebf7f54a5cdcf3b42d22a3b3864da9c735300cadc7d756f26055a7e62408d51a5ebdb906be9b1bf85bf3712ed + checksum: 6c3fe058a29716cb8d31d436e284aa7ab51ec3c272dc34d49275ea0033c3350a2486249767d454bca20a4ccd00ed910f7ed518d2ebe30693b0218db1b3c990ac languageName: node linkType: hard @@ -12214,16 +11543,16 @@ __metadata: languageName: node linkType: hard -"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.10": - version: 5.0.0-beta.10 - resolution: "@rjsf/material-ui@npm:5.0.0-beta.10" +"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/material-ui@npm:5.0.0-beta.12" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.0.0-beta.1 "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: c6e602fc331ec37524837123f42e605389c8ea1a9207ed3e9052de380b91fb90365aa962b0020197f0fb2bcbd87baac34bef7dbbb31ea4b57b6587d0fcd81a09 + checksum: 9b67c64956e74af6230d722fe9510fc50e6133c6913642f5bcbcb8da38b7ff5d912bc90a6b6692eb3df315ba9b330136556fb41854fb351e432433d584c1a969 languageName: node linkType: hard @@ -12239,9 +11568,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:^5.0.0-beta.10": - version: 5.0.0-beta.11 - resolution: "@rjsf/utils@npm:5.0.0-beta.11" +"@rjsf/utils@npm:^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/utils@npm:5.0.0-beta.12" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -12250,21 +11579,21 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: 4e77616023b5cf193e1631a4d5fb8d54122d9f48e30ce2fcb1b22f057e2dcf37aae174f25f1afddb664b0114e461f9d738fa282995b07e9e3eb30f7469d77145 + checksum: b9698a2238dd5d3c79c13b84d92587825005938cd449680204903463b6fc6f63165fb715ea1e50a94e6764aa405be2b2ac2e6aad8bc68cd50623f065fd6f979a languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:^5.0.0-beta.10": - version: 5.0.0-beta.11 - resolution: "@rjsf/validator-ajv8@npm:5.0.0-beta.11" +"@rjsf/validator-ajv8@npm:^5.0.0-beta.12": + version: 5.0.0-beta.13 + resolution: "@rjsf/validator-ajv8@npm:5.0.0-beta.13" dependencies: - ajv: ^8.11.0 ajv-formats: ^2.1.1 + ajv8: "npm:ajv@^8.11.0" lodash: ^4.17.15 lodash-es: ^4.17.15 peerDependencies: - "@rjsf/utils": ^5.0.0-beta.1 - checksum: e9aec2e77c69ee55fd35cc82b2c3fe0c78cf021145500bc86f7e0a5bae794163dfae198df0543ce635e22cd4235880dcbb7c73487ae0baae6b03e1bdea2955c4 + "@rjsf/utils": ^5.0.0-beta.12 + checksum: e0a51e25845745da628794dadef2c7ffc910d26cb99a90fa763d4a5593b554b084c578a73ed688d02defbeb5ddec38066caae527f5dc8dabba7f012cec31e8a3 languageName: node linkType: hard @@ -12293,8 +11622,8 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-github-insights@npm:^2.0.5": - version: 2.1.0 - resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.1.0" + version: 2.1.1 + resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.1.1" dependencies: "@backstage/catalog-model": ^1.1.2 "@backstage/core-components": ^0.11.2 @@ -12316,7 +11645,7 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 33ba1f1cf2370bd0af8cd3b9ed117f432de13be7b7a17dc23d427195826a66f696d0dcf916e6105c02b595d6c1eb151e4d280c8f248f75e8cfff05e8480c7cd8 + checksum: 95f02d4e51e88c7e3acf04b4fa54e68bf20800f0c21a22c4231bc6400cfae0cc11e7f0779f6d82e4d76eb6e97c25e7bd4ca869ada14e668d42741fd9b89f7351 languageName: node linkType: hard @@ -12445,17 +11774,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^4.1.1": - version: 4.1.1 - resolution: "@rollup/pluginutils@npm:4.1.1" - dependencies: - estree-walker: ^2.0.1 - picomatch: ^2.2.2 - checksum: 405f681c7d32661980aa3caa928ff22e1c06f0e081db1550e6ab9c179dc9d3d8d63c05dcc7338fe65ab3f856a56c465696a51300b83e98171956fcb141106e39 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^4.2.1": +"@rollup/pluginutils@npm:^4.1.1, @rollup/pluginutils@npm:^4.2.1": version: 4.2.1 resolution: "@rollup/pluginutils@npm:4.2.1" dependencies: @@ -12570,7 +11889,16 @@ __metadata: languageName: node linkType: hard -"@sinonjs/samsam@npm:^6.1.1": +"@sinonjs/fake-timers@npm:^7.1.2": + version: 7.1.2 + resolution: "@sinonjs/fake-timers@npm:7.1.2" + dependencies: + "@sinonjs/commons": ^1.7.0 + checksum: c84773d7973edad5511a31d2cc75023447b5cf714a84de9bb50eda45dda88a0d3bd2c30bf6e6e936da50a048d5352e2151c694e13e59b97d187ba1f329e9a00c + languageName: node + linkType: hard + +"@sinonjs/samsam@npm:^6.0.2, @sinonjs/samsam@npm:^6.1.1": version: 6.1.1 resolution: "@sinonjs/samsam@npm:6.1.1" dependencies: @@ -12822,137 +12150,95 @@ __metadata: languageName: node linkType: hard -"@swc/core-android-arm-eabi@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-android-arm-eabi@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.122 - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@swc/core-android-arm64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-android-arm64@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@swc/core-darwin-arm64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-darwin-arm64@npm:1.3.9" +"@swc/core-darwin-arm64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-arm64@npm:1.3.16" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-darwin-x64@npm:1.3.9" +"@swc/core-darwin-x64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-x64@npm:1.3.16" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-freebsd-x64@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-freebsd-x64@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@swc/core-linux-arm-gnueabihf@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-linux-arm-gnueabihf@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.16" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9" +"@swc/core-linux-arm64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.9" +"@swc/core-linux-arm64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.9" +"@swc/core-linux-x64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-linux-x64-musl@npm:1.3.9" +"@swc/core-linux-x64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-musl@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-win32-arm64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.16" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9" - dependencies: - "@swc/wasm": 1.2.130 +"@swc/core-win32-ia32-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.16" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.9": - version: 1.3.9 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.9" +"@swc/core-win32-x64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.16" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.9": - version: 1.3.9 - resolution: "@swc/core@npm:1.3.9" + version: 1.3.16 + resolution: "@swc/core@npm:1.3.16" dependencies: - "@swc/core-android-arm-eabi": 1.3.9 - "@swc/core-android-arm64": 1.3.9 - "@swc/core-darwin-arm64": 1.3.9 - "@swc/core-darwin-x64": 1.3.9 - "@swc/core-freebsd-x64": 1.3.9 - "@swc/core-linux-arm-gnueabihf": 1.3.9 - "@swc/core-linux-arm64-gnu": 1.3.9 - "@swc/core-linux-arm64-musl": 1.3.9 - "@swc/core-linux-x64-gnu": 1.3.9 - "@swc/core-linux-x64-musl": 1.3.9 - "@swc/core-win32-arm64-msvc": 1.3.9 - "@swc/core-win32-ia32-msvc": 1.3.9 - "@swc/core-win32-x64-msvc": 1.3.9 + "@swc/core-darwin-arm64": 1.3.16 + "@swc/core-darwin-x64": 1.3.16 + "@swc/core-linux-arm-gnueabihf": 1.3.16 + "@swc/core-linux-arm64-gnu": 1.3.16 + "@swc/core-linux-arm64-musl": 1.3.16 + "@swc/core-linux-x64-gnu": 1.3.16 + "@swc/core-linux-x64-musl": 1.3.16 + "@swc/core-win32-arm64-msvc": 1.3.16 + "@swc/core-win32-ia32-msvc": 1.3.16 + "@swc/core-win32-x64-msvc": 1.3.16 dependenciesMeta: - "@swc/core-android-arm-eabi": - optional: true - "@swc/core-android-arm64": - optional: true "@swc/core-darwin-arm64": optional: true "@swc/core-darwin-x64": optional: true - "@swc/core-freebsd-x64": - optional: true "@swc/core-linux-arm-gnueabihf": optional: true "@swc/core-linux-arm64-gnu": @@ -12971,16 +12257,16 @@ __metadata: optional: true bin: swcx: run_swcx.js - checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa + checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13 languageName: node linkType: hard "@swc/helpers@npm:^0.4.7": - version: 0.4.12 - resolution: "@swc/helpers@npm:0.4.12" + version: 0.4.14 + resolution: "@swc/helpers@npm:0.4.14" dependencies: tslib: ^2.4.0 - checksum: 3f9112f37d87815b6d4270137fc78d22bb98c75138e9b0eac7cac203ec2cf2bffbf13b20a713067c292affd5e9e70a724eb245b8daf0963e7fe528b901771c28 + checksum: 273fd3f3fc461a92f3790cc551ea054745c6d6959afbe1232e6d7aa1c722bbc114d308aab96bef5c78fc0303c85c7b472ef00e2253251cc89737f3b1af56e5a5 languageName: node linkType: hard @@ -12996,20 +12282,6 @@ __metadata: languageName: node linkType: hard -"@swc/wasm@npm:1.2.122": - version: 1.2.122 - resolution: "@swc/wasm@npm:1.2.122" - checksum: 563345370c5ad18373d3b403590ab880fe52dcd8fc8c8601be263fcd9886520b28a7f4e46236cf49ca2b136c79d4ef50c960bc34b7cdc2068118b0d84dfca1f4 - languageName: node - linkType: hard - -"@swc/wasm@npm:1.2.130": - version: 1.2.130 - resolution: "@swc/wasm@npm:1.2.130" - checksum: 02203bfef3e382c64cbbd63c138c8fdf61865e74d923b317e9d9e9f33f5a3f0a9533b5fdbc9505e76d78e864be04a82fc847eb987a1e47ccac5850146c858292 - languageName: node - linkType: hard - "@szmarczak/http-timer@npm:^4.0.5": version: 4.0.5 resolution: "@szmarczak/http-timer@npm:4.0.5" @@ -13019,18 +12291,18 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:4.13.0": - version: 4.13.0 - resolution: "@tanstack/query-core@npm:4.13.0" - checksum: 11cb95be4dc6e1ba3f0f4eb04c255eab7fa5eca3441d6e698e2c6d03c84c03efaf34d475594e259593d76f584af0c0e830c7d868a682d6dc0f61d1a439728d12 +"@tanstack/query-core@npm:4.14.5": + version: 4.14.5 + resolution: "@tanstack/query-core@npm:4.14.5" + checksum: 25af0f4999668cd66a4a54c2d2d64dd7002f4852fb901d1d1d64908da4ea43d63e53e512b536987a789039713ffc6ae4ffa2d41cfab676b01704f4937be18a04 languageName: node linkType: hard "@tanstack/react-query@npm:^4.1.3": - version: 4.13.0 - resolution: "@tanstack/react-query@npm:4.13.0" + version: 4.14.6 + resolution: "@tanstack/react-query@npm:4.14.6" dependencies: - "@tanstack/query-core": 4.13.0 + "@tanstack/query-core": 4.14.5 use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -13041,7 +12313,7 @@ __metadata: optional: true react-native: optional: true - checksum: e538b585e4c2b4a8ff84c17509f4ce226e18e3e862553b6a9ca90e29c200db4ec7ab4f400f19ef4846a76c51babe0db120c54779054805fbecdcd29b369caf0e + checksum: 38e293616aa04ccfe2fec47315c5b98f0b157ee6548b4dbb6a8ca01c90de113e437f5effbc82884f2d860bde54eeb07335e9ed4e233543c7039f717d9855ab9e languageName: node linkType: hard @@ -13698,23 +12970,13 @@ __metadata: languageName: node linkType: hard -"@types/dockerode@npm:^3.3.0": - version: 3.3.10 - resolution: "@types/dockerode@npm:3.3.10" +"@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.8": + version: 3.3.13 + resolution: "@types/dockerode@npm:3.3.13" dependencies: "@types/docker-modem": "*" "@types/node": "*" - checksum: ef2231adebbdc1876a00fd16a51963ed2ea05a2305031467420c753f77a27a6f2a47617e2f4a42702be84c88046a5a5f6dfd471e3579f11f21166f539a3d2373 - languageName: node - linkType: hard - -"@types/dockerode@npm:^3.3.8": - version: 3.3.9 - resolution: "@types/dockerode@npm:3.3.9" - dependencies: - "@types/docker-modem": "*" - "@types/node": "*" - checksum: 3d03c68addb37c50e9557fff17171d26423aa18e544cb24e4caa81ebcec39ccc1cafed7adbfb8f4220d8ed23028d231717826bb77a786d425885c4f4cc37536d + checksum: dbcf3e33f5d8b731a1540d8b72c91d12583eb87d47adf8defb71f8bc1b328a26a035c66068255929ef99a7906da53ac6e4be76099e8fa7e9720c134b1ab3e153 languageName: node linkType: hard @@ -13775,18 +13037,7 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.18": - version: 4.17.29 - resolution: "@types/express-serve-static-core@npm:4.17.29" - dependencies: - "@types/node": "*" - "@types/qs": "*" - "@types/range-parser": "*" - checksum: ec4194dc59276ec6dd906887fc377be0cadf4aaa4d535d9052ab9624937ef2b984a8d9da2c11c96979e21f3d9f78f1da93e767dbcec637f7f13d2e3003151145 - languageName: node - linkType: hard - -"@types/express-serve-static-core@npm:4.17.31, @types/express-serve-static-core@npm:^4.17.5": +"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:4.17.31, @types/express-serve-static-core@npm:^4.17.18, @types/express-serve-static-core@npm:^4.17.5": version: 4.17.31 resolution: "@types/express-serve-static-core@npm:4.17.31" dependencies: @@ -13954,11 +13205,11 @@ __metadata: linkType: hard "@types/inquirer@npm:^8.1.3": - version: 8.2.4 - resolution: "@types/inquirer@npm:8.2.4" + version: 8.2.5 + resolution: "@types/inquirer@npm:8.2.5" dependencies: "@types/through": "*" - checksum: 3a46231faac1e5df4863a2d501617b3f25e9481ea8a966a9b866bafef01fcc151606d9f25cb66f90492dd0d1d7af7c675a2314f50db85a7f2aeed265d93eb412 + checksum: 932c432e634697bcff5d50fdc9e64f90d2e31c5ebcda909f2e9704d0433b5ec608b6ece985c6e57a283f3b62434f1cd3619b64ca61433d7c3bdb41d3c5f27586 languageName: node linkType: hard @@ -14014,17 +13265,7 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:*": - version: 27.4.1 - resolution: "@types/jest@npm:27.4.1" - dependencies: - jest-matcher-utils: ^27.0.0 - pretty-format: ^27.0.0 - checksum: 5184f3eef4832d01ee8f59bed15eec45ccc8e29c724a5e6ce37bf74396b37bdf04f557000f45ba4fc38ae6075cf9cfcce3d7a75abc981023c61ceb27230a93e4 - languageName: node - linkType: hard - -"@types/jest@npm:^29.0.0": +"@types/jest@npm:*, @types/jest@npm:^29.0.0": version: 29.0.3 resolution: "@types/jest@npm:29.0.3" dependencies: @@ -14143,11 +13384,11 @@ __metadata: linkType: hard "@types/ldapjs@npm:^2.2.0": - version: 2.2.4 - resolution: "@types/ldapjs@npm:2.2.4" + version: 2.2.5 + resolution: "@types/ldapjs@npm:2.2.5" dependencies: "@types/node": "*" - checksum: 3f240809927e1292380e5977579d7edffb6e5e41b35510c7091b51da19e7387d4ebff0f254c0b145f3cf5d5485b6bb39c77335d857d092e6f4e9ce5a6682a872 + checksum: 779e462f118f8a6643b7f49d35646e4dae339ff1c6290198950327a736a79bc03beca882e1356ede4c8d54f6dc19bf544f0d23b09279558d69222a93bacd459c languageName: node linkType: hard @@ -14186,17 +13427,10 @@ __metadata: languageName: node linkType: hard -"@types/luxon@npm:*": - version: 3.0.1 - resolution: "@types/luxon@npm:3.0.1" - checksum: a81444f9b474ea9b3063ab4cc68b917a2634e38b4e229f86c78c35023a32bf5e8d1044d7c229c011291662c976cb6c4cf109dc3d2077c571790a31779a554178 - languageName: node - linkType: hard - -"@types/luxon@npm:^3.0.0": - version: 3.0.2 - resolution: "@types/luxon@npm:3.0.2" - checksum: e47e199c5d70ce16e4eff54b21fdf385065f1134774109b40c36dba8b5fd29a732b763125e93863d6070dd22ba6a3f18dbdd368cf3748aae9f24bb335c5c210d +"@types/luxon@npm:*, @types/luxon@npm:^3.0.0": + version: 3.1.0 + resolution: "@types/luxon@npm:3.1.0" + checksum: 04768029342ad76fc2a9339436c143ea64797b35cf9b03ddded787c13eae30f0ca1246e51c2c5365ed912f98068e13a967a3931b137eb4585248a0ad7ec3fa86 languageName: node linkType: hard @@ -14247,20 +13481,20 @@ __metadata: languageName: node linkType: hard -"@types/minimatch@npm:*, @types/minimatch@npm:^3.0.3, @types/minimatch@npm:^3.0.5": - version: 3.0.5 - resolution: "@types/minimatch@npm:3.0.5" - checksum: c41d136f67231c3131cf1d4ca0b06687f4a322918a3a5adddc87ce90ed9dbd175a3610adee36b106ae68c0b92c637c35e02b58c8a56c424f71d30993ea220b92 - languageName: node - linkType: hard - -"@types/minimatch@npm:^5.0.0": +"@types/minimatch@npm:*, @types/minimatch@npm:^5.0.0": version: 5.1.2 resolution: "@types/minimatch@npm:5.1.2" checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 languageName: node linkType: hard +"@types/minimatch@npm:^3.0.3, @types/minimatch@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/minimatch@npm:3.0.5" + checksum: c41d136f67231c3131cf1d4ca0b06687f4a322918a3a5adddc87ce90ed9dbd175a3610adee36b106ae68c0b92c637c35e02b58c8a56c424f71d30993ea220b92 + languageName: node + linkType: hard + "@types/minimist@npm:^1.2.0": version: 1.2.2 resolution: "@types/minimist@npm:1.2.2" @@ -14269,11 +13503,11 @@ __metadata: linkType: hard "@types/minipass@npm:*": - version: 3.3.5 - resolution: "@types/minipass@npm:3.3.5" + version: 3.1.2 + resolution: "@types/minipass@npm:3.1.2" dependencies: - minipass: "*" - checksum: 160f4ae5416697c947e0c0ee1225fe25973acf73a30d01bdf202447f12bd32ba3ea33d2fc4f2517a038dc408022a5aff5f7a1d92da0157a9b04276d1b0209550 + "@types/node": "*" + checksum: 0d01e11b5b959625385a482ad29ea16352be42506b459555b0f77fd82235e9c540946cc9c05a73fed1ae30b132914baaa4ccf257ed2cad20bc9773f0a06f4bac languageName: node linkType: hard @@ -14331,10 +13565,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": - version: 17.0.25 - resolution: "@types/node@npm:17.0.25" - checksum: 6a820bd624e69ea772f52a6cdb326484eff5829443dc981939373929ade109f58c21698b9f0a831bd6ceea799e722a75dc49c5fa7a6bc32a81e1cbdfc6507b64 +"@types/node@npm:*, @types/node@npm:>= 8, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": + version: 18.11.9 + resolution: "@types/node@npm:18.11.9" + checksum: cc0aae109e9b7adefc32eecb838d6fad931663bb06484b5e9cbbbf74865c721b03d16fd8d74ad90e31dbe093d956a7c2c306ba5429ba0c00f3f7505103d7a496 languageName: node linkType: hard @@ -14345,13 +13579,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:>= 8": - version: 18.7.4 - resolution: "@types/node@npm:18.7.4" - checksum: 051d2147e4d8129fceb63ee9384259b2f224dbc4e4b0c46d96a6b61cbaad4e3fe4060950e7f4fc3d5692b1e6ea47e68ad03b61155754bfa169593747cfe3f8f4 - languageName: node - linkType: hard - "@types/node@npm:^10.1.0, @types/node@npm:^10.12.0": version: 10.17.60 resolution: "@types/node@npm:10.17.60" @@ -14360,16 +13587,16 @@ __metadata: linkType: hard "@types/node@npm:^12.7.1": - version: 12.20.48 - resolution: "@types/node@npm:12.20.48" - checksum: 48bd705bda1af2332c50fb24819bba7b0eac791b07c24c098c39b10940170a53bd3c4755aedc3409c7114c539f1f86ea657aa6838d164fd135e3b89b9f9aa772 + version: 12.20.55 + resolution: "@types/node@npm:12.20.55" + checksum: e4f86785f4092706e0d3b0edff8dca5a13b45627e4b36700acd8dfe6ad53db71928c8dee914d4276c7fd3b6ccd829aa919811c9eb708a2c8e4c6eb3701178c37 languageName: node linkType: hard "@types/node@npm:^14.14.31": - version: 14.18.16 - resolution: "@types/node@npm:14.18.16" - checksum: 1999799309dc8620a2adf9a5d5e48416af87321bae4c950b4aa8018fcef2c3b6c1fcf98c39eae06f6492c03a643a5a44e2bb3750cd2574d9cf7eac33bac50e24 + version: 14.18.33 + resolution: "@types/node@npm:14.18.33" + checksum: 4e23f95186d8ae1d38c999bc6b46fe94e790da88744b0a3bfeedcbd0d9ffe2cb0ff39e85f43014f6739e5270292c1a1f6f97a1fc606fd573a0c17fda9a1d42de languageName: node linkType: hard @@ -14381,9 +13608,9 @@ __metadata: linkType: hard "@types/node@npm:^16.0.0, @types/node@npm:^16.11.26, @types/node@npm:^16.9.2": - version: 16.11.56 - resolution: "@types/node@npm:16.11.56" - checksum: b4efade16eb08a39810921c54a1637e69c8f3184a20d87e8fe74d557d9bda73f0829ac318e2a30a32b1903e4b099812defd1dfe438be70b98dbfbea5b0d99a53 + version: 16.18.3 + resolution: "@types/node@npm:16.18.3" + checksum: 6b8ba2ea5d842f7986e366cb9184c54d273d492784dc62e08fd5afeae938d9b61aec6e4222d2541cd18f9b1412ba361bbcb3f4204fb003608af80a2a6af959f9 languageName: node linkType: hard @@ -14472,18 +13699,7 @@ __metadata: languageName: node linkType: hard -"@types/passport-oauth2@npm:*": - version: 1.4.9 - resolution: "@types/passport-oauth2@npm:1.4.9" - dependencies: - "@types/express": "*" - "@types/oauth": "*" - "@types/passport": "*" - checksum: a7dc84ba1c166c73445974c138f7776be39e9c04e0f66ae84a55c89d91292f1cc30ea063c250183c4557fe35ecbdb581b0b28cc958217aff211aa6fa45889767 - languageName: node - linkType: hard - -"@types/passport-oauth2@npm:^1.4.11": +"@types/passport-oauth2@npm:*, @types/passport-oauth2@npm:^1.4.11": version: 1.4.11 resolution: "@types/passport-oauth2@npm:1.4.11" dependencies: @@ -14514,16 +13730,7 @@ __metadata: languageName: node linkType: hard -"@types/passport@npm:*": - version: 1.0.10 - resolution: "@types/passport@npm:1.0.10" - dependencies: - "@types/express": "*" - checksum: bd9704b64db7a16d53bd547bb436fb5a1cf9747dbe888a10b124603aeccf297f162a5b0854409cd6ee6bff1a8e9cdf989b07738f600f37949abfa8f8e5960deb - languageName: node - linkType: hard - -"@types/passport@npm:^1.0.3": +"@types/passport@npm:*, @types/passport@npm:^1.0.3": version: 1.0.11 resolution: "@types/passport@npm:1.0.11" dependencies: @@ -14661,13 +13868,13 @@ __metadata: linkType: hard "@types/react@npm:^17": - version: 17.0.45 - resolution: "@types/react@npm:17.0.45" + version: 17.0.52 + resolution: "@types/react@npm:17.0.52" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 3cc13a02824c13f6fa4807a83abd065ac1d9943359e76bd995cc7cd2b4148c1176ebd54a30a9f4eb8a0f141ff359d712876f256c4fee707e4290607ef8410b3e + checksum: a51b98dd87838d161278fdf9dd78e6a4ff8c018f406d6647f77963e144fb52a8beee40c89fd0e7e840eaeaa8bd9fe2f34519410540b1a52d43a6f8b4d2fbce33 languageName: node linkType: hard @@ -14698,14 +13905,14 @@ __metadata: linkType: hard "@types/request@npm:^2.47.1": - version: 2.48.5 - resolution: "@types/request@npm:2.48.5" + version: 2.48.8 + resolution: "@types/request@npm:2.48.8" dependencies: "@types/caseless": "*" "@types/node": "*" "@types/tough-cookie": "*" form-data: ^2.5.0 - checksum: 02572a0558b9a95ae1a2fa3912b45c4c12f587e25773b2d9bdbf5dfa6f2da5e3787d22256ee0dc4836250f39cf2dcb39fc4ded5bf554c0f948a623c8772e8bd3 + checksum: 0b7754941e08205dce51635d894ec524df276d2b83ca13b9aab723f9281acecf1108841e9554494cb1cb60f6d6ddbb47ebea97392bcf2bf607f035b3a9b4af45 languageName: node linkType: hard @@ -14783,10 +13990,10 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.8": - version: 7.3.12 - resolution: "@types/semver@npm:7.3.12" - checksum: 35536b2fc5602904f21cae681f6c9498e177dab3f54ae37c92f9a1b7e43c35f18bcd81e1c98c1cf0d33ee046bb06c771e9928c1c00a401d56a03f56549252a15 +"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.8": + version: 7.3.13 + resolution: "@types/semver@npm:7.3.13" + checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 languageName: node linkType: hard @@ -14808,17 +14015,7 @@ __metadata: languageName: node linkType: hard -"@types/serve-static@npm:*": - version: 1.13.9 - resolution: "@types/serve-static@npm:1.13.9" - dependencies: - "@types/mime": ^1 - "@types/node": "*" - checksum: 5c5f3b64e9fe7c51fb428ef70f1f2365b897fc3c8400be6d6afc8db0f152639182b360361ebd3d0cbaeb607b125dee03bf0c50bf7e08642ff150028f05bb7381 - languageName: node - linkType: hard - -"@types/serve-static@npm:^1.13.10": +"@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10": version: 1.13.10 resolution: "@types/serve-static@npm:1.13.10" dependencies: @@ -14837,6 +14034,22 @@ __metadata: languageName: node linkType: hard +"@types/sinon@npm:^10.0.10": + version: 10.0.13 + resolution: "@types/sinon@npm:10.0.13" + dependencies: + "@types/sinonjs__fake-timers": "*" + checksum: 46a14c888db50f0098ec53d451877e0111d878ec4a653b9e9ed7f8e54de386d6beb0e528ddc3e95cd3361a8ab9ad54e4cca33cd88d45b9227b83e9fc8fb6688a + languageName: node + linkType: hard + +"@types/sinonjs__fake-timers@npm:*": + version: 8.1.2 + resolution: "@types/sinonjs__fake-timers@npm:8.1.2" + checksum: bbc73a5ab6c0ec974929392f3d6e1e8db4ebad97ec506d785301e1c3d8a4f98a35b1aa95b97035daef02886fd8efd7788a2fa3ced2ec7105988bfd8dce61eedd + languageName: node + linkType: hard + "@types/sinonjs__fake-timers@npm:8.1.1": version: 8.1.1 resolution: "@types/sinonjs__fake-timers@npm:8.1.1" @@ -14896,11 +14109,11 @@ __metadata: linkType: hard "@types/stream-buffers@npm:^3.0.3": - version: 3.0.3 - resolution: "@types/stream-buffers@npm:3.0.3" + version: 3.0.4 + resolution: "@types/stream-buffers@npm:3.0.4" dependencies: "@types/node": "*" - checksum: c3456fa2a18f89d31c54fe169621d8288a9735fb7e92aba45786642659d93be26fa0b4caa5c1043b21f4cfaeeefc24d247fa833586a8a0f3aecedf03adb7b5ac + checksum: 5b432b2bf963d612747b79ac317562888236d6a9ea14414fb055c24e7be9643b5e3c7b7470841fa82802aa1c1c0d752a4ba935bbc0cfb12de6b89f7e1dadee92 languageName: node linkType: hard @@ -15030,9 +14243,9 @@ __metadata: linkType: hard "@types/underscore@npm:^1.8.9": - version: 1.10.23 - resolution: "@types/underscore@npm:1.10.23" - checksum: 5e9458888e8c09a0f61f93f5958d4ce57e02e317b21444319f7e4a11796445e58a78d6c743dad17365aa8fb9c31fa23d5f4d30a9047fa2df30d446ccc5e42023 + version: 1.11.4 + resolution: "@types/underscore@npm:1.11.4" + checksum: db9f8486bc851b732259e51f42d62aad1ae2158be5724612dc125ece5f5d61c51447f9dea28284c2a0f79cb95e788d01cb5ce97709880019213e69fab0dd1696 languageName: node linkType: hard @@ -15144,7 +14357,7 @@ __metadata: languageName: node linkType: hard -"@types/yauzl@npm:^2.10.0": +"@types/yauzl@npm:^2.10.0, @types/yauzl@npm:^2.9.1": version: 2.10.0 resolution: "@types/yauzl@npm:2.10.0" dependencies: @@ -15153,15 +14366,6 @@ __metadata: languageName: node linkType: hard -"@types/yauzl@npm:^2.9.1": - version: 2.9.2 - resolution: "@types/yauzl@npm:2.9.2" - dependencies: - "@types/node": "*" - checksum: dfb49abe82605615712fc694eaa4f7068fe30aa03f38c085e2c2e74408beaad30471d36da9654a811482ece2ea4405575fd99b19c0aa327ed2a9736b554bbf43 - languageName: node - linkType: hard - "@types/yup@npm:^0.29.13": version: 0.29.14 resolution: "@types/yup@npm:0.29.14" @@ -15232,16 +14436,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.20.0": - version: 5.20.0 - resolution: "@typescript-eslint/scope-manager@npm:5.20.0" - dependencies: - "@typescript-eslint/types": 5.20.0 - "@typescript-eslint/visitor-keys": 5.20.0 - checksum: 904fd43f559dc2579958496ffad837eca124940b4a172666f0ea54ed606074d9ec7d2bec0f2141c3f9a8b894dd2644817cb86809e79a7a73ecba2b7babcdb5c9 - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:5.36.2": version: 5.36.2 resolution: "@typescript-eslint/scope-manager@npm:5.36.2" @@ -15252,6 +14446,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:5.43.0": + version: 5.43.0 + resolution: "@typescript-eslint/scope-manager@npm:5.43.0" + dependencies: + "@typescript-eslint/types": 5.43.0 + "@typescript-eslint/visitor-keys": 5.43.0 + checksum: e594c7a32c3fa29e46dd0b0bc62f97f154bd864682ae7da87a14b6f4336f4cb02f6ed0602bbdb15783e4230ecdf8a0ccc6f7c5820850e8f11240c9e4fb0e388d + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:5.9.0": version: 5.9.0 resolution: "@typescript-eslint/scope-manager@npm:5.9.0" @@ -15279,13 +14483,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:5.20.0": - version: 5.20.0 - resolution: "@typescript-eslint/types@npm:5.20.0" - checksum: d7f6e51e23f59feee8857340828c47a98a0dd5eaa1b045e936dc11199b55754cf78ae5cd8d56c1fafb1b5a40a6f472c1ac921072951217caffe3f06a717fa61c - languageName: node - linkType: hard - "@typescript-eslint/types@npm:5.36.2": version: 5.36.2 resolution: "@typescript-eslint/types@npm:5.36.2" @@ -15293,6 +14490,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:5.43.0": + version: 5.43.0 + resolution: "@typescript-eslint/types@npm:5.43.0" + checksum: fc5e5431c305feee4a3faae84f34df482e08d74b910a6f9376b01326c682ceefeeb0e270d03d7778787bc94ef05b3b85ee6d3c9d732290fbdb4a67ae1b110226 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:5.9.0": version: 5.9.0 resolution: "@typescript-eslint/types@npm:5.9.0" @@ -15300,24 +14504,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.20.0": - version: 5.20.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.20.0" - dependencies: - "@typescript-eslint/types": 5.20.0 - "@typescript-eslint/visitor-keys": 5.20.0 - debug: ^4.3.2 - globby: ^11.0.4 - is-glob: ^4.0.3 - semver: ^7.3.5 - tsutils: ^3.21.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 2b709292b7df3675d1f8eaf2f4e1ecf491f70fc525012c6a0fb5164aa893c165317b0a419022b8b00aaed502864d5b5b84092b58a9950d2633248e8d7627abd8 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:5.36.2": version: 5.36.2 resolution: "@typescript-eslint/typescript-estree@npm:5.36.2" @@ -15336,6 +14522,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:5.43.0": + version: 5.43.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.43.0" + dependencies: + "@typescript-eslint/types": 5.43.0 + "@typescript-eslint/visitor-keys": 5.43.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 3479f9413d73369ab3d574580c90a72f74d2ae1ec4afe485eebfad054c3d15c89f23a137bb9d6197dfdae33e444a76a99f6832688787feabbb064e09d39a3f55 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.9.0": version: 5.9.0 resolution: "@typescript-eslint/typescript-estree@npm:5.9.0" @@ -15370,29 +14574,21 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:^5.10.0": - version: 5.20.0 - resolution: "@typescript-eslint/utils@npm:5.20.0" +"@typescript-eslint/utils@npm:^5.10.0, @typescript-eslint/utils@npm:^5.13.0": + version: 5.43.0 + resolution: "@typescript-eslint/utils@npm:5.43.0" dependencies: "@types/json-schema": ^7.0.9 - "@typescript-eslint/scope-manager": 5.20.0 - "@typescript-eslint/types": 5.20.0 - "@typescript-eslint/typescript-estree": 5.20.0 + "@types/semver": ^7.3.12 + "@typescript-eslint/scope-manager": 5.43.0 + "@typescript-eslint/types": 5.43.0 + "@typescript-eslint/typescript-estree": 5.43.0 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 + semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: e387cf96124e34d079804220c5cb9134148fb3efc68d852a344453e285e3016e0b7e37b11308ef58c0e7afc638f145002cebc27c5da0fd03e0c074ff97d8210e - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:5.20.0": - version: 5.20.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.20.0" - dependencies: - "@typescript-eslint/types": 5.20.0 - eslint-visitor-keys: ^3.0.0 - checksum: 1e1aa5f14fd60f1846ee26947d571953898dc82eb635a7eab3984c6b7db9bb8897743416713a129cc95c8cd63325cc0c64b3935d264f73100911fc5da76fc65f + checksum: 4c6b383b51506b57230f2624f883ae21e5d8411d138587c04fe3145f915bf8c289cc2a9f7b0b3faba98345ba230504e5014922bcc578aa0badd594d9eaa8f9ef languageName: node linkType: hard @@ -15406,6 +14602,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:5.43.0": + version: 5.43.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.43.0" + dependencies: + "@typescript-eslint/types": 5.43.0 + eslint-visitor-keys: ^3.3.0 + checksum: 4820679e50096dcdaadc7c95d32e5dca3ba8510acf1a865e283822bae3940a2faec02ad8abe793f8a25f75b600f1e7215e1fd3b3ba73779eff737fa90d092550 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:5.9.0": version: 5.9.0 resolution: "@typescript-eslint/visitor-keys@npm:5.9.0" @@ -15416,9 +14622,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.12.4": - version: 4.12.4 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.12.4" +"@uiw/codemirror-extensions-basic-setup@npm:4.13.2": + version: 4.13.2 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.13.2" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/commands": ^6.0.0 @@ -15435,19 +14641,19 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 27c65e051383cedf0ea63b3c923caf10aa45dba7cec01b3a767d81d1d0114ba221665bf0d8166f8de67946806fde7348768cf4a7683a70907e9f2eef9c99dbea + checksum: 5597d6bd7ea0304aa15f77c4bec4a071d95ae9b706a2abd6486f5fc51dba4a89101fa1e6faeb8f4fc27f4698993b008c3fd751a864618eef6baef56434d1fafd languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.9.3": - version: 4.12.4 - resolution: "@uiw/react-codemirror@npm:4.12.4" + version: 4.13.2 + resolution: "@uiw/react-codemirror@npm:4.13.2" dependencies: "@babel/runtime": ^7.18.6 "@codemirror/commands": ^6.1.0 "@codemirror/state": ^6.1.1 "@codemirror/theme-one-dark": ^6.0.0 - "@uiw/codemirror-extensions-basic-setup": 4.12.4 + "@uiw/codemirror-extensions-basic-setup": 4.13.2 codemirror: ^6.0.0 peerDependencies: "@babel/runtime": ">=7.11.0" @@ -15457,7 +14663,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: e7228beb95e918929e99e819c4f3b3920a16c5aca2477775c41bd16166af5bb7b5cefe240bd75b80fd9f61cde82086f93f8cd2dc1e2a4ecf02ff6d756cfd6f42 + checksum: 8f35aa2f54beabc440027584ccd6244f4d2e52e0792f700fb8612f1a5c8d0d705203ddddd202b3d6b82a3b1426bd4bdb230f76a5ec1ae41ec3806e9b2c955900 languageName: node linkType: hard @@ -15646,14 +14852,7 @@ __metadata: languageName: node linkType: hard -"@xmldom/xmldom@npm:^0.7.0, @xmldom/xmldom@npm:^0.7.5": - version: 0.7.5 - resolution: "@xmldom/xmldom@npm:0.7.5" - checksum: 8d7ec35c1ef6183b4f621df08e01d7e61f244fb964a4719025e65fe6ac06fac418919be64fb40fe5908e69158ef728f2d936daa082db326fe04603012b5f2a84 - languageName: node - linkType: hard - -"@xmldom/xmldom@npm:^0.7.6": +"@xmldom/xmldom@npm:^0.7.0, @xmldom/xmldom@npm:^0.7.5, @xmldom/xmldom@npm:^0.7.6": version: 0.7.6 resolution: "@xmldom/xmldom@npm:0.7.6" checksum: 3c31dcd909aaefd65090033bd45e0aca42d636a9ae43c7313f4be87de570d046abba28362810d63c0718d6f08a9ce5f8da27b87437afc24d2290b6d4e75a6eee @@ -15712,21 +14911,14 @@ __metadata: languageName: node linkType: hard -"abab@npm:^2.0.3, abab@npm:^2.0.5": - version: 2.0.5 - resolution: "abab@npm:2.0.5" - checksum: 0ec951b46d5418c2c2f923021ec193eaebdb4e802ffd5506286781b454be722a13a8430f98085cd3e204918401d9130ec6cc8f5ae19be315b3a0e857d83196e1 - languageName: node - linkType: hard - -"abab@npm:^2.0.6": +"abab@npm:^2.0.3, abab@npm:^2.0.5, abab@npm:^2.0.6": version: 2.0.6 resolution: "abab@npm:2.0.6" checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e languageName: node linkType: hard -"abbrev@npm:1": +"abbrev@npm:1, abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 @@ -15810,16 +15002,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.0, acorn@npm:^8.7.1": - version: 8.7.1 - resolution: "acorn@npm:8.7.1" - bin: - acorn: bin/acorn - checksum: aca0aabf98826717920ac2583fdcad0a6fbe4e583fdb6e843af2594e907455aeafe30b1e14f1757cd83ce1776773cf8296ffc3a4acf13f0bd3dfebcf1db6ae80 - languageName: node - linkType: hard - -"acorn@npm:^8.8.0": +"acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.0, acorn@npm:^8.7.1, acorn@npm:^8.8.0": version: 8.8.0 resolution: "acorn@npm:8.8.0" bin: @@ -15851,18 +15034,7 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.1.3, agentkeepalive@npm:^4.1.4, agentkeepalive@npm:^4.2.0": - version: 4.2.0 - resolution: "agentkeepalive@npm:4.2.0" - dependencies: - debug: ^4.1.0 - depd: ^1.1.2 - humanize-ms: ^1.2.1 - checksum: 89806f83ceebbcaabf6bd581a8dce4870910fd2a11f66df8f505b4cd4ce4ca5ab9e6eec8d11ce8531a6b60f6748b75b0775e0e2fa33871503ef00d535418a19a - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.2.1": +"agentkeepalive@npm:^4.1.3, agentkeepalive@npm:^4.1.4, agentkeepalive@npm:^4.2.1": version: 4.2.1 resolution: "agentkeepalive@npm:4.2.1" dependencies: @@ -15929,6 +15101,18 @@ __metadata: languageName: node linkType: hard +"ajv8@npm:ajv@^8.11.0, ajv@npm:^8.0.0, ajv@npm:^8.10.0, ajv@npm:^8.6.3, ajv@npm:^8.8.0": + version: 8.11.2 + resolution: "ajv@npm:8.11.2" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 53435bf79ee7d1eabba8085962dba4c08d08593334b304db7772887f0b7beebc1b3d957432f7437ed4b60e53b5d966a57b439869890209c50fed610459999e3e + languageName: node + linkType: hard + "ajv@npm:^6.10.0, ajv@npm:^6.10.1, ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5, ajv@npm:^6.5.5, ajv@npm:^6.7.0, ajv@npm:~6.12.6": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -15941,18 +15125,6 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^8.0.0, ajv@npm:^8.10.0, ajv@npm:^8.11.0, ajv@npm:^8.6.3, ajv@npm:^8.8.0": - version: 8.11.0 - resolution: "ajv@npm:8.11.0" - dependencies: - fast-deep-equal: ^3.1.1 - json-schema-traverse: ^1.0.0 - require-from-string: ^2.0.2 - uri-js: ^4.2.2 - checksum: 5e0ff226806763be73e93dd7805b634f6f5921e3e90ca04acdf8db81eed9d8d3f0d4c5f1213047f45ebbf8047ffe0c840fa1ef2ec42c3a644899f69aa72b5bef - languageName: node - linkType: hard - "alphanum-sort@npm:^1.0.2": version: 1.0.2 resolution: "alphanum-sort@npm:1.0.2" @@ -16095,16 +15267,7 @@ __metadata: languageName: node linkType: hard -"apollo-reporting-protobuf@npm:^3.3.1": - version: 3.3.1 - resolution: "apollo-reporting-protobuf@npm:3.3.1" - dependencies: - "@apollo/protobufjs": 1.2.2 - checksum: 1933affb1640d5905e29f8a41becdba1981effd767660748517ea1d4ef30db4c6789b17eba02f11dafd29b46b56d95cd15cbc3eb319d0a90affbdd0f2d168473 - languageName: node - linkType: hard - -"apollo-reporting-protobuf@npm:^3.3.3": +"apollo-reporting-protobuf@npm:^3.3.1, apollo-reporting-protobuf@npm:^3.3.3": version: 3.3.3 resolution: "apollo-reporting-protobuf@npm:3.3.3" dependencies: @@ -16113,9 +15276,9 @@ __metadata: languageName: node linkType: hard -"apollo-server-core@npm:^3.10.3": - version: 3.10.3 - resolution: "apollo-server-core@npm:3.10.3" +"apollo-server-core@npm:^3.11.1": + version: 3.11.1 + resolution: "apollo-server-core@npm:3.11.1" dependencies: "@apollo/utils.keyvaluecache": ^1.0.1 "@apollo/utils.logger": ^1.0.0 @@ -16129,19 +15292,20 @@ __metadata: apollo-reporting-protobuf: ^3.3.3 apollo-server-env: ^4.2.1 apollo-server-errors: ^3.3.1 - apollo-server-plugin-base: ^3.6.3 - apollo-server-types: ^3.6.3 + apollo-server-plugin-base: ^3.7.1 + apollo-server-types: ^3.7.1 async-retry: ^1.2.1 fast-json-stable-stringify: ^2.1.0 graphql-tag: ^2.11.0 loglevel: ^1.6.8 lru-cache: ^6.0.0 + node-abort-controller: ^3.0.1 sha.js: ^2.4.11 uuid: ^9.0.0 whatwg-mimetype: ^3.0.0 peerDependencies: graphql: ^15.3.0 || ^16.0.0 - checksum: 1a9c3ca29c1e664970737e83d76999d43ceb938e39026a329682fcc80fa17a564a69cb7b38110b1928d3d512ae77eeeb8ed6e160043521052c0360b0b00f0ada + checksum: a5cb7cff331680c2a926c64e88f744425b724bcfae46aeb02ae636d0b6f57a605e561eb284e765618bd0b2b5f8c556c92183f69852f2e4f5889368fee6aa38dc languageName: node linkType: hard @@ -16163,9 +15327,9 @@ __metadata: languageName: node linkType: hard -"apollo-server-express@npm:^3.0.0, apollo-server-express@npm:^3.10.3": - version: 3.10.3 - resolution: "apollo-server-express@npm:3.10.3" +"apollo-server-express@npm:^3.0.0, apollo-server-express@npm:^3.11.1": + version: 3.11.1 + resolution: "apollo-server-express@npm:3.11.1" dependencies: "@types/accepts": ^1.3.5 "@types/body-parser": 1.19.2 @@ -16173,32 +15337,32 @@ __metadata: "@types/express": 4.17.14 "@types/express-serve-static-core": 4.17.31 accepts: ^1.3.5 - apollo-server-core: ^3.10.3 - apollo-server-types: ^3.6.3 + apollo-server-core: ^3.11.1 + apollo-server-types: ^3.7.1 body-parser: ^1.19.0 cors: ^2.8.5 parseurl: ^1.3.3 peerDependencies: express: ^4.17.1 graphql: ^15.3.0 || ^16.0.0 - checksum: c6dcfd8b61a558bd479d93d1c9cc4f436145b31e7f5e53d6c655d919c79f0b4b785788f0d16fc1d94c1929b85b034ae84a7332ce4e20603b67e0a4709e48b3a6 + checksum: 1db1a77aaa2f760c885233ded249b632e467bb4895d1c3f797df6e197a9ca7021c5b65dd8829e88fd6dbf32d925c7dcf62b48b949a518e2e31072c490302fa60 languageName: node linkType: hard -"apollo-server-plugin-base@npm:^3.6.3": - version: 3.6.3 - resolution: "apollo-server-plugin-base@npm:3.6.3" +"apollo-server-plugin-base@npm:^3.7.1": + version: 3.7.1 + resolution: "apollo-server-plugin-base@npm:3.7.1" dependencies: - apollo-server-types: ^3.6.3 + apollo-server-types: ^3.7.1 peerDependencies: graphql: ^15.3.0 || ^16.0.0 - checksum: 50e690cf4c5047957c4546676f11d82f8c0bee2c0340573322f23188af27175ac49859d463c6123ebef500b3c32a0932e3e3f9fa8671e2d1a410d2e89c8608e3 + checksum: db8c5f658da8c51c067bd6659b31ec2436d4961437b6f6f6b1b2a109d26764bc52a4dbe1bdafcb3c712b0e2f13ca10ed787e90423505685d2043a77363bdfc0b languageName: node linkType: hard -"apollo-server-types@npm:^3.6.3": - version: 3.6.3 - resolution: "apollo-server-types@npm:3.6.3" +"apollo-server-types@npm:^3.7.1": + version: 3.7.1 + resolution: "apollo-server-types@npm:3.7.1" dependencies: "@apollo/utils.keyvaluecache": ^1.0.1 "@apollo/utils.logger": ^1.0.0 @@ -16206,21 +15370,21 @@ __metadata: apollo-server-env: ^4.2.1 peerDependencies: graphql: ^15.3.0 || ^16.0.0 - checksum: ebd218e6fa8b756bb2d6954b454676907d99b8f140923b439cc1bbb200251f9df7228a9d83c5c91bb571a448cc80c2d86bc0a0eae491a4ce028e86a724cde68a + checksum: fe9a0847d0b8ab70dbe407b4ba1f5e506d351ff1f728193f4b308806e73b958f50537478a71edeefdd66fcf3dbf32ec732b6ffe6542860d5b683b1d657a019a2 languageName: node linkType: hard "apollo-server@npm:^3.0.0": - version: 3.10.3 - resolution: "apollo-server@npm:3.10.3" + version: 3.11.1 + resolution: "apollo-server@npm:3.11.1" dependencies: "@types/express": 4.17.14 - apollo-server-core: ^3.10.3 - apollo-server-express: ^3.10.3 + apollo-server-core: ^3.11.1 + apollo-server-express: ^3.11.1 express: ^4.17.1 peerDependencies: graphql: ^15.3.0 || ^16.0.0 - checksum: eec2423bbd30256683c0e7873cd1e3f616ff2a3c90cf7bba241880027f5e1374d20d13bf7ce4b09543b16753d0d7a4627f77d64de77b5b241c410f0f246bdbd7 + checksum: 6d4e981682e3b60313dddfe999c408c683f7e4cdeed5c14b6d6245b708808b94cb14df67ebe1b9df38df6b5193a9291089c41e287d014f2a9f94b2f3ecc9b376 languageName: node linkType: hard @@ -16360,27 +15524,6 @@ __metadata: languageName: node linkType: hard -"arr-diff@npm:^4.0.0": - version: 4.0.0 - resolution: "arr-diff@npm:4.0.0" - checksum: ea7c8834842ad3869297f7915689bef3494fd5b102ac678c13ffccab672d3d1f35802b79e90c4cfec2f424af3392e44112d1ccf65da34562ed75e049597276a0 - languageName: node - linkType: hard - -"arr-flatten@npm:^1.1.0": - version: 1.1.0 - resolution: "arr-flatten@npm:1.1.0" - checksum: 963fe12564fca2f72c055f3f6c206b9e031f7c433a0c66ca9858b484821f248c5b1e5d53c8e4989d80d764cd776cf6d9b160ad05f47bdc63022bfd63b5455e22 - languageName: node - linkType: hard - -"arr-union@npm:^3.1.0": - version: 3.1.0 - resolution: "arr-union@npm:3.1.0" - checksum: b5b0408c6eb7591143c394f3be082fee690ddd21f0fdde0a0a01106799e847f67fcae1b7e56b0a0c173290e29c6aca9562e82b300708a268bc8f88f3d6613cb9 - languageName: node - linkType: hard - "array-differ@npm:^3.0.0": version: 3.0.0 resolution: "array-differ@npm:3.0.0" @@ -16409,20 +15552,7 @@ __metadata: languageName: node linkType: hard -"array-includes@npm:^3.1.2, array-includes@npm:^3.1.4": - version: 3.1.4 - resolution: "array-includes@npm:3.1.4" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.1 - get-intrinsic: ^1.1.1 - is-string: ^1.0.7 - checksum: 69967c38c52698f84b50a7aed5554aadc89c6ac6399b6d92ad061a5952f8423b4bba054c51d40963f791dfa294d7247cdd7988b6b1f2c5861477031c6386e1c0 - languageName: node - linkType: hard - -"array-includes@npm:^3.1.5": +"array-includes@npm:^3.1.4, array-includes@npm:^3.1.5": version: 3.1.5 resolution: "array-includes@npm:3.1.5" dependencies: @@ -16458,14 +15588,7 @@ __metadata: languageName: node linkType: hard -"array-unique@npm:^0.3.2": - version: 0.3.2 - resolution: "array-unique@npm:0.3.2" - checksum: da344b89cfa6b0a5c221f965c21638bfb76b57b45184a01135382186924f55973cd9b171d4dad6bf606c6d9d36b0d721d091afdc9791535ead97ccbe78f8a888 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.2.3": +"array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.2.5": version: 1.3.0 resolution: "array.prototype.flat@npm:1.3.0" dependencies: @@ -16477,17 +15600,6 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.flat@npm:1.2.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.0 - checksum: 9cc6414b111abfc7717e39546e4887b1e5ec74df8f1618d83425deaa95752bf05d475d1d241253b4d88d4a01f8e1bc84845ad5b7cc2047f8db2f614512acd40e - languageName: node - linkType: hard - "array.prototype.flatmap@npm:^1.3.0": version: 1.3.0 resolution: "array.prototype.flatmap@npm:1.3.0" @@ -16576,13 +15688,6 @@ __metadata: languageName: node linkType: hard -"assign-symbols@npm:^1.0.0": - version: 1.0.0 - resolution: "assign-symbols@npm:1.0.0" - checksum: c0eb895911d05b6b2d245154f70461c5e42c107457972e5ebba38d48967870dee53bcdf6c7047990586daa80fab8dab3cc6300800fbd47b454247fdedd859a2c - languageName: node - linkType: hard - "ast-types-flow@npm:^0.0.7": version: 0.0.7 resolution: "ast-types-flow@npm:0.0.7" @@ -16599,6 +15704,15 @@ __metadata: languageName: node linkType: hard +"ast-types@npm:0.15.2": + version: 0.15.2 + resolution: "ast-types@npm:0.15.2" + dependencies: + tslib: ^2.0.1 + checksum: 24f0d86bf9e4c8dae16fa24b13c1776f2c2677040bcfbd4eb4f27911db49020be4876885e45e6cfcc548ed4dfea3a0742d77e3346b84fae47379cb0b89e9daa0 + languageName: node + linkType: hard + "astral-regex@npm:^2.0.0": version: 2.0.0 resolution: "astral-regex@npm:2.0.0" @@ -16643,15 +15757,6 @@ __metadata: languageName: node linkType: hard -"atob@npm:^2.1.2": - version: 2.1.2 - resolution: "atob@npm:2.1.2" - bin: - atob: bin/atob.js - checksum: dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a - languageName: node - linkType: hard - "atomic-sleep@npm:^1.0.0": version: 1.0.0 resolution: "atomic-sleep@npm:1.0.0" @@ -16710,6 +15815,17 @@ __metadata: languageName: node linkType: hard +"aws-sdk-client-mock@npm:^2.0.0": + version: 2.0.0 + resolution: "aws-sdk-client-mock@npm:2.0.0" + dependencies: + "@types/sinon": ^10.0.10 + sinon: ^11.1.1 + tslib: ^2.1.0 + checksum: e6081ca6bb72f5c082dfcd93155bbb7e1c9e8d3d346914ed05d736c495a5ef99ab3d0253507aff2e07b5b995fae63671e53e094437ddfaf8649d69725628ff8f + languageName: node + linkType: hard + "aws-sdk-mock@npm:^5.2.1": version: 5.7.0 resolution: "aws-sdk-mock@npm:5.7.0" @@ -17113,21 +16229,6 @@ __metadata: languageName: node linkType: hard -"base@npm:^0.11.1": - version: 0.11.2 - resolution: "base@npm:0.11.2" - dependencies: - cache-base: ^1.0.1 - class-utils: ^0.3.5 - component-emitter: ^1.2.1 - define-property: ^1.0.0 - isobject: ^3.0.1 - mixin-deep: ^1.2.0 - pascalcase: ^0.1.1 - checksum: a4a146b912e27eea8f66d09cb0c9eab666f32ce27859a7dfd50f38cd069a2557b39f16dba1bc2aecb3b44bf096738dd207b7970d99b0318423285ab1b1994edd - languageName: node - linkType: hard - "basic-auth@npm:~2.0.1": version: 2.0.1 resolution: "basic-auth@npm:2.0.1" @@ -17310,7 +16411,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.0": +"body-parser@npm:1.20.0, body-parser@npm:^1.19.0": version: 1.20.0 resolution: "body-parser@npm:1.20.0" dependencies: @@ -17330,24 +16431,6 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^1.19.0": - version: 1.19.2 - resolution: "body-parser@npm:1.19.2" - dependencies: - bytes: 3.1.2 - content-type: ~1.0.4 - debug: 2.6.9 - depd: ~1.1.2 - http-errors: 1.8.1 - iconv-lite: 0.4.24 - on-finished: ~2.3.0 - qs: 6.9.7 - raw-body: 2.4.3 - type-is: ~1.6.18 - checksum: 7f777ea65670e2622ca4a785b5dcb2a68451b3bb8d4d0f41091d307d56b640dba588a9ae04d85dda2cdd5e42788266a783528d5417e5643720fd611fd52522e7 - languageName: node - linkType: hard - "bonjour-service@npm:^1.0.11": version: 1.0.11 resolution: "bonjour-service@npm:1.0.11" @@ -17381,6 +16464,13 @@ __metadata: languageName: node linkType: hard +"bowser@npm:^2.11.0": + version: 2.11.0 + resolution: "bowser@npm:2.11.0" + checksum: 29c3f01f22e703fa6644fc3b684307442df4240b6e10f6cfe1b61c6ca5721073189ca97cdeedb376081148c8518e33b1d818a57f781d70b0b70e1f31fb48814f + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -17400,24 +16490,6 @@ __metadata: languageName: node linkType: hard -"braces@npm:^2.3.1": - version: 2.3.2 - resolution: "braces@npm:2.3.2" - dependencies: - arr-flatten: ^1.1.0 - array-unique: ^0.3.2 - extend-shallow: ^2.0.1 - fill-range: ^4.0.0 - isobject: ^3.0.1 - repeat-element: ^1.1.2 - snapdragon: ^0.8.1 - snapdragon-node: ^2.0.1 - split-string: ^3.0.2 - to-regex: ^3.0.1 - checksum: e30dcb6aaf4a31c8df17d848aa283a65699782f75ad61ae93ec25c9729c66cf58e66f0000a9fec84e4add1135bb7da40f7cb9601b36bebcfa9ca58e8d5c07de0 - languageName: node - linkType: hard - "braces@npm:^3.0.2, braces@npm:~3.0.2": version: 3.0.2 resolution: "braces@npm:3.0.2" @@ -17528,36 +16600,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.17.5, browserslist@npm:^4.18.1": - version: 4.19.1 - resolution: "browserslist@npm:4.19.1" - dependencies: - caniuse-lite: ^1.0.30001286 - electron-to-chromium: ^1.4.17 - escalade: ^3.1.1 - node-releases: ^2.0.1 - picocolors: ^1.0.0 - bin: - browserslist: cli.js - checksum: c0777fd483691638fd6801e16c9d809e1d65f6d2b06db2e806654be51045cbab1452a89841a2c5caea2cbe19d621b4f1d391cffbb24512aa33280039ab345875 - languageName: node - linkType: hard - -"browserslist@npm:^4.20.2, browserslist@npm:^4.21.2": - version: 4.21.2 - resolution: "browserslist@npm:4.21.2" - dependencies: - caniuse-lite: ^1.0.30001366 - electron-to-chromium: ^1.4.188 - node-releases: ^2.0.6 - update-browserslist-db: ^1.0.4 - bin: - browserslist: cli.js - checksum: 30fe59f8b065f99665ea63819d29c797660f7975857c290f61f570403abed4d7039ca15b6fd21e39a57b87e1a9262f94676114040766fc0da6ccc11faf9fc377 - languageName: node - linkType: hard - -"browserslist@npm:^4.21.3": +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.18.1, browserslist@npm:^4.21.2, browserslist@npm:^4.21.3": version: 4.21.4 resolution: "browserslist@npm:4.21.4" dependencies: @@ -17640,7 +16683,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.2.0, buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0, buffer@npm:^5.7.1": +"buffer@npm:^5.2.0, buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -17711,7 +16754,7 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^15.0.3, cacache@npm:^15.0.5, cacache@npm:^15.2.0, cacache@npm:^15.3.0": +"cacache@npm:^15.0.3, cacache@npm:^15.0.5, cacache@npm:^15.2.0": version: 15.3.0 resolution: "cacache@npm:15.3.0" dependencies: @@ -17763,23 +16806,6 @@ __metadata: languageName: node linkType: hard -"cache-base@npm:^1.0.1": - version: 1.0.1 - resolution: "cache-base@npm:1.0.1" - dependencies: - collection-visit: ^1.0.0 - component-emitter: ^1.2.1 - get-value: ^2.0.6 - has-value: ^1.0.0 - isobject: ^3.0.1 - set-value: ^2.0.0 - to-object-path: ^0.3.0 - union-value: ^1.0.0 - unset-value: ^1.0.0 - checksum: 9114b8654fe2366eedc390bad0bcf534e2f01b239a888894e2928cb58cdc1e6ea23a73c6f3450dcfd2058aa73a8a981e723cd1e7c670c047bf11afdc65880107 - languageName: node - linkType: hard - "cacheable-lookup@npm:^5.0.3": version: 5.0.3 resolution: "cacheable-lookup@npm:5.0.3" @@ -17913,29 +16939,22 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001286, caniuse-lite@npm:^1.0.30001366": - version: 1.0.30001392 - resolution: "caniuse-lite@npm:1.0.30001392" - checksum: b46fdb4cd63f43e608c9378e9a4cfc1092407fccda32f13f53db8818e0e654e5b2b9e7aee76b95a1a4fd3f2c2eabd1157aef19905f2c60dfcec136b27ac5fce6 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001400": +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001400": version: 1.0.30001407 resolution: "caniuse-lite@npm:1.0.30001407" checksum: e1c449d22f120a708accc956c1780f1da01af6c226cb6a324e531dc9f26f53075bff98e6c9cfce806157cdeede459aa8de03a3407b05f71d292a57b2910018b1 languageName: node linkType: hard -"canvas@npm:^2.6.1": - version: 2.10.1 - resolution: "canvas@npm:2.10.1" +"canvas@npm:^2.10.2": + version: 2.10.2 + resolution: "canvas@npm:2.10.2" dependencies: "@mapbox/node-pre-gyp": ^1.0.0 - nan: ^2.15.0 + nan: ^2.17.0 node-gyp: latest simple-get: ^3.0.3 - checksum: 29b162a59df8c63e5591cae62711ab3cc3b0a078f260b39b4594b51c5bcb9baa597eff40b52f25bd788aceb81756a41097c2dd0c01cbc17ae4a15e873da44cdf + checksum: b2e3eb4c3635fa2f67857619621c3d314f935a9e51904536dadf4908ab580dff4f5bcbaafe6eb0255247fa027ca494d5cd97c33376a49a0f994997263fa9944b languageName: node linkType: hard @@ -18173,6 +17192,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^2.0.0": + version: 2.0.0 + resolution: "ci-info@npm:2.0.0" + checksum: 3b374666a85ea3ca43fa49aa3a048d21c9b475c96eb13c133505d2324e7ae5efd6a454f41efe46a152269e9b6a00c9edbe63ec7fa1921957165aae16625acd67 + languageName: node + linkType: hard + "ci-info@npm:^3.1.0, ci-info@npm:^3.2.0": version: 3.3.2 resolution: "ci-info@npm:3.3.2" @@ -18206,18 +17232,6 @@ __metadata: languageName: node linkType: hard -"class-utils@npm:^0.3.5": - version: 0.3.6 - resolution: "class-utils@npm:0.3.6" - dependencies: - arr-union: ^3.1.0 - define-property: ^0.2.5 - isobject: ^3.0.0 - static-extend: ^0.1.1 - checksum: be108900801e639e50f96a7e4bfa8867c753a7750a7603879f3981f8b0a89cba657497a2d5f40cd4ea557ff15d535a100818bb486baf6e26fe5d7872e75f1078 - languageName: node - linkType: hard - "classnames@npm:*, classnames@npm:^2.2.5, classnames@npm:^2.2.6, classnames@npm:^2.3.1": version: 2.3.1 resolution: "classnames@npm:2.3.1" @@ -18512,16 +17526,6 @@ __metadata: languageName: node linkType: hard -"collection-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "collection-visit@npm:1.0.0" - dependencies: - map-visit: ^1.0.0 - object-visit: ^1.0.0 - checksum: 15d9658fe6eb23594728346adad5433b86bb7a04fd51bbab337755158722f9313a5376ef479de5b35fbc54140764d0d39de89c339f5d25b959ed221466981da9 - languageName: node - linkType: hard - "color-convert@npm:^0.5.2": version: 0.5.3 resolution: "color-convert@npm:0.5.3" @@ -18607,20 +17611,13 @@ __metadata: languageName: node linkType: hard -"colorette@npm:2.0.19, colorette@npm:^2.0.16, colorette@npm:^2.0.17": +"colorette@npm:2.0.19, colorette@npm:^2.0.10, colorette@npm:^2.0.16, colorette@npm:^2.0.17": version: 2.0.19 resolution: "colorette@npm:2.0.19" checksum: 888cf5493f781e5fcf54ce4d49e9d7d698f96ea2b2ef67906834bb319a392c667f9ec69f4a10e268d2946d13a9503d2d19b3abaaaf174e3451bfe91fb9d82427 languageName: node linkType: hard -"colorette@npm:^2.0.10": - version: 2.0.16 - resolution: "colorette@npm:2.0.16" - checksum: cd55596a3a2d1071c1a28eee7fd8a5387593ff1bd10a3e8d0a6221499311fe34a9f2b9272d77c391e0e003dcdc8934fb2f8d106e7ef1f7516f8060c901d41a27 - languageName: node - linkType: hard - "colors@npm:1.0.3": version: 1.0.3 resolution: "colors@npm:1.0.3" @@ -18682,10 +17679,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:*, commander@npm:^9.3.0": - version: 9.4.0 - resolution: "commander@npm:9.4.0" - checksum: a322de584a6ccd1ea83c24f6a660e52d16ffbe2613fcfbb8d2cc68bc9dec637492456d754fe8bb5b039ad843ed8e04fb0b107e581a75f62cde9e1a0ab1546e09 +"commander@npm:*, commander@npm:^9.1.0, commander@npm:^9.3.0": + version: 9.4.1 + resolution: "commander@npm:9.4.1" + checksum: bfb18e325a5bdf772763c2213d5c7d9e77144d944124e988bcd8e5e65fb6d45d5d4e86b09155d0f2556c9a59c31e428720e57968bcd050b2306e910a0bf3cf13 languageName: node linkType: hard @@ -18738,13 +17735,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^9.1.0": - version: 9.4.1 - resolution: "commander@npm:9.4.1" - checksum: bfb18e325a5bdf772763c2213d5c7d9e77144d944124e988bcd8e5e65fb6d45d5d4e86b09155d0f2556c9a59c31e428720e57968bcd050b2306e910a0bf3cf13 - languageName: node - linkType: hard - "common-ancestor-path@npm:^1.0.1": version: 1.0.1 resolution: "common-ancestor-path@npm:1.0.1" @@ -18794,7 +17784,7 @@ __metadata: languageName: node linkType: hard -"component-emitter@npm:^1.2.1, component-emitter@npm:^1.3.0, component-emitter@npm:~1.3.0": +"component-emitter@npm:^1.3.0, component-emitter@npm:~1.3.0": version: 1.3.0 resolution: "component-emitter@npm:1.3.0" checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b @@ -18914,8 +17904,8 @@ __metadata: linkType: hard "concurrently@npm:^7.0.0": - version: 7.4.0 - resolution: "concurrently@npm:7.4.0" + version: 7.5.0 + resolution: "concurrently@npm:7.5.0" dependencies: chalk: ^4.1.0 date-fns: ^2.29.1 @@ -18929,7 +17919,7 @@ __metadata: bin: conc: dist/bin/concurrently.js concurrently: dist/bin/concurrently.js - checksum: cc547866ad8d009d184ca3a7115d6636052a5f56f5429d123092d651286043d7233f6429257e30e50f509894cd12798ea831896ac18092d8135f67ffcc8ac3ea + checksum: 7886e1c8559d2699ae1b62be8aca5d56c226966e252a2b9dd6077b3c1fd5397e98ef537c040fffa1de50418bd2616746eb9dd589a31ffb9056d4758b850a865b languageName: node linkType: hard @@ -19065,14 +18055,7 @@ __metadata: languageName: node linkType: hard -"copy-descriptor@npm:^0.1.0": - version: 0.1.1 - resolution: "copy-descriptor@npm:0.1.1" - checksum: d4b7b57b14f1d256bb9aa0b479241048afd7f5bcf22035fc7b94e8af757adeae247ea23c1a774fe44869fd5694efba4a969b88d966766c5245fdee59837fe45b - languageName: node - linkType: hard - -"copy-to-clipboard@npm:^3, copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": +"copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" dependencies: @@ -19091,27 +18074,13 @@ __metadata: languageName: node linkType: hard -"core-js-pure@npm:^3.20.2": - version: 3.21.1 - resolution: "core-js-pure@npm:3.21.1" - checksum: 00a5dff599b7fb0b30746a638b9d0edbdc0df24ed1580ca56be595fbe3c78c375d37fc4e1bff23627109229702c9ee8ea2587a66b8280eb33b85160aa4e401e9 - languageName: node - linkType: hard - -"core-js-pure@npm:^3.23.3": +"core-js-pure@npm:^3.20.2, core-js-pure@npm:^3.23.3, core-js-pure@npm:^3.6.5": version: 3.25.5 resolution: "core-js-pure@npm:3.25.5" checksum: e48799a8ab28f00ef3db18377142ff2c578574ab2b18ebddde6cbf12823e0181a57c80e3caa6046ce2a2e439d603a252be767583ddc54248e3d1060bc5012127 languageName: node linkType: hard -"core-js-pure@npm:^3.6.5": - version: 3.25.3 - resolution: "core-js-pure@npm:3.25.3" - checksum: be3097b8e2b541977a08004e433b68adb4951cc7694229e695ae407f296d370c1f360e5fd70fc6910c4427e46e48e087ac455d68cebdf4314370907d2e03eef1 - languageName: node - linkType: hard - "core-js@npm:^2.4.0, core-js@npm:^2.5.0": version: 2.6.12 resolution: "core-js@npm:2.6.12" @@ -19119,17 +18088,10 @@ __metadata: languageName: node linkType: hard -"core-js@npm:^3.4.1": - version: 3.25.0 - resolution: "core-js@npm:3.25.0" - checksum: 5a72740bf5babaf2e6203da4c0e831a0b97c3fe6f21b4c1aa8601d3a927660a22128dd8f0e86ce84778c4e5372ab0fc03c7944afa7e215c7fb13b2c79d5d5504 - languageName: node - linkType: hard - -"core-js@npm:^3.6.5": - version: 3.25.5 - resolution: "core-js@npm:3.25.5" - checksum: 208b308c49bc022f90d4349d4c99802a73c9d55053976b3c529f10014c1e37845926defad8c519f2c7f71ea0acf18d2b323ab6aaee34dc85b4c4b3ced0623f3f +"core-js@npm:^3.4.1, core-js@npm:^3.6.5": + version: 3.26.1 + resolution: "core-js@npm:3.26.1" + checksum: 0a01149f51ff1e9f41d1ea49cc4c9222047949ea597189ede7c4cf8cde3b097766b9c7615acc77c86fe65b4002f20b638a133dfba7b41dba830d707aeeed45ad languageName: node linkType: hard @@ -19159,7 +18121,7 @@ __metadata: languageName: node linkType: hard -"cosmiconfig-typescript-loader@npm:4.1.1": +"cosmiconfig-typescript-loader@npm:4.1.1, cosmiconfig-typescript-loader@npm:^4.0.0": version: 4.1.1 resolution: "cosmiconfig-typescript-loader@npm:4.1.1" peerDependencies: @@ -19171,18 +18133,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig-typescript-loader@npm:^4.0.0": - version: 4.0.0 - resolution: "cosmiconfig-typescript-loader@npm:4.0.0" - peerDependencies: - "@types/node": "*" - cosmiconfig: ">=7" - ts-node: ">=10" - typescript: ">=3" - checksum: 9151ffe62d0b3b0bac7435add229febf04d72f4db8199390813fef071343865e91e823bd75210f9aabe218dc97a2cc2c776120c0dc886e9164947b80a910c19b - languageName: node - linkType: hard - "cosmiconfig@npm:7.0.1, cosmiconfig@npm:^7.0.0, cosmiconfig@npm:^7.0.1": version: 7.0.1 resolution: "cosmiconfig@npm:7.0.1" @@ -19340,6 +18290,19 @@ __metadata: languageName: node linkType: hard +"cross-spawn@npm:^6.0.5": + version: 6.0.5 + resolution: "cross-spawn@npm:6.0.5" + dependencies: + nice-try: ^1.0.4 + path-key: ^2.0.1 + semver: ^5.5.0 + shebang-command: ^1.2.0 + which: ^1.2.9 + checksum: f893bb0d96cd3d5751d04e67145bdddf25f99449531a72e82dcbbd42796bbc8268c1076c6b3ea51d4d455839902804b94bc45dfb37ecbb32ea8e54a6741c3ab9 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -19351,21 +18314,6 @@ __metadata: languageName: node linkType: hard -"cross-undici-fetch@npm:^0.4.11": - version: 0.4.11 - resolution: "cross-undici-fetch@npm:0.4.11" - dependencies: - abort-controller: ^3.0.0 - busboy: ^1.6.0 - form-data-encoder: ^1.7.1 - formdata-node: ^4.3.1 - node-fetch: ^2.6.7 - undici: 5.5.1 - web-streams-polyfill: ^3.2.0 - checksum: 76927df814f5ac8f5656d69099d20f9970acdfe309a46908913c68e17cf16f4454eeeae3dfc6e9f6fb9efddf1c11a10b805a97d02dedd258efcd3e575e09bc3f - languageName: node - linkType: hard - "crypto-browserify@npm:^3.11.0": version: 3.12.0 resolution: "crypto-browserify@npm:3.12.0" @@ -19434,20 +18382,20 @@ __metadata: linkType: hard "css-loader@npm:^6.5.1": - version: 6.7.1 - resolution: "css-loader@npm:6.7.1" + version: 6.7.2 + resolution: "css-loader@npm:6.7.2" dependencies: icss-utils: ^5.1.0 - postcss: ^8.4.7 + postcss: ^8.4.18 postcss-modules-extract-imports: ^3.0.0 postcss-modules-local-by-default: ^4.0.0 postcss-modules-scope: ^3.0.0 postcss-modules-values: ^4.0.0 postcss-value-parser: ^4.2.0 - semver: ^7.3.5 + semver: ^7.3.8 peerDependencies: webpack: ^5.0.0 - checksum: 170fdbc630a05a43679ef60fa97694766b568dbde37adccc0faafa964fc675f08b976bc68837bb73b61d60240e8d2cbcbf51540fe94ebc9dafc56e7c46ba5527 + checksum: f3c980cc9c033a02e60df7e5a2f33a1e8c2c3dd552f017485d2d81b383be623ae8c4189404e7a4a7403b52744683ae4b516def0f7ccf125c2b198cb647e46543 languageName: node linkType: hard @@ -19706,8 +18654,8 @@ __metadata: linkType: hard "cypress@npm:^10.0.0": - version: 10.10.0 - resolution: "cypress@npm:10.10.0" + version: 10.11.0 + resolution: "cypress@npm:10.11.0" dependencies: "@cypress/request": ^2.88.10 "@cypress/xvfb": ^1.2.4 @@ -19753,7 +18701,7 @@ __metadata: yauzl: ^2.10.0 bin: cypress: bin/cypress - checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2 + checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2 languageName: node linkType: hard @@ -20007,21 +18955,7 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.16.1": - version: 2.28.0 - resolution: "date-fns@npm:2.28.0" - checksum: a0516b2e4f99b8bffc6cc5193349f185f195398385bdcaf07f17c2c4a24473c99d933eb0018be4142a86a6d46cb0b06be6440ad874f15e795acbedd6fd727a1f - languageName: node - linkType: hard - -"date-fns@npm:^2.18.0": - version: 2.19.0 - resolution: "date-fns@npm:2.19.0" - checksum: c8b727aa10941d76977c48c72bda3b33adeb6a89d67763c95689ef7c18729a564a6e01e87fd5f65ba44b6866e8282d636d5e8bc598f099b925597bb109a0880c - languageName: node - linkType: hard - -"date-fns@npm:^2.29.1": +"date-fns@npm:^2.16.1, date-fns@npm:^2.18.0, date-fns@npm:^2.29.1": version: 2.29.3 resolution: "date-fns@npm:2.29.3" checksum: e01cf5b62af04e05dfff921bb9c9933310ed0e1ae9a81eb8653452e64dc841acf7f6e01e1a5ae5644d0337e9a7f936175fd2cb6819dc122fdd9c5e86c56be484 @@ -20056,7 +18990,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.0, debug@npm:^2.6.9": +"debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" dependencies: @@ -20147,14 +19081,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.2.1": - version: 10.3.1 - resolution: "decimal.js@npm:10.3.1" - checksum: 0351ac9f05fe050f23227aa6a4573bee2d58fa7378fcf28d969a8c789525032effb488a90320fd3fe86a66e17b4bc507d811b15eada5b7f0e7ec5d2af4c24a59 - languageName: node - linkType: hard - -"decimal.js@npm:^10.3.1": +"decimal.js@npm:^10.2.1, decimal.js@npm:^10.3.1": version: 10.4.1 resolution: "decimal.js@npm:10.4.1" checksum: 5da6dc74af5b73d954741b24d404ef6da07841794d9e51412a2708ec384dd7b4bced3365fb178f4cd119b7ef45f0b34344014a4dc0494c8374c5e746df3cb410 @@ -20265,34 +19192,6 @@ __metadata: languageName: node linkType: hard -"define-property@npm:^0.2.5": - version: 0.2.5 - resolution: "define-property@npm:0.2.5" - dependencies: - is-descriptor: ^0.1.0 - checksum: 85af107072b04973b13f9e4128ab74ddfda48ec7ad2e54b193c0ffb57067c4ce5b7786a7b4ae1f24bd03e87c5d18766b094571810b314d7540f86d4354dbd394 - languageName: node - linkType: hard - -"define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "define-property@npm:1.0.0" - dependencies: - is-descriptor: ^1.0.0 - checksum: 5fbed11dace44dd22914035ba9ae83ad06008532ca814d7936a53a09e897838acdad5b108dd0688cc8d2a7cf0681acbe00ee4136cf36743f680d10517379350a - languageName: node - linkType: hard - -"define-property@npm:^2.0.2": - version: 2.0.2 - resolution: "define-property@npm:2.0.2" - dependencies: - is-descriptor: ^1.0.2 - isobject: ^3.0.1 - checksum: 3217ed53fc9eed06ba8da6f4d33e28c68a82e2f2a8ab4d562c4920d8169a166fe7271453675e6c69301466f36a65d7f47edf0cf7f474b9aa52a5ead9c1b13c99 - languageName: node - linkType: hard - "del@npm:^6.0.0": version: 6.1.1 resolution: "del@npm:6.1.1" @@ -20365,14 +19264,7 @@ __metadata: languageName: node linkType: hard -"dequal@npm:^2.0.0": - version: 2.0.2 - resolution: "dequal@npm:2.0.2" - checksum: 86c7a2c59f7b0797ed397c74b5fcdb744e48fc19440b70ad6ac59f57550a96b0faef3f1cfd5760ec5e6d3f7cb101f634f1f80db4e727b1dc8389bf62d977c0a0 - languageName: node - linkType: hard - -"dequal@npm:^2.0.2": +"dequal@npm:^2.0.0, dequal@npm:^2.0.2": version: 2.0.3 resolution: "dequal@npm:2.0.3" checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 @@ -20463,13 +19355,6 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^27.5.1": - version: 27.5.1 - resolution: "diff-sequences@npm:27.5.1" - checksum: a00db5554c9da7da225db2d2638d85f8e41124eccbd56cbaefb3b276dcbb1c1c2ad851c32defe2055a54a4806f030656cbf6638105fd6ce97bb87b90b32a33ca - languageName: node - linkType: hard - "diff-sequences@npm:^29.0.0": version: 29.0.0 resolution: "diff-sequences@npm:29.0.0" @@ -20706,13 +19591,20 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:=2.3.10, dompurify@npm:^2.2.7, dompurify@npm:^2.2.9, dompurify@npm:^2.3.6": +"dompurify@npm:=2.3.10": version: 2.3.10 resolution: "dompurify@npm:2.3.10" checksum: ee343876b4c065e82d194818c66af76a6d2290264c7db583ad71761c11781fd626f0245f9f4670175d5707c4b8fcfb89adae80bed0418a9426a47ee7f36b0ffc languageName: node linkType: hard +"dompurify@npm:^2.2.7, dompurify@npm:^2.2.9, dompurify@npm:^2.3.6": + version: 2.4.0 + resolution: "dompurify@npm:2.4.0" + checksum: c93ea73cf8e3ba044588450198563e56ce6902e36d0e16e3699df2fa59e82c4fdd11d4ad04ef5024569ce96a35b46f29d0bbea522516add33cd39a7f56a8a675 + languageName: node + linkType: hard + "domutils@npm:^2.5.2, domutils@npm:^2.6.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" @@ -20755,20 +19647,13 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:^0.1.2": +"duplexer@npm:^0.1.2, duplexer@npm:~0.1.1": version: 0.1.2 resolution: "duplexer@npm:0.1.2" checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 languageName: node linkType: hard -"duplexer@npm:~0.1.1": - version: 0.1.1 - resolution: "duplexer@npm:0.1.1" - checksum: fc7937c4a43808493cd63dfa59f4deb6cf02beea783cb17f39677b53ccacb9fba48f87731b8944048dd6dfa8f456d0725f86f3fd587ab780532d9a8e2914e8b7 - languageName: node - linkType: hard - "duplexify@npm:^4.0.0": version: 4.1.1 resolution: "duplexify@npm:4.1.1" @@ -20888,20 +19773,6 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.17": - version: 1.4.35 - resolution: "electron-to-chromium@npm:1.4.35" - checksum: c4d7943abf370ca294129cda8432ea2f83c5b867e708aa33c7953e10f741803cfb23f83ba7341b6a76d76efb649f967b8e7b130ebe1e262971c764537ea5fd9b - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.188": - version: 1.4.194 - resolution: "electron-to-chromium@npm:1.4.194" - checksum: faea6fa96a258228a3e2953160aa6ef467bf86c856d8ee1a7c2d4a1c9edaeca51fb2bf3a0cdb17b1b485e7c9d2144fb63079119d6b210e56b370dd819954139b - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.4.251": version: 1.4.255 resolution: "electron-to-chromium@npm:1.4.255" @@ -21056,27 +19927,27 @@ __metadata: languageName: node linkType: hard -"entities@npm:^2.0.0, entities@npm:~2.1.0": - version: 2.1.0 - resolution: "entities@npm:2.1.0" - checksum: a10a877e489586a3f6a691fe49bf3fc4e58f06c8e80522f08214a5150ba457e7017b447d4913a3fa041bda06ee4c92517baa4d8d75373eaa79369e9639225ffd +"entities@npm:2.2.0, entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 languageName: node linkType: hard -"entities@npm:^4.3.0": - version: 4.3.1 - resolution: "entities@npm:4.3.1" - checksum: e8f6d2bac238494b2355e90551893882d2675142be7e7bdfcb15248ed0652a630678ba0e3a8dc750693e736cb6011f504c27dabeb4cd3330560092e88b105090 - languageName: node - linkType: hard - -"entities@npm:^4.4.0": +"entities@npm:^4.3.0, entities@npm:^4.4.0": version: 4.4.0 resolution: "entities@npm:4.4.0" checksum: 84d250329f4b56b40fa93ed067b194db21e8815e4eb9b59f43a086f0ecd342814f6bc483de8a77da5d64e0f626033192b1b4f1792232a7ea6b970ebe0f3187c2 languageName: node linkType: hard +"entities@npm:~2.1.0": + version: 2.1.0 + resolution: "entities@npm:2.1.0" + checksum: a10a877e489586a3f6a691fe49bf3fc4e58f06c8e80522f08214a5150ba457e7017b447d4913a3fa041bda06ee4c92517baa4d8d75373eaa79369e9639225ffd + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.0 resolution: "env-paths@npm:2.2.0" @@ -21123,35 +19994,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.18.0-next.1, es-abstract@npm:^1.18.0-next.2, es-abstract@npm:^1.19.1": - version: 1.19.1 - resolution: "es-abstract@npm:1.19.1" - dependencies: - call-bind: ^1.0.2 - es-to-primitive: ^1.2.1 - function-bind: ^1.1.1 - get-intrinsic: ^1.1.1 - get-symbol-description: ^1.0.0 - has: ^1.0.3 - has-symbols: ^1.0.2 - internal-slot: ^1.0.3 - is-callable: ^1.2.4 - is-negative-zero: ^2.0.1 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.1 - is-string: ^1.0.7 - is-weakref: ^1.0.1 - object-inspect: ^1.11.0 - object-keys: ^1.1.1 - object.assign: ^4.1.2 - string.prototype.trimend: ^1.0.4 - string.prototype.trimstart: ^1.0.4 - unbox-primitive: ^1.0.1 - checksum: b6be8410672c5364db3fb01eb786e30c7b4bb32b4af63d381c08840f4382c4a168e7855cd338bf59d4f1a1a1138f4d748d1fd40ec65aaa071876f9e9fbfed949 - languageName: node - linkType: hard - -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.2, es-abstract@npm:^1.19.5": +"es-abstract@npm:^1.18.0-next.1, es-abstract@npm:^1.18.0-next.2, es-abstract@npm:^1.19.0, es-abstract@npm:^1.19.1, es-abstract@npm:^1.19.2, es-abstract@npm:^1.19.5": version: 1.20.1 resolution: "es-abstract@npm:1.20.1" dependencies: @@ -21216,200 +20059,100 @@ __metadata: languageName: node linkType: hard -"esbuild-android-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-android-64@npm:0.14.54" +"esbuild-android-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-android-64@npm:0.15.13" conditions: os=android & cpu=x64 languageName: node linkType: hard -"esbuild-android-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-android-64@npm:0.15.8" - dependencies: - esbuild-wasm: 0.15.8 - conditions: os=android & cpu=x64 - languageName: node - linkType: hard - -"esbuild-android-arm64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-android-arm64@npm:0.14.54" +"esbuild-android-arm64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-android-arm64@npm:0.15.13" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"esbuild-android-arm64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-android-arm64@npm:0.15.8" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"esbuild-darwin-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-darwin-64@npm:0.14.54" +"esbuild-darwin-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-darwin-64@npm:0.15.13" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"esbuild-darwin-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-darwin-64@npm:0.15.8" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"esbuild-darwin-arm64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-darwin-arm64@npm:0.14.54" +"esbuild-darwin-arm64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-darwin-arm64@npm:0.15.13" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"esbuild-darwin-arm64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-darwin-arm64@npm:0.15.8" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"esbuild-freebsd-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-freebsd-64@npm:0.14.54" +"esbuild-freebsd-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-freebsd-64@npm:0.15.13" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"esbuild-freebsd-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-freebsd-64@npm:0.15.8" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"esbuild-freebsd-arm64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-freebsd-arm64@npm:0.14.54" +"esbuild-freebsd-arm64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-freebsd-arm64@npm:0.15.13" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"esbuild-freebsd-arm64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-freebsd-arm64@npm:0.15.8" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - -"esbuild-linux-32@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-32@npm:0.14.54" +"esbuild-linux-32@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-32@npm:0.15.13" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"esbuild-linux-32@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-32@npm:0.15.8" - conditions: os=linux & cpu=ia32 - languageName: node - linkType: hard - -"esbuild-linux-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-64@npm:0.14.54" +"esbuild-linux-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-64@npm:0.15.13" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"esbuild-linux-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-64@npm:0.15.8" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"esbuild-linux-arm64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-arm64@npm:0.14.54" +"esbuild-linux-arm64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-arm64@npm:0.15.13" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"esbuild-linux-arm64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-arm64@npm:0.15.8" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - -"esbuild-linux-arm@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-arm@npm:0.14.54" +"esbuild-linux-arm@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-arm@npm:0.15.13" conditions: os=linux & cpu=arm languageName: node linkType: hard -"esbuild-linux-arm@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-arm@npm:0.15.8" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"esbuild-linux-mips64le@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-mips64le@npm:0.14.54" +"esbuild-linux-mips64le@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-mips64le@npm:0.15.13" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"esbuild-linux-mips64le@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-mips64le@npm:0.15.8" - conditions: os=linux & cpu=mips64el - languageName: node - linkType: hard - -"esbuild-linux-ppc64le@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-ppc64le@npm:0.14.54" +"esbuild-linux-ppc64le@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-ppc64le@npm:0.15.13" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"esbuild-linux-ppc64le@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-ppc64le@npm:0.15.8" - conditions: os=linux & cpu=ppc64 - languageName: node - linkType: hard - -"esbuild-linux-riscv64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-riscv64@npm:0.14.54" +"esbuild-linux-riscv64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-riscv64@npm:0.15.13" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"esbuild-linux-riscv64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-riscv64@npm:0.15.8" - conditions: os=linux & cpu=riscv64 - languageName: node - linkType: hard - -"esbuild-linux-s390x@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-linux-s390x@npm:0.14.54" - conditions: os=linux & cpu=s390x - languageName: node - linkType: hard - -"esbuild-linux-s390x@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-linux-s390x@npm:0.15.8" +"esbuild-linux-s390x@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-linux-s390x@npm:0.15.13" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -21430,199 +20173,74 @@ __metadata: languageName: node linkType: hard -"esbuild-netbsd-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-netbsd-64@npm:0.14.54" +"esbuild-netbsd-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-netbsd-64@npm:0.15.13" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"esbuild-netbsd-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-netbsd-64@npm:0.15.8" - conditions: os=netbsd & cpu=x64 - languageName: node - linkType: hard - -"esbuild-openbsd-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-openbsd-64@npm:0.14.54" +"esbuild-openbsd-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-openbsd-64@npm:0.15.13" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"esbuild-openbsd-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-openbsd-64@npm:0.15.8" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - -"esbuild-sunos-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-sunos-64@npm:0.14.54" +"esbuild-sunos-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-sunos-64@npm:0.15.13" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"esbuild-sunos-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-sunos-64@npm:0.15.8" - conditions: os=sunos & cpu=x64 - languageName: node - linkType: hard - -"esbuild-wasm@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-wasm@npm:0.15.8" - bin: - esbuild: bin/esbuild - checksum: 54797a22f42b572ca7f314cb95a8d130f85948a9557bb03775ebdd2f76d60f164ac2a80bb1ee8339f8a7445a1bc5ab28e1b48584c0573aeca9366119dbad7448 - languageName: node - linkType: hard - -"esbuild-windows-32@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-windows-32@npm:0.14.54" +"esbuild-windows-32@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-windows-32@npm:0.15.13" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"esbuild-windows-32@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-windows-32@npm:0.15.8" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"esbuild-windows-64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-windows-64@npm:0.14.54" +"esbuild-windows-64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-windows-64@npm:0.15.13" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"esbuild-windows-64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-windows-64@npm:0.15.8" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"esbuild-windows-arm64@npm:0.14.54": - version: 0.14.54 - resolution: "esbuild-windows-arm64@npm:0.14.54" +"esbuild-windows-arm64@npm:0.15.13": + version: 0.15.13 + resolution: "esbuild-windows-arm64@npm:0.15.13" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"esbuild-windows-arm64@npm:0.15.8": - version: 0.15.8 - resolution: "esbuild-windows-arm64@npm:0.15.8" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"esbuild@npm:^0.14.1, esbuild@npm:^0.14.10": - version: 0.14.54 - resolution: "esbuild@npm:0.14.54" +"esbuild@npm:^0.15.0, esbuild@npm:^0.15.6": + version: 0.15.13 + resolution: "esbuild@npm:0.15.13" dependencies: - "@esbuild/linux-loong64": 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 - dependenciesMeta: - "@esbuild/linux-loong64": - optional: true - esbuild-android-64: - optional: true - esbuild-android-arm64: - optional: true - esbuild-darwin-64: - optional: true - esbuild-darwin-arm64: - optional: true - esbuild-freebsd-64: - optional: true - esbuild-freebsd-arm64: - optional: true - esbuild-linux-32: - optional: true - esbuild-linux-64: - optional: true - esbuild-linux-arm: - optional: true - esbuild-linux-arm64: - optional: true - esbuild-linux-mips64le: - optional: true - esbuild-linux-ppc64le: - optional: true - esbuild-linux-riscv64: - optional: true - esbuild-linux-s390x: - optional: true - esbuild-netbsd-64: - optional: true - esbuild-openbsd-64: - optional: true - esbuild-sunos-64: - optional: true - esbuild-windows-32: - optional: true - esbuild-windows-64: - optional: true - esbuild-windows-arm64: - optional: true - bin: - esbuild: bin/esbuild - checksum: 49e360b1185c797f5ca3a7f5f0a75121494d97ddf691f65ed1796e6257d318f928342a97f559bb8eced6a90cf604dd22db4a30e0dbbf15edd9dbf22459b639af - languageName: node - linkType: hard - -"esbuild@npm:^0.15.6": - version: 0.15.8 - resolution: "esbuild@npm:0.15.8" - dependencies: - "@esbuild/android-arm": 0.15.8 - "@esbuild/linux-loong64": 0.15.8 - esbuild-android-64: 0.15.8 - esbuild-android-arm64: 0.15.8 - esbuild-darwin-64: 0.15.8 - esbuild-darwin-arm64: 0.15.8 - esbuild-freebsd-64: 0.15.8 - esbuild-freebsd-arm64: 0.15.8 - esbuild-linux-32: 0.15.8 - esbuild-linux-64: 0.15.8 - esbuild-linux-arm: 0.15.8 - esbuild-linux-arm64: 0.15.8 - esbuild-linux-mips64le: 0.15.8 - esbuild-linux-ppc64le: 0.15.8 - esbuild-linux-riscv64: 0.15.8 - esbuild-linux-s390x: 0.15.8 - esbuild-netbsd-64: 0.15.8 - esbuild-openbsd-64: 0.15.8 - esbuild-sunos-64: 0.15.8 - esbuild-windows-32: 0.15.8 - esbuild-windows-64: 0.15.8 - esbuild-windows-arm64: 0.15.8 + "@esbuild/android-arm": 0.15.13 + "@esbuild/linux-loong64": 0.15.13 + esbuild-android-64: 0.15.13 + esbuild-android-arm64: 0.15.13 + esbuild-darwin-64: 0.15.13 + esbuild-darwin-arm64: 0.15.13 + esbuild-freebsd-64: 0.15.13 + esbuild-freebsd-arm64: 0.15.13 + esbuild-linux-32: 0.15.13 + esbuild-linux-64: 0.15.13 + esbuild-linux-arm: 0.15.13 + esbuild-linux-arm64: 0.15.13 + esbuild-linux-mips64le: 0.15.13 + esbuild-linux-ppc64le: 0.15.13 + esbuild-linux-riscv64: 0.15.13 + esbuild-linux-s390x: 0.15.13 + esbuild-netbsd-64: 0.15.13 + esbuild-openbsd-64: 0.15.13 + esbuild-sunos-64: 0.15.13 + esbuild-windows-32: 0.15.13 + esbuild-windows-64: 0.15.13 + esbuild-windows-arm64: 0.15.13 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -21670,7 +20288,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 96991dd4bdd628a62d8b962b1e8f1cf6f71ffb06f2c8c8615cba326a2f1800a0029b602c9c5ced0db43d78026ee2cce8bd4c3990411cb0081ede297627735d9d + checksum: ef5f339fae7e2abc4ec5484d4b301efdf40f580e043cbf8a66e19d6c91df82368a810abec61fd5e5db226f0c354f49c36616c9ea04c5412a142a050c10239bf7 languageName: node linkType: hard @@ -21810,8 +20428,8 @@ __metadata: linkType: hard "eslint-plugin-deprecation@npm:^1.3.2": - version: 1.3.2 - resolution: "eslint-plugin-deprecation@npm:1.3.2" + version: 1.3.3 + resolution: "eslint-plugin-deprecation@npm:1.3.3" dependencies: "@typescript-eslint/experimental-utils": ^5.0.0 tslib: ^2.3.1 @@ -21819,7 +20437,7 @@ __metadata: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: ^3.7.5 || ^4.0.0 - checksum: 763776eec6af02ad442bf9ed7e73da198da6969b51418b43f79b3f0a27395e85e9988a3b182e61fab7812a35e17539ba72464d1123a87cc25b195288cbd0c31d + checksum: 5e14d7bc8245a14784623632d43a6210880a4aad4c029fd44686a5516c248287f32406ff230f6e9d238784854b24cd09da953ec8f73d9d19a7c4b3905884e432 languageName: node linkType: hard @@ -21847,8 +20465,8 @@ __metadata: linkType: hard "eslint-plugin-jest@npm:^27.0.0": - version: 27.0.4 - resolution: "eslint-plugin-jest@npm:27.0.4" + version: 27.1.5 + resolution: "eslint-plugin-jest@npm:27.1.5" dependencies: "@typescript-eslint/utils": ^5.10.0 peerDependencies: @@ -21859,7 +20477,7 @@ __metadata: optional: true jest: optional: true - checksum: 8408d8a53bae946527ac4120865c29b3468cf58d8e5ff3b9c75c5303bb5aa451ac7e04329fc004cf6302f84431e6c6c1f2ba9009b0150d1718df58ea490ed3f5 + checksum: 7c9de765793f7161afa0bdcdce67f4d072944152880fa638b25d228188dcee47a4b4aada26c57db72bc10193c96a1979e17afb8a7c3e400e961d8adfbf23ddbe languageName: node linkType: hard @@ -21947,6 +20565,17 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-testing-library@npm:^5.9.1": + version: 5.9.1 + resolution: "eslint-plugin-testing-library@npm:5.9.1" + dependencies: + "@typescript-eslint/utils": ^5.13.0 + peerDependencies: + eslint: ^7.5.0 || ^8.0.0 + checksum: d09f9486945807e9587d52b6979117bc41b750df741567381a06219671096afb318696a0e0db63e253e150fead40e77ef9653ee00f1dda83fc8920e3b3c47107 + languageName: node + linkType: hard + "eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -22009,13 +20638,13 @@ __metadata: linkType: hard "eslint@npm:^8.6.0": - version: 8.23.1 - resolution: "eslint@npm:8.23.1" + version: 8.27.0 + resolution: "eslint@npm:8.27.0" dependencies: - "@eslint/eslintrc": ^1.3.2 - "@humanwhocodes/config-array": ^0.10.4 - "@humanwhocodes/gitignore-to-minimatch": ^1.0.2 + "@eslint/eslintrc": ^1.3.3 + "@humanwhocodes/config-array": ^0.11.6 "@humanwhocodes/module-importer": ^1.0.1 + "@nodelib/fs.walk": ^1.2.8 ajv: ^6.10.0 chalk: ^4.0.0 cross-spawn: ^7.0.2 @@ -22031,14 +20660,14 @@ __metadata: fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 find-up: ^5.0.0 - glob-parent: ^6.0.1 + glob-parent: ^6.0.2 globals: ^13.15.0 - globby: ^11.1.0 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 + is-path-inside: ^3.0.3 js-sdsl: ^4.1.4 js-yaml: ^4.1.0 json-stable-stringify-without-jsonify: ^1.0.1 @@ -22053,7 +20682,7 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: a727e15492786a03b438bcf021db49f715680679846a7b8d79b98ad34576f2a570404ffe882d3c3e26f6359bff7277ef11fae5614bfe8629adb653f20d018c71 + checksum: 153b022d309e1b647a73b1bb0fa98912add699b06e279084155f23c6f2b5fc5abd05411fc1ba81608a24bbfaf044ca079544c16fffa6fc987b8f676c9960a2c4 languageName: node linkType: hard @@ -22188,20 +20817,13 @@ __metadata: languageName: node linkType: hard -"eventemitter2@npm:6.4.7": +"eventemitter2@npm:6.4.7, eventemitter2@npm:^6.4.4": version: 6.4.7 resolution: "eventemitter2@npm:6.4.7" checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66 languageName: node linkType: hard -"eventemitter2@npm:^6.4.4": - version: 6.4.5 - resolution: "eventemitter2@npm:6.4.5" - checksum: 84504f9cf0cc30205cdd46783fe9df3733435e5097f13070b678023110b5ef07847651808ae280cd94c42cd5976880211c7a40321a8ff8fa56f7c5f9c5c11960 - languageName: node - linkType: hard - "eventemitter3@npm:^3.1.0": version: 3.1.2 resolution: "eventemitter3@npm:3.1.2" @@ -22338,7 +20960,7 @@ __metadata: react-router-dom: ^6.3.0 react-use: ^17.2.4 start-server-and-test: ^1.10.11 - zen-observable: ^0.8.15 + zen-observable: ^0.9.0 languageName: unknown linkType: soft @@ -22372,7 +20994,10 @@ __metadata: "@backstage/plugin-azure-sites-backend": "workspace:^" "@backstage/plugin-badges-backend": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-node": "workspace:^" "@backstage/plugin-code-coverage-backend": "workspace:^" + "@backstage/plugin-events-backend": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-graphql-backend": "workspace:^" "@backstage/plugin-jenkins-backend": "workspace:^" "@backstage/plugin-kafka-backend": "workspace:^" @@ -22514,21 +21139,6 @@ __metadata: languageName: node linkType: hard -"expand-brackets@npm:^2.1.4": - version: 2.1.4 - resolution: "expand-brackets@npm:2.1.4" - dependencies: - debug: ^2.3.3 - define-property: ^0.2.5 - extend-shallow: ^2.0.1 - posix-character-classes: ^0.1.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: 1781d422e7edfa20009e2abda673cadb040a6037f0bd30fcd7357304f4f0c284afd420d7622722ca4a016f39b6d091841ab57b401c1f7e2e5131ac65b9f14fa1 - languageName: node - linkType: hard - "expand-template@npm:^2.0.3": version: 2.0.3 resolution: "expand-template@npm:2.0.3" @@ -22642,25 +21252,6 @@ __metadata: languageName: node linkType: hard -"extend-shallow@npm:^2.0.1": - version: 2.0.1 - resolution: "extend-shallow@npm:2.0.1" - dependencies: - is-extendable: ^0.1.0 - checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 - languageName: node - linkType: hard - -"extend-shallow@npm:^3.0.0, extend-shallow@npm:^3.0.2": - version: 3.0.2 - resolution: "extend-shallow@npm:3.0.2" - dependencies: - assign-symbols: ^1.0.0 - is-extendable: ^1.0.1 - checksum: a920b0cd5838a9995ace31dfd11ab5e79bf6e295aa566910ce53dff19f4b1c0fda2ef21f26b28586c7a2450ca2b42d97bd8c0f5cec9351a819222bf861e02461 - languageName: node - linkType: hard - "extend@npm:3.0.2, extend@npm:^3.0.0, extend@npm:^3.0.2, extend@npm:~3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -22686,22 +21277,6 @@ __metadata: languageName: node linkType: hard -"extglob@npm:^2.0.4": - version: 2.0.4 - resolution: "extglob@npm:2.0.4" - dependencies: - array-unique: ^0.3.2 - define-property: ^1.0.0 - expand-brackets: ^2.1.4 - extend-shallow: ^2.0.1 - fragment-cache: ^0.2.1 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: a41531b8934735b684cef5e8c5a01d0f298d7d384500ceca38793a9ce098125aab04ee73e2d75d5b2901bc5dddd2b64e1b5e3bf19139ea48bac52af4a92f1d00 - languageName: node - linkType: hard - "extract-files@npm:^11.0.0": version: 11.0.0 resolution: "extract-files@npm:11.0.0" @@ -22846,6 +21421,15 @@ __metadata: languageName: node linkType: hard +"fast-xml-parser@npm:3.19.0": + version: 3.19.0 + resolution: "fast-xml-parser@npm:3.19.0" + bin: + xml2js: cli.js + checksum: d9da9145f73d90c05ee2746d80c78eca4da0249dea8c81ea8f1a6e1245e62988ed4a040dbd1c7229b1e0bdcbf69d33c882e0ac337d10c7eedb159a4dc9779327 + languageName: node + linkType: hard + "fastest-stable-stringify@npm:^2.0.2": version: 2.0.2 resolution: "fastest-stable-stringify@npm:2.0.2" @@ -22986,18 +21570,6 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^4.0.0": - version: 4.0.0 - resolution: "fill-range@npm:4.0.0" - dependencies: - extend-shallow: ^2.0.1 - is-number: ^3.0.0 - repeat-string: ^1.6.1 - to-regex-range: ^2.1.0 - checksum: dbb5102467786ab42bc7a3ec7380ae5d6bfd1b5177b2216de89e4a541193f8ba599a6db84651bd2c58c8921db41b8cc3d699ea83b477342d3ce404020f73c298 - languageName: node - linkType: hard - "fill-range@npm:^7.0.1": version: 7.0.1 resolution: "fill-range@npm:7.0.1" @@ -23130,6 +21702,15 @@ __metadata: languageName: node linkType: hard +"find-yarn-workspace-root@npm:^2.0.0": + version: 2.0.0 + resolution: "find-yarn-workspace-root@npm:2.0.0" + dependencies: + micromatch: ^4.0.2 + checksum: fa5ca8f9d08fe7a54ce7c0a5931ff9b7e36f9ee7b9475fb13752bcea80ec6b5f180fa5102d60b376d5526ce924ea3fc6b19301262efa0a5d248dd710f3644242 + languageName: node + linkType: hard + "first-chunk-stream@npm:^2.0.0": version: 2.0.0 resolution: "first-chunk-stream@npm:2.0.0" @@ -23177,27 +21758,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0": - version: 1.14.8 - resolution: "follow-redirects@npm:1.14.8" - peerDependenciesMeta: - debug: - optional: true - checksum: 40c67899c2e3149a27e8b6498a338ff27f39fe138fde8d7f0756cb44b073ba0bfec3d52af28f20c5bdd67263d564d0d8d7b5efefd431de95c18c42f7b4aef457 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.14.8": - version: 1.15.0 - resolution: "follow-redirects@npm:1.15.0" - peerDependenciesMeta: - debug: - optional: true - checksum: eaec81c3e0ae57aae2422e38ad3539d0e7279b3a63f9681eeea319bb683dea67502c4e097136b8ce9721542b4e236e092b6b49e34e326cdd7733c274f0a3f378 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.14.9": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9": version: 1.15.1 resolution: "follow-redirects@npm:1.15.1" peerDependenciesMeta: @@ -23207,13 +21768,6 @@ __metadata: languageName: node linkType: hard -"for-in@npm:^1.0.2": - version: 1.0.2 - resolution: "for-in@npm:1.0.2" - checksum: 09f4ae93ce785d253ac963d94c7f3432d89398bf25ac7a24ed034ca393bf74380bdeccc40e0f2d721a895e54211b07c8fad7132e8157827f6f7f059b70b4043d - languageName: node - linkType: hard - "foreach@npm:^2.0.4, foreach@npm:^2.0.5": version: 2.0.5 resolution: "foreach@npm:2.0.5" @@ -23344,17 +21898,7 @@ __metadata: languageName: node linkType: hard -"formdata-node@npm:^4.0.0": - version: 4.3.0 - resolution: "formdata-node@npm:4.3.0" - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 4.0.0-beta.1 - checksum: d298e941126e3d0389fe4007187fd252f271ef84693710111e7ce98da83e09a1c60111fc44e2a376d17831ec4a4478515049064f45b8763df2025595c91eac9d - languageName: node - linkType: hard - -"formdata-node@npm:^4.3.1": +"formdata-node@npm:^4.0.0, formdata-node@npm:^4.3.1": version: 4.3.2 resolution: "formdata-node@npm:4.3.2" dependencies: @@ -23383,15 +21927,6 @@ __metadata: languageName: node linkType: hard -"fragment-cache@npm:^0.2.1": - version: 0.2.1 - resolution: "fragment-cache@npm:0.2.1" - dependencies: - map-cache: ^0.2.2 - checksum: 1cbbd0b0116b67d5790175de0038a11df23c1cd2e8dcdbade58ebba5594c2d641dade6b4f126d82a7b4a6ffc2ea12e3d387dbb64ea2ae97cf02847d436f60fdc - languageName: node - linkType: hard - "fresh@npm:0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" @@ -23611,20 +22146,7 @@ __metadata: languageName: node linkType: hard -"gaxios@npm:^5.0.0": - version: 5.0.0 - resolution: "gaxios@npm:5.0.0" - dependencies: - abort-controller: ^3.0.0 - extend: ^3.0.2 - https-proxy-agent: ^5.0.0 - is-stream: ^2.0.0 - node-fetch: ^2.6.7 - checksum: d5f81e49db881a6d4fe78ba080a74b27c1be9128e806ff84c26dd6e44539a954551128d7c193d29a3a030510e504448810fa3c3c69af7f21d46572476f1fdef2 - languageName: node - linkType: hard - -"gaxios@npm:^5.0.1": +"gaxios@npm:^5.0.0, gaxios@npm:^5.0.1": version: 5.0.1 resolution: "gaxios@npm:5.0.1" dependencies: @@ -23770,13 +22292,6 @@ __metadata: languageName: node linkType: hard -"get-value@npm:^2.0.3, get-value@npm:^2.0.6": - version: 2.0.6 - resolution: "get-value@npm:2.0.6" - checksum: 5c3b99cb5398ea8016bf46ff17afc5d1d286874d2ad38ca5edb6e87d75c0965b0094cb9a9dddef2c59c23d250702323539a7fbdd870620db38c7e7d7ec87c1eb - languageName: node - linkType: hard - "getopts@npm:2.3.0": version: 2.3.0 resolution: "getopts@npm:2.3.0" @@ -23837,7 +22352,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^6.0.1": +"glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: @@ -23881,7 +22396,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.0": +"glob@npm:^8.0.0, glob@npm:^8.0.1": version: 8.0.3 resolution: "glob@npm:8.0.3" dependencies: @@ -23894,20 +22409,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.1": - version: 8.0.1 - resolution: "glob@npm:8.0.1" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^5.0.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 7ac782f3ef1c08005884447479e68ceb0ad56997eb2003e1e9aefae71bad3cb48eb7c49190d3d6736f2ffcd8af4985d53a46831b3d5e0052cc5756822a38b61a - languageName: node - linkType: hard - "global-agent@npm:^3.0.0": version: 3.0.0 resolution: "global-agent@npm:3.0.0" @@ -24014,9 +22515,9 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^8.0.0": - version: 8.5.2 - resolution: "google-auth-library@npm:8.5.2" +"google-auth-library@npm:^8.0.0, google-auth-library@npm:^8.0.1, google-auth-library@npm:^8.0.2": + version: 8.7.0 + resolution: "google-auth-library@npm:8.7.0" dependencies: arrify: ^2.0.0 base64-js: ^1.3.0 @@ -24027,52 +22528,11 @@ __metadata: gtoken: ^6.1.0 jws: ^4.0.0 lru-cache: ^6.0.0 - checksum: 5ab2904f5da3c119a7c241a1d5a11640468a7da58dfcec8a9cad181cc2723e6662b3c65997906069852d9fa066ba3e4b7f14e11cbb80d541e320b66ead6777dc + checksum: 978d1c5f763aceddbc0218cd76fa578c8ba54a0653cefffaf61847bb8d246ebf26e7fcd276d8885b8a3354c17eef0a11cfae9e60e4df62c01cae4378d4eb78e4 languageName: node linkType: hard -"google-auth-library@npm:^8.0.1, google-auth-library@npm:^8.0.2": - version: 8.4.0 - resolution: "google-auth-library@npm:8.4.0" - dependencies: - arrify: ^2.0.0 - base64-js: ^1.3.0 - ecdsa-sig-formatter: ^1.0.11 - fast-text-encoding: ^1.0.0 - gaxios: ^5.0.0 - gcp-metadata: ^5.0.0 - gtoken: ^6.1.0 - jws: ^4.0.0 - lru-cache: ^6.0.0 - checksum: 4f3f52399c851dff3be797f888e675dbb6099613fcd934aece0d1527b9e9a77e5aadc9be12d137981d2d820a59050b0baf29ea126d2722e20a3e1adf425c93e6 - languageName: node - linkType: hard - -"google-gax@npm:^3.3.0": - version: 3.3.0 - resolution: "google-gax@npm:3.3.0" - dependencies: - "@grpc/grpc-js": ~1.6.0 - "@grpc/proto-loader": ^0.7.0 - "@types/long": ^4.0.0 - abort-controller: ^3.0.0 - duplexify: ^4.0.0 - fast-text-encoding: ^1.0.3 - google-auth-library: ^8.0.2 - is-stream-ended: ^0.1.4 - node-fetch: ^2.6.7 - object-hash: ^3.0.0 - proto3-json-serializer: ^1.0.0 - protobufjs: 7.0.0 - protobufjs-cli: 1.0.0 - retry-request: ^5.0.0 - bin: - compileProtos: build/tools/compileProtos.js - checksum: 536b27f9970d80192a8de5609e119126d80de3843c8c9ad674191d2f6d7bc4ee12c28b4d074f6f36859459734144c201b1fbf413cb710bc77a419094ce5aa68a - languageName: node - linkType: hard - -"google-gax@npm:^3.5.1": +"google-gax@npm:^3.3.0, google-gax@npm:^3.5.1": version: 3.5.1 resolution: "google-gax@npm:3.5.1" dependencies: @@ -24134,14 +22594,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": - version: 4.2.9 - resolution: "graceful-fs@npm:4.2.9" - checksum: 68ea4e07ff2c041ada184f9278b830375f8e0b75154e3f080af6b70f66172fabb4108d19b3863a96b53fc068a310b9b6493d86d1291acc5f3861eb4b79d26ad6 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da @@ -24204,15 +22657,6 @@ __metadata: languageName: node linkType: hard -"graphql-executor@npm:0.0.23": - version: 0.0.23 - resolution: "graphql-executor@npm:0.0.23" - peerDependencies: - graphql: ^15.0.0 || ^16.0.0 - checksum: 22f19ba2d80d73be33246540a5f20c87c1acc53965ac9de05cca12b004f6183f8e4083198c55554f949cdbb0c748eedeb7b9cfc606aea09f30bc7135daa00464 - languageName: node - linkType: hard - "graphql-language-service@npm:^5.0.6": version: 5.0.6 resolution: "graphql-language-service@npm:5.0.6" @@ -24297,31 +22741,7 @@ __metadata: languageName: node linkType: hard -"grpc-docs@npm:^1.0.6": - version: 1.1.2 - resolution: "grpc-docs@npm:1.1.2" - dependencies: - "@improbable-eng/grpc-web": ^0.15.0 - "@types/minimatch": ^3.0.5 - gendocu-public-apis: ^1.0.0 - google-protobuf: ^3.19.1 - grpc-docs: ^1.0.6 - js-yaml: ^4.1.0 - minimatch: ^3.0.4 - react-copy-to-clipboard: ^5.0.4 - react-dom: ^16.13.1 - react-is: ^16.8.0 - react-syntax-highlighter: ^15.4.5 - rollup: ^0.60 - rollup-plugin-smart-asset: ^2.1.2 - styled-components: ^5.3.3 - peerDependencies: - react: ^16.0.0 - checksum: ad1bac493e42bdf4cd363eed80f70f40e80ee3e7605e530958c4155e95e3c9ca6f92f6fa9f28a6c5304327c3926fc6661fc1127b79ca43ef32bc9558a0b093cc - languageName: node - linkType: hard - -"grpc-docs@npm:^1.1.2": +"grpc-docs@npm:^1.0.6, grpc-docs@npm:^1.1.2": version: 1.1.3 resolution: "grpc-docs@npm:1.1.3" dependencies: @@ -24515,45 +22935,6 @@ __metadata: languageName: node linkType: hard -"has-value@npm:^0.3.1": - version: 0.3.1 - resolution: "has-value@npm:0.3.1" - dependencies: - get-value: ^2.0.3 - has-values: ^0.1.4 - isobject: ^2.0.0 - checksum: 29e2a1e6571dad83451b769c7ce032fce6009f65bccace07c2962d3ad4d5530b6743d8f3229e4ecf3ea8e905d23a752c5f7089100c1f3162039fa6dc3976558f - languageName: node - linkType: hard - -"has-value@npm:^1.0.0": - version: 1.0.0 - resolution: "has-value@npm:1.0.0" - dependencies: - get-value: ^2.0.6 - has-values: ^1.0.0 - isobject: ^3.0.0 - checksum: b9421d354e44f03d3272ac39fd49f804f19bc1e4fa3ceef7745df43d6b402053f828445c03226b21d7d934a21ac9cf4bc569396dc312f496ddff873197bbd847 - languageName: node - linkType: hard - -"has-values@npm:^0.1.4": - version: 0.1.4 - resolution: "has-values@npm:0.1.4" - checksum: ab1c4bcaf811ccd1856c11cfe90e62fca9e2b026ebe474233a3d282d8d67e3b59ed85b622c7673bac3db198cb98bd1da2b39300a2f98e453729b115350af49bc - languageName: node - linkType: hard - -"has-values@npm:^1.0.0": - version: 1.0.0 - resolution: "has-values@npm:1.0.0" - dependencies: - is-number: ^3.0.0 - kind-of: ^4.0.0 - checksum: 77e6693f732b5e4cf6c38dfe85fdcefad0fab011af74995c3e83863fabf5e3a836f406d83565816baa0bc0a523c9410db8b990fe977074d61aeb6d8f4fcffa11 - languageName: node - linkType: hard - "has@npm:^1.0.3": version: 1.0.3 resolution: "has@npm:1.0.3" @@ -24636,14 +23017,7 @@ __metadata: languageName: node linkType: hard -"headers-polyfill@npm:^3.0.4": - version: 3.0.7 - resolution: "headers-polyfill@npm:3.0.7" - checksum: ee392c1acdd2be797090837a085b14c8dc79f221e2501508afc1474667fba0627d583e06f9ab5cad57cf9dd570942d3166f791c75b92522a17c69c1e6bfcfbc4 - languageName: node - linkType: hard - -"headers-polyfill@npm:^3.1.0": +"headers-polyfill@npm:^3.0.4, headers-polyfill@npm:^3.1.0": version: 3.1.0 resolution: "headers-polyfill@npm:3.1.0" checksum: a95257065684653b7185efbb9a380c547ea832002991b5adf0d90cd222073da2701be9dc2849d1970ecf15e8c35b383984358566afe6e76ca8ff1dbd7cdce3af @@ -24844,19 +23218,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:1.8.1": - version: 1.8.1 - resolution: "http-errors@npm:1.8.1" - dependencies: - depd: ~1.1.2 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: ">= 1.5.0 < 2" - toidentifier: 1.0.1 - checksum: d3c7e7e776fd51c0a812baff570bdf06fe49a5dc448b700ab6171b1250e4cf7db8b8f4c0b133e4bfe2451022a5790c1ca6c2cae4094dedd6ac8304a1267f91d2 - languageName: node - linkType: hard - "http-errors@npm:2.0.0, http-errors@npm:^2.0.0": version: 2.0.0 resolution: "http-errors@npm:2.0.0" @@ -25034,11 +23395,11 @@ __metadata: linkType: hard "husky@npm:^8.0.0": - version: 8.0.1 - resolution: "husky@npm:8.0.1" + version: 8.0.2 + resolution: "husky@npm:8.0.2" bin: husky: lib/bin.js - checksum: 943a73a13d0201318fd30e83d299bb81d866bd245b69e6277804c3b462638dc1921694cb94c2b8c920a4a187060f7d6058d3365152865406352e934c5fff70dc + checksum: e101656fcb56163d610488f186448c78b132626aa427094489d886ce9374955a90274912b0f3a34af3326eaa74977883b032e5f701d7aaf4554daa5a7931be43 languageName: node linkType: hard @@ -25161,20 +23522,13 @@ __metadata: languageName: node linkType: hard -"immer@npm:^9.0.1": +"immer@npm:^9.0.1, immer@npm:^9.0.7": version: 9.0.16 resolution: "immer@npm:9.0.16" checksum: e9a5ca65c929b329da7a3b7beccf7984271cda7bdd47b2cab619eac3277dcd56598c211b55cc340786b6eff0c06652ac018808d9fd744443f06882364dece6bc languageName: node linkType: hard -"immer@npm:^9.0.7": - version: 9.0.15 - resolution: "immer@npm:9.0.15" - checksum: 92e3d63e810e3c3c2bb61b70c45443e37ef983ad12924e3edaf03725ae5979618f5b473439bb3bb4a8c4769f25132f18dec10ea15c40f0b20da5691ff96ff611 - languageName: node - linkType: hard - "immutable@npm:^3.x.x": version: 3.8.2 resolution: "immutable@npm:3.8.2" @@ -25266,13 +23620,6 @@ __metadata: languageName: node linkType: hard -"indexes-of@npm:^1.0.1": - version: 1.0.1 - resolution: "indexes-of@npm:1.0.1" - checksum: 4f9799b1739a62f3e02d09f6f4162cf9673025282af7fa36e790146e7f4e216dad3e776a25b08536c093209c9fcb5ea7bd04b082d42686a45f58ff401d6da32e - languageName: node - linkType: hard - "indexof@npm:0.0.1": version: 0.0.1 resolution: "indexof@npm:0.0.1" @@ -25370,30 +23717,7 @@ __metadata: languageName: node linkType: hard -"inquirer@npm:^8.0.0": - version: 8.2.4 - resolution: "inquirer@npm:8.2.4" - dependencies: - ansi-escapes: ^4.2.1 - chalk: ^4.1.1 - cli-cursor: ^3.1.0 - cli-width: ^3.0.0 - external-editor: ^3.0.3 - figures: ^3.0.0 - lodash: ^4.17.21 - mute-stream: 0.0.8 - ora: ^5.4.1 - run-async: ^2.4.0 - rxjs: ^7.5.5 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - through: ^2.3.6 - wrap-ansi: ^7.0.0 - checksum: dfcb6529d3af443dfea2241cb471508091b51f5121a088fdb8728b23ec9b349ef0a5e13a0ef2c8e19457b0bed22f7cbbcd561f7a4529d084c562a58c605e2655 - languageName: node - linkType: hard - -"inquirer@npm:^8.2.0": +"inquirer@npm:^8.0.0, inquirer@npm:^8.2.0": version: 8.2.5 resolution: "inquirer@npm:8.2.5" dependencies: @@ -25474,9 +23798,9 @@ __metadata: languageName: node linkType: hard -"ioredis@npm:^5.2.3": - version: 5.2.3 - resolution: "ioredis@npm:5.2.3" +"ioredis@npm:^5.2.4": + version: 5.2.4 + resolution: "ioredis@npm:5.2.4" dependencies: "@ioredis/commands": ^1.1.1 cluster-key-slot: ^1.1.0 @@ -25487,7 +23811,7 @@ __metadata: redis-errors: ^1.2.0 redis-parser: ^3.0.0 standard-as-callback: ^2.1.0 - checksum: 2cb7f0f4217e6774accad3620af1b7114722721c1d1824be2c9f0c2a77ab9629f2e0848d18b1a7208bc37796ae1207cb3e0898fce61900cfe797da0382724ad1 + checksum: c3a7df407a41ae516bede8b6db853c568198b13fe4a4785f66be5cd541087121b9d45fb9a6b1b6a5fb668c29ce52ab4685642b994803bdfa0a35f794ea8ef7ae languageName: node linkType: hard @@ -25536,24 +23860,6 @@ __metadata: languageName: node linkType: hard -"is-accessor-descriptor@npm:^0.1.6": - version: 0.1.6 - resolution: "is-accessor-descriptor@npm:0.1.6" - dependencies: - kind-of: ^3.0.2 - checksum: 3d629a086a9585bc16a83a8e8a3416f400023301855cafb7ccc9a1d63145b7480f0ad28877dcc2cce09492c4ec1c39ef4c071996f24ee6ac626be4217b8ffc8a - languageName: node - linkType: hard - -"is-accessor-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-accessor-descriptor@npm:1.0.0" - dependencies: - kind-of: ^6.0.0 - checksum: 8e475968e9b22f9849343c25854fa24492dbe8ba0dea1a818978f9f1b887339190b022c9300d08c47fe36f1b913d70ce8cbaca00369c55a56705fdb7caed37fe - languageName: node - linkType: hard - "is-alphabetical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphabetical@npm:1.0.4" @@ -25637,13 +23943,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.5": - version: 1.1.6 - resolution: "is-buffer@npm:1.1.6" - checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707 - languageName: node - linkType: hard - "is-buffer@npm:^2.0.0": version: 2.0.4 resolution: "is-buffer@npm:2.0.4" @@ -25667,6 +23966,17 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^2.0.0": + version: 2.0.0 + resolution: "is-ci@npm:2.0.0" + dependencies: + ci-info: ^2.0.0 + bin: + is-ci: bin.js + checksum: 77b869057510f3efa439bbb36e9be429d53b3f51abd4776eeea79ab3b221337fe1753d1e50058a9e2c650d38246108beffb15ccfd443929d77748d8c0cc90144 + languageName: node + linkType: hard + "is-ci@npm:^3.0.0, is-ci@npm:^3.0.1": version: 3.0.1 resolution: "is-ci@npm:3.0.1" @@ -25678,25 +23988,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0, is-core-module@npm:^2.2.0": - version: 2.8.1 - resolution: "is-core-module@npm:2.8.1" - dependencies: - has: ^1.0.3 - checksum: 418b7bc10768a73c41c7ef497e293719604007f88934a6ffc5f7c78702791b8528102fb4c9e56d006d69361549b3d9519440214a74aefc7e0b79e5e4411d377f - languageName: node - linkType: hard - -"is-core-module@npm:^2.8.0, is-core-module@npm:^2.8.1": - version: 2.9.0 - resolution: "is-core-module@npm:2.9.0" - dependencies: - has: ^1.0.3 - checksum: b27034318b4b462f1c8f1dfb1b32baecd651d891a4e2d1922135daeff4141dfced2b82b07aef83ef54275c4a3526aa38da859223664d0868ca24182badb784ce - languageName: node - linkType: hard - -"is-core-module@npm:^2.9.0": +"is-core-module@npm:^2.1.0, is-core-module@npm:^2.2.0, is-core-module@npm:^2.8.1, is-core-module@npm:^2.9.0": version: 2.10.0 resolution: "is-core-module@npm:2.10.0" dependencies: @@ -25705,24 +23997,6 @@ __metadata: languageName: node linkType: hard -"is-data-descriptor@npm:^0.1.4": - version: 0.1.4 - resolution: "is-data-descriptor@npm:0.1.4" - dependencies: - kind-of: ^3.0.2 - checksum: 5c622e078ba933a78338ae398a3d1fc5c23332b395312daf4f74bab4afb10d061cea74821add726cb4db8b946ba36217ee71a24fe71dd5bca4632edb7f6aad87 - languageName: node - linkType: hard - -"is-data-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-data-descriptor@npm:1.0.0" - dependencies: - kind-of: ^6.0.0 - checksum: e705e6816241c013b05a65dc452244ee378d1c3e3842bd140beabe6e12c0d700ef23c91803f971aa7b091fb0573c5da8963af34a2b573337d87bc3e1f53a4e6d - languageName: node - linkType: hard - "is-date-object@npm:^1.0.1": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" @@ -25746,28 +24020,6 @@ __metadata: languageName: node linkType: hard -"is-descriptor@npm:^0.1.0": - version: 0.1.6 - resolution: "is-descriptor@npm:0.1.6" - dependencies: - is-accessor-descriptor: ^0.1.6 - is-data-descriptor: ^0.1.4 - kind-of: ^5.0.0 - checksum: 0f780c1b46b465f71d970fd7754096ffdb7b69fd8797ca1f5069c163eaedcd6a20ec4a50af669075c9ebcfb5266d2e53c8b227e485eefdb0d1fee09aa1dd8ab6 - languageName: node - linkType: hard - -"is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2": - version: 1.0.2 - resolution: "is-descriptor@npm:1.0.2" - dependencies: - is-accessor-descriptor: ^1.0.0 - is-data-descriptor: ^1.0.0 - kind-of: ^6.0.2 - checksum: 2ed623560bee035fb67b23e32ce885700bef8abe3fbf8c909907d86507b91a2c89a9d3a4d835a4d7334dd5db0237a0aeae9ca109c1e4ef1c0e7b577c0846ab5a - languageName: node - linkType: hard - "is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -25777,32 +24029,6 @@ __metadata: languageName: node linkType: hard -"is-dom@npm:^1.0.0": - version: 1.1.0 - resolution: "is-dom@npm:1.1.0" - dependencies: - is-object: ^1.0.1 - is-window: ^1.0.2 - checksum: 72aff0a7366b801c9d598d49452ec06544b52c3da92a0c6c3cacace33bb0c3df5ba1b4e422ac39224773316a553699d5920a1eb136919319f57d00e6384eb41b - languageName: node - linkType: hard - -"is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": - version: 0.1.1 - resolution: "is-extendable@npm:0.1.1" - checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 - languageName: node - linkType: hard - -"is-extendable@npm:^1.0.1": - version: 1.0.1 - resolution: "is-extendable@npm:1.0.1" - dependencies: - is-plain-object: ^2.0.4 - checksum: db07bc1e9de6170de70eff7001943691f05b9d1547730b11be01c0ebfe67362912ba743cf4be6fd20a5e03b4180c685dad80b7c509fe717037e3eee30ad8e84f - languageName: node - linkType: hard - "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -25924,7 +24150,7 @@ __metadata: languageName: node linkType: hard -"is-negative-zero@npm:^2.0.1, is-negative-zero@npm:^2.0.2": +"is-negative-zero@npm:^2.0.2": version: 2.0.2 resolution: "is-negative-zero@npm:2.0.2" checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a @@ -25947,15 +24173,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^3.0.0": - version: 3.0.0 - resolution: "is-number@npm:3.0.0" - dependencies: - kind-of: ^3.0.2 - checksum: 0c62bf8e9d72c4dd203a74d8cfc751c746e75513380fef420cda8237e619a988ee43e678ddb23c87ac24d91ac0fe9f22e4ffb1301a50310c697e9d73ca3994e9 - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -25963,13 +24180,6 @@ __metadata: languageName: node linkType: hard -"is-object@npm:^1.0.1": - version: 1.0.1 - resolution: "is-object@npm:1.0.1" - checksum: 845eea5ecea9723c04809c9c502a19f318b486f796b128a7b8e5a228c7256c3db8c8201043577542075632e292cd4dfeb04627f12f53817d7bd9f30485cf4c34 - languageName: node - linkType: hard - "is-path-cwd@npm:^2.2.0": version: 2.2.0 resolution: "is-path-cwd@npm:2.2.0" @@ -25977,7 +24187,7 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.2": +"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 @@ -26005,7 +24215,7 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": +"is-plain-object@npm:^2.0.4": version: 2.0.4 resolution: "is-plain-object@npm:2.0.4" dependencies: @@ -26107,7 +24317,7 @@ __metadata: languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.1, is-shared-array-buffer@npm:^1.0.2": +"is-shared-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "is-shared-array-buffer@npm:1.0.2" dependencies: @@ -26225,7 +24435,7 @@ __metadata: languageName: node linkType: hard -"is-weakref@npm:^1.0.1, is-weakref@npm:^1.0.2": +"is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" dependencies: @@ -26234,21 +24444,14 @@ __metadata: languageName: node linkType: hard -"is-window@npm:^1.0.2": - version: 1.0.2 - resolution: "is-window@npm:1.0.2" - checksum: aeaacd2ca816d38d4e2fba4670158fba2190061f28a61c5d84df7c479abf8897b8cb634d22cb76cdf7805035e95bebd430faaab6231ac2ebc814eae02d2c8fd4 - languageName: node - linkType: hard - -"is-windows@npm:^1.0.0, is-windows@npm:^1.0.1, is-windows@npm:^1.0.2": +"is-windows@npm:^1.0.0, is-windows@npm:^1.0.1": version: 1.0.2 resolution: "is-windows@npm:1.0.2" checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7 languageName: node linkType: hard -"is-wsl@npm:^2.2.0": +"is-wsl@npm:^2.1.1, is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" dependencies: @@ -26264,13 +24467,6 @@ __metadata: languageName: node linkType: hard -"isarray@npm:1.0.0, isarray@npm:^1.0.0, isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab - languageName: node - linkType: hard - "isarray@npm:2.0.1": version: 2.0.1 resolution: "isarray@npm:2.0.1" @@ -26278,17 +24474,17 @@ __metadata: languageName: node linkType: hard -"isbinaryfile@npm:^4.0.10": - version: 4.0.10 - resolution: "isbinaryfile@npm:4.0.10" - checksum: a6b28db7e23ac7a77d3707567cac81356ea18bd602a4f21f424f862a31d0e7ab4f250759c98a559ece35ffe4d99f0d339f1ab884ffa9795172f632ab8f88e686 +"isarray@npm:^1.0.0, isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab languageName: node linkType: hard -"isbinaryfile@npm:^4.0.8": - version: 4.0.8 - resolution: "isbinaryfile@npm:4.0.8" - checksum: 606e3bb648d1a0dee23459d1d937bb2560e66a5281ec7c9ff50e585402d73321ac268d0f34cb7393125b3ebc4c7962d39e50a01cdb8904b52fce08b7ccd2bf9f +"isbinaryfile@npm:^4.0.10, isbinaryfile@npm:^4.0.8": + version: 4.0.10 + resolution: "isbinaryfile@npm:4.0.10" + checksum: a6b28db7e23ac7a77d3707567cac81356ea18bd602a4f21f424f862a31d0e7ab4f250759c98a559ece35ffe4d99f0d339f1ab884ffa9795172f632ab8f88e686 languageName: node linkType: hard @@ -26306,16 +24502,7 @@ __metadata: languageName: node linkType: hard -"isobject@npm:^2.0.0": - version: 2.1.0 - resolution: "isobject@npm:2.1.0" - dependencies: - isarray: 1.0.0 - checksum: 811c6f5a866877d31f0606a88af4a45f282544de886bf29f6a34c46616a1ae2ed17076cc6bf34c0128f33eecf7e1fcaa2c82cf3770560d3e26810894e96ae79f - languageName: node - linkType: hard - -"isobject@npm:^3.0.0, isobject@npm:^3.0.1": +"isobject@npm:^3.0.1": version: 3.0.1 resolution: "isobject@npm:3.0.1" checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 @@ -26398,14 +24585,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-coverage@npm:^3.0.0": - version: 3.0.0 - resolution: "istanbul-lib-coverage@npm:3.0.0" - checksum: ea57c2428858cc5d1e04c0e28b362950bbf6415e8ba1235cdd6f4c8dc3c57cb950db8b4e8a4f7e33abc240aa1eb816dba0d7285bdb8b70bda22bb2082492dbfc - languageName: node - linkType: hard - -"istanbul-lib-coverage@npm:^3.2.0": +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.0 resolution: "istanbul-lib-coverage@npm:3.2.0" checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 @@ -26605,18 +24785,6 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-diff@npm:27.5.1" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^27.5.1 - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: 8be27c1e1ee57b2bb2bef9c0b233c19621b4c43d53a3c26e2c00a4e805eb4ea11fe1694a06a9fb0e80ffdcfdc0d2b1cb0b85920b3f5c892327ecd1e7bd96b865 - languageName: node - linkType: hard - "jest-diff@npm:^29.0.3": version: 29.0.3 resolution: "jest-diff@npm:29.0.3" @@ -26681,13 +24849,6 @@ __metadata: languageName: node linkType: hard -"jest-get-type@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-get-type@npm:27.5.1" - checksum: 63064ab70195c21007d897c1157bf88ff94a790824a10f8c890392e7d17eda9c3900513cb291ca1c8d5722cad79169764e9a1279f7c8a9c4cd6e9109ff04bbc0 - languageName: node - linkType: hard - "jest-get-type@npm:^29.0.0": version: 29.0.0 resolution: "jest-get-type@npm:29.0.0" @@ -26728,18 +24889,6 @@ __metadata: languageName: node linkType: hard -"jest-matcher-utils@npm:^27.0.0": - version: 27.5.1 - resolution: "jest-matcher-utils@npm:27.5.1" - dependencies: - chalk: ^4.0.0 - jest-diff: ^27.5.1 - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: bb2135fc48889ff3fe73888f6cc7168ddab9de28b51b3148f820c89fdfd2effdcad005f18be67d0b9be80eda208ad47290f62f03d0a33f848db2dd0273c8217a - languageName: node - linkType: hard - "jest-matcher-utils@npm:^29.0.3": version: 29.0.3 resolution: "jest-matcher-utils@npm:29.0.3" @@ -27069,17 +25218,10 @@ __metadata: languageName: node linkType: hard -"jose@npm:^4.1.4": - version: 4.5.0 - resolution: "jose@npm:4.5.0" - checksum: 51142150a9f571ca318842d34ac0daec49fb70bfb6034c68fd46d8c804a8325065876067202310c8ff3cbfc5ca8e44d4712467b4da0d3cadf1e47c96989ca4ca - languageName: node - linkType: hard - -"jose@npm:^4.6.0": - version: 4.9.3 - resolution: "jose@npm:4.9.3" - checksum: 95865830768dcf82774d19e92dc854c5bc9dc5d9c9626a65a2974272e3aca5d2f56678611943f85802431d2d6d6f8bff9548b7cdb7578e6fe61529bd9c82e1d3 +"jose@npm:^4.10.0, jose@npm:^4.6.0": + version: 4.11.0 + resolution: "jose@npm:4.11.0" + checksum: 8d81e978e0da306911b61b1de1e2d78bd4903b4aa68a4b338b7c89c41edc3d56aea4d5ef4784a078a630dd6aa81f6328901ae3ce215f33b90d51ee8ebf4c9dbd languageName: node linkType: hard @@ -27218,9 +25360,9 @@ __metadata: languageName: node linkType: hard -"jscodeshift@npm:^0.13.0": - version: 0.13.1 - resolution: "jscodeshift@npm:0.13.1" +"jscodeshift@npm:^0.14.0": + version: 0.14.0 + resolution: "jscodeshift@npm:0.14.0" dependencies: "@babel/core": ^7.13.16 "@babel/parser": ^7.13.16 @@ -27235,17 +25377,17 @@ __metadata: chalk: ^4.1.2 flow-parser: 0.* graceful-fs: ^4.2.4 - micromatch: ^3.1.10 + micromatch: ^4.0.4 neo-async: ^2.5.0 node-dir: ^0.1.17 - recast: ^0.20.4 + recast: ^0.21.0 temp: ^0.8.4 write-file-atomic: ^2.3.0 peerDependencies: "@babel/preset-env": ^7.1.6 bin: jscodeshift: bin/jscodeshift.js - checksum: 1c35938de5fc29cafec80e2c37d5c3411f85cd5d40e0243b52f2da0c1ab4b659daddfd62de558eca5d562303616f7838097727b651f4ad8e32b1e96f169cdd76 + checksum: 54ea6d639455883336f80b38a70648821c88b7942315dc0fbab01bc34a9ad0f0f78e3bd69304b5ab167e4262d6ed7e6284c6d32525ab01c89d9118df89b3e2a0 languageName: node linkType: hard @@ -27434,15 +25576,15 @@ __metadata: linkType: hard "json-schema-library@npm:^7.0.0": - version: 7.2.1 - resolution: "json-schema-library@npm:7.2.1" + version: 7.3.0 + resolution: "json-schema-library@npm:7.3.0" dependencies: deepmerge: ^4.2.2 fast-deep-equal: ^3.1.3 gson-pointer: ^4.1.1 gson-query: ^5.1.0 valid-url: ^1.0.9 - checksum: 65bc4014cdfe22c4f46d6cb0a0c059d94045128fb96189c4823dff653b6788c2dbab8d5d2e8475bbdc65fd47abf19cedcc3f02df608452c5413fea5d6e675003 + checksum: 3d148d4be1e59e058bd777d247c181e2cb4820f9f5b9c97f7258f88fa73e1c0ed5c8e07c3fef4e1e8e892666def02b2b5fe5366d3d8d2bed09be3752e5593319 languageName: node linkType: hard @@ -27566,14 +25708,7 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.0.0": - version: 3.0.0 - resolution: "jsonc-parser@npm:3.0.0" - checksum: 1df2326f1f9688de30c70ff19c5b2a83ba3b89a1036160da79821d1361090775e9db502dc57a67c11b56e1186fc1ed70b887f25c5febf9a3ec4f91435836c99d - languageName: node - linkType: hard - -"jsonc-parser@npm:^3.2.0": +"jsonc-parser@npm:^3.0.0, jsonc-parser@npm:^3.2.0": version: 3.2.0 resolution: "jsonc-parser@npm:3.2.0" checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 @@ -27763,7 +25898,7 @@ __metadata: languageName: node linkType: hard -"jss@npm:10.6.0, jss@npm:^10.5.1": +"jss@npm:10.6.0": version: 10.6.0 resolution: "jss@npm:10.6.0" dependencies: @@ -27776,7 +25911,7 @@ __metadata: languageName: node linkType: hard -"jss@npm:~10.8.2": +"jss@npm:^10.5.1, jss@npm:~10.8.2": version: 10.8.2 resolution: "jss@npm:10.8.2" dependencies: @@ -27788,17 +25923,7 @@ __metadata: languageName: node linkType: hard -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": - version: 3.2.0 - resolution: "jsx-ast-utils@npm:3.2.0" - dependencies: - array-includes: ^3.1.2 - object.assign: ^4.1.2 - checksum: 9f695c480212868557c5e3cd01082857e101768dc75cb904335d1a805e972d6203baa58ae0b786e7afeab1e8fdb98242fccf22dbc1734595a65845172743877c - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^3.3.2": +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.2": version: 3.3.2 resolution: "jsx-ast-utils@npm:3.3.2" dependencies: @@ -27885,57 +26010,31 @@ __metadata: languageName: node linkType: hard -"keyv-memcache@npm:^1.2.5": - version: 1.2.9 - resolution: "keyv-memcache@npm:1.2.9" - dependencies: - json-buffer: ^3.0.1 - memjs: ^1.3.0 - checksum: d5134c69be50407498b425d4b8a45204d3a69cfcc2572dd089804f95f4fd9516e7bc6e1fce0e90d036a615e79d72fe8f0f9b17c30dbc66ceabf77f891ac4bbcf - languageName: node - linkType: hard - -"keyv@npm:^4.0.0, keyv@npm:^4.0.3": - version: 4.5.0 - resolution: "keyv@npm:4.5.0" +"keyv@npm:^4.0.0, keyv@npm:^4.5.2": + version: 4.5.2 + resolution: "keyv@npm:4.5.2" dependencies: json-buffer: 3.0.1 - checksum: d294873cf88ec8f691e5edeb7b4b884f886c5f021a01902a0e243c362449db2b55419d7fb7187d059add747b7398321e39e44d391b65f94935174ce13452714d + checksum: 13ad58303acd2261c0d4831b4658451603fd159e61daea2121fcb15feb623e75ee328cded0572da9ca76b7b3ceaf8e614f1806c6b3af5db73c9c35a345259651 languageName: node linkType: hard -"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": - version: 3.2.2 - resolution: "kind-of@npm:3.2.2" - dependencies: - is-buffer: ^1.1.5 - checksum: e898df8ca2f31038f27d24f0b8080da7be274f986bc6ed176f37c77c454d76627619e1681f6f9d2e8d2fd7557a18ecc419a6bb54e422abcbb8da8f1a75e4b386 - languageName: node - linkType: hard - -"kind-of@npm:^4.0.0": - version: 4.0.0 - resolution: "kind-of@npm:4.0.0" - dependencies: - is-buffer: ^1.1.5 - checksum: 1b9e7624a8771b5a2489026e820f3bbbcc67893e1345804a56b23a91e9069965854d2a223a7c6ee563c45be9d8c6ff1ef87f28ed5f0d1a8d00d9dcbb067c529f - languageName: node - linkType: hard - -"kind-of@npm:^5.0.0": - version: 5.1.0 - resolution: "kind-of@npm:5.1.0" - checksum: f2a0102ae0cf19c4a953397e552571bad2b588b53282874f25fca7236396e650e2db50d41f9f516bd402536e4df968dbb51b8e69e4d5d4a7173def78448f7bab - languageName: node - linkType: hard - -"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": +"kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": version: 6.0.3 resolution: "kind-of@npm:6.0.3" checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b languageName: node linkType: hard +"klaw-sync@npm:^6.0.0": + version: 6.0.0 + resolution: "klaw-sync@npm:6.0.0" + dependencies: + graceful-fs: ^4.1.11 + checksum: 0da397f8961313c3ef8f79fb63af9002cde5a8fb2aeb1a37351feff0dd6006129c790400c3f5c3b4e757bedcabb13d21ec0a5eaef5a593d59515d4f2c291e475 + languageName: node + linkType: hard + "klaw@npm:^3.0.0": version: 3.0.0 resolution: "klaw@npm:3.0.0" @@ -27952,14 +26051,7 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.0.3": - version: 4.1.4 - resolution: "kleur@npm:4.1.4" - checksum: 7f6db36e378045dec14acd3cbf0b1e59130c09e984ee8b8ce56dd2d2257cfff90389c1e8f8b19bd09dd5d241080566a814b4ccd99fdcef91f59ef93ec33c8a44 - languageName: node - linkType: hard - -"kleur@npm:^4.1.4": +"kleur@npm:^4.0.3, kleur@npm:^4.1.4": version: 4.1.5 resolution: "kleur@npm:4.1.5" checksum: 1dc476e32741acf0b1b5b0627ffd0d722e342c1b0da14de3e8ae97821327ca08f9fb944542fb3c126d90ac5f27f9d804edbe7c585bf7d12ef495d115e0f22c12 @@ -28148,20 +26240,13 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:2.0.5": +"lilconfig@npm:2.0.5, lilconfig@npm:^2.0.3": version: 2.0.5 resolution: "lilconfig@npm:2.0.5" checksum: f7bb9e42656f06930ad04e583026f087508ae408d3526b8b54895e934eb2a966b7aafae569656f2c79a29fe6d779b3ec44ba577e80814734c8655d6f71cdf2d1 languageName: node linkType: hard -"lilconfig@npm:^2.0.3": - version: 2.0.4 - resolution: "lilconfig@npm:2.0.4" - checksum: 02ae530aa49218d782eb79e92c600ea5220828987f85aa3403fa512cadc7efe38c0ac7d0cd2edf600ad3fae1f6c1752f5b4bb78c0d9950435b044d53d507c9e1 - languageName: node - linkType: hard - "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -28304,24 +26389,24 @@ __metadata: linkType: hard "loader-utils@npm:^1.1.0": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" + version: 1.4.2 + resolution: "loader-utils@npm:1.4.2" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 + checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 languageName: node linkType: hard -"loader-utils@npm:^2.0.0": - version: 2.0.0 - resolution: "loader-utils@npm:2.0.0" +"loader-utils@npm:^2.0.0, loader-utils@npm:^2.0.3": + version: 2.0.3 + resolution: "loader-utils@npm:2.0.3" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^2.1.2 - checksum: 6856423131b50b6f5f259da36f498cfd7fc3c3f8bb17777cf87fdd9159e797d4ba4288d9a96415fd8da62c2906960e88f74711dee72d03a9003bddcd0d364a51 + checksum: d055c61ce5927b64cb4af40218606603a7d3a39adb7b6eec116bb31d19203875950e478152dea056de404eced8e87e9bfd336ec636591ded040ea451f63c7d88 languageName: node linkType: hard @@ -28752,13 +26837,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.3.1": - version: 7.3.1 - resolution: "lru-cache@npm:7.3.1" - checksum: 34bb50c015ffc29fd83545e912f28cea6e03fbf41c497fa220c4f131b990f9ddf95babac98745b416cbc6c0d835254d61668d09b8a4ecb476934546afc9e51bd - languageName: node - linkType: hard - "lunr@npm:^2.3.9": version: 2.3.9 resolution: "lunr@npm:2.3.9" @@ -28774,9 +26852,9 @@ __metadata: linkType: hard "luxon@npm:^3.0.0": - version: 3.0.4 - resolution: "luxon@npm:3.0.4" - checksum: d0908c3951da2a10ccf23040210ead23b0da5366a9d0954e7d5db3560189a7bd703d8af1e00084f197effc9cd7158d1bddf32886d98a70d59ce9bc3fe88bbce0 + version: 3.1.0 + resolution: "luxon@npm:3.1.0" + checksum: f8a850b759ba7a2e009d904c522ed7bc264bf4add57578f8948e52a0ed96b627b025b5aad8032295b570ae19fac41f0ffab91bdb128715fb0cc020798a7ba886 languageName: node linkType: hard @@ -28833,31 +26911,7 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^10.0.1": - version: 10.0.2 - resolution: "make-fetch-happen@npm:10.0.2" - dependencies: - agentkeepalive: ^4.2.0 - cacache: ^15.3.0 - http-cache-semantics: ^4.1.0 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^7.3.1 - minipass: ^3.1.6 - minipass-collect: ^1.0.2 - minipass-fetch: ^1.4.1 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.3 - promise-retry: ^2.0.1 - socks-proxy-agent: ^6.1.1 - ssri: ^8.0.1 - checksum: 5a620f84ab9e28673f70b0640b15133cb329ca4dbeec17e24b5029f07b134c52d96ebac150cab99979c48c5e6e99056978ed0321e4ce1e22a4d4d6fc7148c2fd - languageName: node - linkType: hard - -"make-fetch-happen@npm:^10.0.3": +"make-fetch-happen@npm:^10.0.1, make-fetch-happen@npm:^10.0.3": version: 10.2.1 resolution: "make-fetch-happen@npm:10.2.1" dependencies: @@ -28914,7 +26968,7 @@ __metadata: languageName: node linkType: hard -"map-cache@npm:^0.2.0, map-cache@npm:^0.2.2": +"map-cache@npm:^0.2.0": version: 0.2.2 resolution: "map-cache@npm:0.2.2" checksum: 3067cea54285c43848bb4539f978a15dedc63c03022abeec6ef05c8cb6829f920f13b94bcaf04142fc6a088318e564c4785704072910d120d55dbc2e0c421969 @@ -28942,15 +26996,6 @@ __metadata: languageName: node linkType: hard -"map-visit@npm:^1.0.0": - version: 1.0.0 - resolution: "map-visit@npm:1.0.0" - dependencies: - object-visit: ^1.0.0 - checksum: c27045a5021c344fc19b9132eb30313e441863b2951029f8f8b66f79d3d8c1e7e5091578075a996f74e417479506fe9ede28c44ca7bc351a61c9d8073daec36a - languageName: node - linkType: hard - "markdown-it-anchor@npm:^8.4.1": version: 8.6.4 resolution: "markdown-it-anchor@npm:8.6.4" @@ -28983,16 +27028,7 @@ __metadata: languageName: node linkType: hard -"marked@npm:^4.0.10": - version: 4.1.0 - resolution: "marked@npm:4.1.0" - bin: - marked: bin/marked.js - checksum: f0b3732a9d6208c933541342e60eb78029bd046c143a6ade0e76ed80b6174f92b186205a9dfe805e435070806ec475b0e87e62d04348eafd2f761c24281b192a - languageName: node - linkType: hard - -"marked@npm:^4.0.14": +"marked@npm:^4.0.10, marked@npm:^4.0.14": version: 4.1.1 resolution: "marked@npm:4.1.1" bin: @@ -29310,14 +27346,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0": - version: 1.3.0 - resolution: "merge2@npm:1.3.0" - checksum: bff71d47cd8c01edf2222f205f1c312cae0082e2c05b06123b0990605447dc395208367bb1d1635caec6083d3e6bb0756df05ac24cdc15cb630d5af6daa8eb7c - languageName: node - linkType: hard - -"merge2@npm:^1.4.1": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -29678,27 +27707,6 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^3.1.10": - version: 3.1.10 - resolution: "micromatch@npm:3.1.10" - dependencies: - arr-diff: ^4.0.0 - array-unique: ^0.3.2 - braces: ^2.3.1 - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - extglob: ^2.0.4 - fragment-cache: ^0.2.1 - kind-of: ^6.0.2 - nanomatch: ^1.2.9 - object.pick: ^1.3.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.2 - checksum: ad226cba4daa95b4eaf47b2ca331c8d2e038d7b41ae7ed0697cde27f3f1d6142881ab03d4da51b65d9d315eceb5e4cdddb3fbb55f5f72cfa19cf3ea469d054dc - languageName: node - linkType: hard - "micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -29856,12 +27864,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.0.4": - version: 3.0.4 - resolution: "minimatch@npm:3.0.4" +"minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: ^1.1.7 - checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a languageName: node linkType: hard @@ -29883,15 +27891,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - "minimist-options@npm:^4.0.2": version: 4.1.0 resolution: "minimist-options@npm:4.1.0" @@ -29903,14 +27902,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.6": - version: 1.2.6 - resolution: "minimist@npm:1.2.6" - checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb - languageName: node - linkType: hard - -"minimist@npm:^1.2.5": +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.7 resolution: "minimist@npm:1.2.7" checksum: 7346574a1038ca23c32e02252f603801f09384dd1d78b69a943a4e8c2c28730b80e96193882d3d3b22a063445f460e48316b29b8a25addca2d7e5e8f75478bec @@ -30002,25 +27994,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:*": - version: 3.3.4 - resolution: "minipass@npm:3.3.4" - dependencies: - yallist: ^4.0.0 - checksum: 5d95a7738c54852ba78d484141e850c792e062666a2d0c681a5ac1021275beb7e1acb077e59f9523ff1defb80901aea4e30fac10ded9a20a25d819a42916ef1b - languageName: node - linkType: hard - -"minipass@npm:^3.0.0, minipass@npm:^3.1.0, minipass@npm:^3.1.1, minipass@npm:^3.1.3, minipass@npm:^3.1.6": - version: 3.1.6 - resolution: "minipass@npm:3.1.6" - dependencies: - yallist: ^4.0.0 - checksum: 57a04041413a3531a65062452cb5175f93383ef245d6f4a2961d34386eb9aa8ac11ac7f16f791f5e8bbaf1dfb1ef01596870c88e8822215db57aa591a5bb0a77 - languageName: node - linkType: hard - -"minipass@npm:^3.3.5": +"minipass@npm:^3.0.0, minipass@npm:^3.1.0, minipass@npm:^3.1.1, minipass@npm:^3.1.3, minipass@npm:^3.1.6, minipass@npm:^3.3.5": version: 3.3.5 resolution: "minipass@npm:3.3.5" dependencies: @@ -30039,16 +28013,6 @@ __metadata: languageName: node linkType: hard -"mixin-deep@npm:^1.2.0": - version: 1.3.2 - resolution: "mixin-deep@npm:1.3.2" - dependencies: - for-in: ^1.0.2 - is-extendable: ^1.0.1 - checksum: 820d5a51fcb7479f2926b97f2c3bb223546bc915e6b3a3eb5d906dda871bba569863595424a76682f2b15718252954644f3891437cb7e3f220949bed54b1750d - languageName: node - linkType: hard - "mixme@npm:^0.5.1": version: 0.5.4 resolution: "mixme@npm:0.5.4" @@ -30056,14 +28020,7 @@ __metadata: languageName: node linkType: hard -"mkdirp-classic@npm:^0.5.2": - version: 0.5.2 - resolution: "mkdirp-classic@npm:0.5.2" - checksum: 771d69e289bbf1a14390d7971aac8c80182caea55ebab58f9d84fd8ad989fcdee6a13a03506393ef6287ec60359ebb97994e4fea0628369c422f5d4aaa579f42 - languageName: node - linkType: hard - -"mkdirp-classic@npm:^0.5.3": +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" checksum: 3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac @@ -30109,9 +28066,9 @@ __metadata: linkType: hard "mock-fs@npm:^5.1.0, mock-fs@npm:^5.1.1": - version: 5.1.4 - resolution: "mock-fs@npm:5.1.4" - checksum: e5621c9162be71f88ba264c32cbbc2df737b4e243608ca9126f05b6b1410f1ca911e155a36d3785f194b4219438df8fa33d79cd7ef0b8c7701efd0e4a11f0630 + version: 5.2.0 + resolution: "mock-fs@npm:5.2.0" + checksum: c25835247bd26fa4e0189addd61f98973f61a72741e4d2a5694b143a2069b84978443a7ac0fdb1a71aead99273ec22ff4e9c968de11bbd076db020264c5b8312 languageName: node linkType: hard @@ -30199,9 +28156,9 @@ __metadata: languageName: node linkType: hard -"msw@npm:^0.47.0": - version: 0.47.4 - resolution: "msw@npm:0.47.4" +"msw@npm:^0.48.0": + version: 0.48.0 + resolution: "msw@npm:0.48.0" dependencies: "@mswjs/cookies": ^0.2.2 "@mswjs/interceptors": ^0.17.5 @@ -30230,7 +28187,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10ff632641d40384d6622abf4df6399e4ae649db0f676b5d1ee2d0a515ec96f33abe9d4fecba08cdba4b2e43255af419da9eefc020d40a7e10669d0906457197 + checksum: a931232d18ad02c8b98ffb5db507824d619860743eab6ecf2c228a403b5a20e2b167d4e0ef6cdd7ca2c0d1e4cc913dce1a690e80d7ef3ec6724d3ee060abc477 languageName: node linkType: hard @@ -30302,12 +28259,12 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.14.1, nan@npm:^2.15.0": - version: 2.15.0 - resolution: "nan@npm:2.15.0" +"nan@npm:^2.14.1, nan@npm:^2.15.0, nan@npm:^2.17.0": + version: 2.17.0 + resolution: "nan@npm:2.17.0" dependencies: node-gyp: latest - checksum: 33e1bb4dfca447fe37d4bb5889be55de154828632c8d38646db67293a21afd61ed9909cdf1b886214a64707d935926c4e60e2b09de9edfc2ad58de31d6ce8f39 + checksum: ec609aeaf7e68b76592a3ba96b372aa7f5df5b056c1e37410b0f1deefbab5a57a922061e2c5b369bae9c7c6b5e6eecf4ad2dac8833a1a7d3a751e0a7c7f849ed languageName: node linkType: hard @@ -30346,25 +28303,6 @@ __metadata: languageName: node linkType: hard -"nanomatch@npm:^1.2.9": - version: 1.2.13 - resolution: "nanomatch@npm:1.2.13" - dependencies: - arr-diff: ^4.0.0 - array-unique: ^0.3.2 - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - fragment-cache: ^0.2.1 - is-windows: ^1.0.2 - kind-of: ^6.0.2 - object.pick: ^1.3.0 - regex-not: ^1.0.0 - snapdragon: ^0.8.1 - to-regex: ^3.0.1 - checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8 - languageName: node - linkType: hard - "napi-build-utils@npm:^1.0.1": version: 1.0.2 resolution: "napi-build-utils@npm:1.0.2" @@ -30408,7 +28346,14 @@ __metadata: languageName: node linkType: hard -"nise@npm:^5.1.1": +"nice-try@npm:^1.0.4": + version: 1.0.5 + resolution: "nice-try@npm:1.0.5" + checksum: 0b4af3b5bb5d86c289f7a026303d192a7eb4417231fe47245c460baeabae7277bcd8fd9c728fb6bd62c30b3e15cd6620373e2cf33353b095d8b403d3e8a15aff + languageName: node + linkType: hard + +"nise@npm:^5.1.0, nise@npm:^5.1.1": version: 5.1.1 resolution: "nise@npm:5.1.1" dependencies: @@ -30513,6 +28458,26 @@ __metadata: languageName: node linkType: hard +"node-gyp@npm:^9.1.0": + version: 9.3.0 + resolution: "node-gyp@npm:9.3.0" + dependencies: + env-paths: ^2.2.0 + glob: ^7.1.4 + graceful-fs: ^4.2.6 + make-fetch-happen: ^10.0.3 + nopt: ^6.0.0 + npmlog: ^6.0.0 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.2 + which: ^2.0.2 + bin: + node-gyp: bin/node-gyp.js + checksum: 589ddd3ed967724ef425f9624bfa47cf73022640ab3eba6d556e92cdc4ddef33b63fce3a467c93b995a3f61df92eafd3c3d1e8dbe4a2c00c383334487dea99c3 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 9.1.0 resolution: "node-gyp@npm:9.1.0" @@ -30571,20 +28536,6 @@ __metadata: languageName: node linkType: hard -"node-modules-regexp@npm:^1.0.0": - version: 1.0.0 - resolution: "node-modules-regexp@npm:1.0.0" - checksum: 99541903536c5ce552786f0fca7f06b88df595e62e423c21fa86a1674ee2363dad1f7482d1bec20b4bd9fa5f262f88e6e5cb788fc56411113f2fe2e97783a3a7 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.1": - version: 2.0.1 - resolution: "node-releases@npm:2.0.1" - checksum: b20dd8d4bced11f75060f0387e05e76b9dc4a0451f7bb3516eade6f50499ea7768ba95d8a60d520c193402df1e58cb3fe301510cc1c1ad68949c3d57b5149866 - languageName: node - linkType: hard - "node-releases@npm:^2.0.6": version: 2.0.6 resolution: "node-releases@npm:2.0.6" @@ -30634,6 +28585,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^6.0.0": + version: 6.0.0 + resolution: "nopt@npm:6.0.0" + dependencies: + abbrev: ^1.0.0 + bin: + nopt: bin/nopt.js + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + languageName: node + linkType: hard + "normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" @@ -30898,17 +28860,6 @@ __metadata: languageName: node linkType: hard -"object-copy@npm:^0.1.0": - version: 0.1.0 - resolution: "object-copy@npm:0.1.0" - dependencies: - copy-descriptor: ^0.1.0 - define-property: ^0.2.5 - kind-of: ^3.0.3 - checksum: a9e35f07e3a2c882a7e979090360d1a20ab51d1fa19dfdac3aa8873b328a7c4c7683946ee97c824ae40079d848d6740a3788fa14f2185155dab7ed970a72c783 - languageName: node - linkType: hard - "object-hash@npm:3.0.0, object-hash@npm:^3.0.0": version: 3.0.0 resolution: "object-hash@npm:3.0.0" @@ -30923,7 +28874,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.11.0, object-inspect@npm:^1.12.0, object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": +"object-inspect@npm:^1.12.0, object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": version: 1.12.2 resolution: "object-inspect@npm:1.12.2" checksum: a534fc1b8534284ed71f25ce3a496013b7ea030f3d1b77118f6b7b1713829262be9e6243acbcb3ef8c626e2b64186112cb7f6db74e37b2789b9c789ca23048b2 @@ -30937,28 +28888,7 @@ __metadata: languageName: node linkType: hard -"object-visit@npm:^1.0.0": - version: 1.0.1 - resolution: "object-visit@npm:1.0.1" - dependencies: - isobject: ^3.0.0 - checksum: b0ee07f5bf3bb881b881ff53b467ebbde2b37ebb38649d6944a6cd7681b32eedd99da9bd1e01c55facf81f54ed06b13af61aba6ad87f0052982995e09333f790 - languageName: node - linkType: hard - -"object.assign@npm:^4.1.0": - version: 4.1.2 - resolution: "object.assign@npm:4.1.2" - dependencies: - call-bind: ^1.0.0 - define-properties: ^1.1.3 - has-symbols: ^1.0.1 - object-keys: ^1.1.1 - checksum: d621d832ed7b16ac74027adb87196804a500d80d9aca536fccb7ba48d33a7e9306a75f94c1d29cbfa324bc091bfc530bc24789568efdaee6a47fcfa298993814 - languageName: node - linkType: hard - -"object.assign@npm:^4.1.2": +"object.assign@npm:^4.1.0, object.assign@npm:^4.1.2": version: 4.1.4 resolution: "object.assign@npm:4.1.4" dependencies: @@ -31002,15 +28932,6 @@ __metadata: languageName: node linkType: hard -"object.pick@npm:^1.3.0": - version: 1.3.0 - resolution: "object.pick@npm:1.3.0" - dependencies: - isobject: ^3.0.1 - checksum: 77fb6eed57c67adf75e9901187e37af39f052ef601cb4480386436561357eb9e459e820762f01fd02c5c1b42ece839ad393717a6d1850d848ee11fbabb3e580a - languageName: node - linkType: hard - "object.values@npm:^1.1.5": version: 1.1.5 resolution: "object.values@npm:1.1.5" @@ -31030,11 +28951,11 @@ __metadata: linkType: hard "octokit-plugin-create-pull-request@npm:^3.10.0": - version: 3.12.2 - resolution: "octokit-plugin-create-pull-request@npm:3.12.2" + version: 3.13.1 + resolution: "octokit-plugin-create-pull-request@npm:3.13.1" dependencies: "@octokit/types": ^6.8.2 - checksum: 1f23b6ab62f148795eb7d0109bbfbaf022760ccd17eca2d8d6e0dd860ec76d509fcc0e94841caedaf1e5fe48885cec080fdf8c1cddf0736d0c119070eb7f371f + checksum: 169e393046cecc51b9c9be23321086fc60681bfdfe2bcec5477d0916e5b8e3b64b54588f631f61d98677a0561f5d44fa85589abd75ff851122c798795921292b languageName: node linkType: hard @@ -31068,7 +28989,7 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:2.4.1": +"on-finished@npm:2.4.1, on-finished@npm:^2.3.0": version: 2.4.1 resolution: "on-finished@npm:2.4.1" dependencies: @@ -31077,7 +28998,7 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:^2.3.0, on-finished@npm:~2.3.0": +"on-finished@npm:~2.3.0": version: 2.3.0 resolution: "on-finished@npm:2.3.0" dependencies: @@ -31129,6 +29050,16 @@ __metadata: languageName: node linkType: hard +"open@npm:^7.4.2": + version: 7.4.2 + resolution: "open@npm:7.4.2" + dependencies: + is-docker: ^2.0.0 + is-wsl: ^2.1.1 + checksum: 3333900ec0e420d64c23b831bc3467e57031461d843c801f569b2204a1acc3cd7b3ec3c7897afc9dde86491dfa289708eb92bba164093d8bd88fb2c231843c91 + languageName: node + linkType: hard + "open@npm:^8.0.0, open@npm:^8.0.9, open@npm:^8.4.0": version: 8.4.0 resolution: "open@npm:8.4.0" @@ -31157,27 +29088,15 @@ __metadata: languageName: node linkType: hard -"openid-client@npm:^5.1.3": - version: 5.1.10 - resolution: "openid-client@npm:5.1.10" +"openid-client@npm:^5.1.6, openid-client@npm:^5.2.1": + version: 5.3.0 + resolution: "openid-client@npm:5.3.0" dependencies: - jose: ^4.1.4 + jose: ^4.10.0 lru-cache: ^6.0.0 object-hash: ^2.0.1 oidc-token-hash: ^5.0.1 - checksum: 38a4bf08ea4ee4576043968307cf53f0369df224bd025c1bc348b295152df36c47d2a836dfe1505d15c6b79c05f86aadefad798bd3ea3ccbe90834be01f2245c - languageName: node - linkType: hard - -"openid-client@npm:^5.1.6": - version: 5.1.9 - resolution: "openid-client@npm:5.1.9" - dependencies: - jose: ^4.1.4 - lru-cache: ^6.0.0 - object-hash: ^2.0.1 - oidc-token-hash: ^5.0.1 - checksum: 55390a7eceaafdc340a5f2ece576eb4863fcb4cd8840e4a7a1af66bbaf830623b18cf1dd0b8ce472c6f36c6313e78f92db48ca0c10eb8c681a81e5a3d607fc9f + checksum: 27faa298e083daae2a2a99629b25cc89f648302f4845dd1acd04ec6e7105a6edf13a5c38ab1159bcb7b88c5bc54be08e021c911e22f0b8bfcca1b2d686ae3d95 languageName: node linkType: hard @@ -31318,16 +29237,7 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^2.0.0": - version: 2.2.2 - resolution: "p-limit@npm:2.2.2" - dependencies: - p-try: ^2.0.0 - checksum: 20c395084f4bbcb6330c21ed5408a482c7e03bb68fbf9d4667fb0f49de944a7474f788b214ca087090868dfce3f3fff4a4830b0951c8a979469786635b172fb2 - languageName: node - linkType: hard - -"p-limit@npm:^2.2.0": +"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" dependencies: @@ -31717,13 +29627,6 @@ __metadata: languageName: node linkType: hard -"pascalcase@npm:^0.1.1": - version: 0.1.1 - resolution: "pascalcase@npm:0.1.1" - checksum: f83681c3c8ff75fa473a2bb2b113289952f802ff895d435edd717e7cb898b0408cbdb247117a938edcbc5d141020909846cc2b92c47213d764e2a94d2ad2b925 - languageName: node - linkType: hard - "passport-auth0@npm:^1.4.3": version: 1.4.3 resolution: "passport-auth0@npm:1.4.3" @@ -31860,6 +29763,30 @@ __metadata: languageName: node linkType: hard +"patch-package@npm:^6.5.0": + version: 6.5.0 + resolution: "patch-package@npm:6.5.0" + dependencies: + "@yarnpkg/lockfile": ^1.1.0 + chalk: ^4.1.2 + cross-spawn: ^6.0.5 + find-yarn-workspace-root: ^2.0.0 + fs-extra: ^7.0.1 + is-ci: ^2.0.0 + klaw-sync: ^6.0.0 + minimist: ^1.2.6 + open: ^7.4.2 + rimraf: ^2.6.3 + semver: ^5.6.0 + slash: ^2.0.0 + tmp: ^0.0.33 + yaml: ^1.10.2 + bin: + patch-package: index.js + checksum: d300e87617e3fb990d1f78fd5be205b5a5e65dfdf197b1e7f76f3b3dfe1551a03d276cb5ee6b82ab4d57e78f54ddc22bde803eec1b0896560262b276d0b2c4ab + languageName: node + linkType: hard + "path-browserify@npm:0.0.1": version: 0.0.1 resolution: "path-browserify@npm:0.0.1" @@ -31928,6 +29855,13 @@ __metadata: languageName: node linkType: hard +"path-key@npm:^2.0.1": + version: 2.0.1 + resolution: "path-key@npm:2.0.1" + checksum: f7ab0ad42fe3fb8c7f11d0c4f849871e28fbd8e1add65c370e422512fc5887097b9cf34d09c1747d45c942a8c1e26468d6356e2df3f740bf177ab8ca7301ebfd + languageName: node + linkType: hard + "path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -32282,16 +30216,7 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.0": - version: 4.0.1 - resolution: "pirates@npm:4.0.1" - dependencies: - node-modules-regexp: ^1.0.0 - checksum: 091e232aac19f0049a681838fa9fcb4af824b5b1eb0e9325aa07b9d13245bfe3e4fa57a7766b9fdcd19cb89f2c15c688b46023be3047cb288023a0c079d3b2a3 - languageName: node - linkType: hard - -"pirates@npm:^4.0.1, pirates@npm:^4.0.4": +"pirates@npm:^4.0.0, pirates@npm:^4.0.1, pirates@npm:^4.0.4": version: 4.0.5 resolution: "pirates@npm:4.0.5" checksum: c9994e61b85260bec6c4fc0307016340d9b0c4f4b6550a957afaaff0c9b1ad58fbbea5cfcf083860a25cb27a375442e2b0edf52e2e1e40e69934e08dcc52d227 @@ -32371,13 +30296,6 @@ __metadata: languageName: node linkType: hard -"posix-character-classes@npm:^0.1.0": - version: 0.1.1 - resolution: "posix-character-classes@npm:0.1.1" - checksum: dedb99913c60625a16050cfed2fb5c017648fc075be41ac18474e1c6c3549ef4ada201c8bd9bd006d36827e289c571b6092e1ef6e756cdbab2fd7046b25c6442 - languageName: node - linkType: hard - "postcss-calc@npm:^8.0.0": version: 8.0.0 resolution: "postcss-calc@npm:8.0.0" @@ -32738,19 +30656,7 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": - version: 6.0.4 - resolution: "postcss-selector-parser@npm:6.0.4" - dependencies: - cssesc: ^3.0.0 - indexes-of: ^1.0.1 - uniq: ^1.0.1 - util-deprecate: ^1.0.2 - checksum: 2030e3439a5841d0d1bbe3e7a77515bc677397b0073691e8dc4e1168ecd8a7adc8aba2ce7f274d1b2654b73c94818758d335ecbf85e1b29705d17180030f8164 - languageName: node - linkType: hard - -"postcss-selector-parser@npm:^6.0.5": +"postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5": version: 6.0.6 resolution: "postcss-selector-parser@npm:6.0.6" dependencies: @@ -32798,25 +30704,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.1.0": - version: 8.4.17 - resolution: "postcss@npm:8.4.17" +"postcss@npm:^8.1.0, postcss@npm:^8.4.18": + version: 8.4.19 + resolution: "postcss@npm:8.4.19" dependencies: nanoid: ^3.3.4 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: a6d9096dd711e17f7b1d18ff5dcb4fdedf3941d5a3dc8b0e4ea873b8f31972d57f73d6da9a8aed7ff389eb52190ed34f6a94f299a7f5ddc68b08a24a48f77eb9 - languageName: node - linkType: hard - -"postcss@npm:^8.4.7": - version: 8.4.16 - resolution: "postcss@npm:8.4.16" - dependencies: - nanoid: ^3.3.4 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 10eee25efd77868036403858577da0cefaf2e0905feeaba5770d5438ccdddba3d01cba8063e96b8aac4c6daa0ed413dd5ae0554a433a3c4db38df1d134cffc1f + checksum: 62782723a385f92b7525f66d29614624de7c5643855423db3a5efd9287e677650300192749adddbbb6734cea9b1d5f5fd4f6ea00ca3f9a95dbbb88f835f5ca64 languageName: node linkType: hard @@ -32941,7 +30836,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^27.0.0, pretty-format@npm:^27.5.1": +"pretty-format@npm:^27.0.2": version: 27.5.1 resolution: "pretty-format@npm:27.5.1" dependencies: @@ -32952,18 +30847,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^27.0.2": - version: 27.3.1 - resolution: "pretty-format@npm:27.3.1" - dependencies: - "@jest/types": ^27.2.5 - ansi-regex: ^5.0.1 - ansi-styles: ^5.0.0 - react-is: ^17.0.1 - checksum: 2979eae85a4f7ba1c3946faa8f5c6497cc80dc64ba499ccd5fdada267f82dc664f315a4c1cdd4c0b4b97edbae399a7bf0a957cc1b87feb91cd95f1e436834fed - languageName: node - linkType: hard - "pretty-format@npm:^29.0.0, pretty-format@npm:^29.0.3": version: 29.0.3 resolution: "pretty-format@npm:29.0.3" @@ -33144,29 +31027,6 @@ __metadata: languageName: node linkType: hard -"protobufjs-cli@npm:1.0.0": - version: 1.0.0 - resolution: "protobufjs-cli@npm:1.0.0" - dependencies: - chalk: ^4.0.0 - escodegen: ^1.13.0 - espree: ^9.0.0 - estraverse: ^5.1.0 - glob: ^8.0.0 - jsdoc: ^3.6.3 - minimist: ^1.2.0 - semver: ^7.1.2 - tmp: ^0.2.1 - uglify-js: ^3.7.7 - peerDependencies: - protobufjs: ^7.0.0 - bin: - pbjs: bin/pbjs - pbts: bin/pbts - checksum: 3346b3ebb0b8a1e6eb2c319f92d0e193632c8068a4b3f2379e8a655c03c359a7a723606f356014eaba70e23423a9e112c274262dfb36369ca57eb6219248bf38 - languageName: node - linkType: hard - "protobufjs-cli@npm:1.0.2": version: 1.0.2 resolution: "protobufjs-cli@npm:1.0.2" @@ -33190,28 +31050,7 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:7.0.0, protobufjs@npm:^7.0.0": - version: 7.0.0 - resolution: "protobufjs@npm:7.0.0" - dependencies: - "@protobufjs/aspromise": ^1.1.2 - "@protobufjs/base64": ^1.1.2 - "@protobufjs/codegen": ^2.0.4 - "@protobufjs/eventemitter": ^1.1.0 - "@protobufjs/fetch": ^1.1.0 - "@protobufjs/float": ^1.0.2 - "@protobufjs/inquire": ^1.1.0 - "@protobufjs/path": ^1.1.2 - "@protobufjs/pool": ^1.1.0 - "@protobufjs/utf8": ^1.1.0 - "@types/long": ^4.0.1 - "@types/node": ">=13.7.0" - long: ^5.0.0 - checksum: 84c12ceef34d190bb0e08c7203a4e066c66b67fa788ac18575b5c45a269a515c3921b13116e12fe55ffe1fd4831ce208481d44231b75dbe0a8730ab4ca51c84b - languageName: node - linkType: hard - -"protobufjs@npm:7.1.1": +"protobufjs@npm:7.1.1, protobufjs@npm:^7.0.0": version: 7.1.1 resolution: "protobufjs@npm:7.1.1" dependencies: @@ -33231,7 +31070,7 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^6.10.0, protobufjs@npm:^6.11.2": +"protobufjs@npm:^6.11.2": version: 6.11.3 resolution: "protobufjs@npm:6.11.3" dependencies: @@ -33414,13 +31253,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.9.7": - version: 6.9.7 - resolution: "qs@npm:6.9.7" - checksum: 5bbd263332ccf320a1f36d04a2019a5834dc20bcb736431eaccde2a39dcba03fb26d2fd00174f5d7bc26aaad1cad86124b18440883ac042ea2a0fca6170c1bf1 - languageName: node - linkType: hard - "qs@npm:~6.5.2": version: 6.5.2 resolution: "qs@npm:6.5.2" @@ -33489,15 +31321,6 @@ __metadata: languageName: node linkType: hard -"raf@npm:^3.4.0": - version: 3.4.1 - resolution: "raf@npm:3.4.1" - dependencies: - performance-now: ^2.1.0 - checksum: 50ba284e481c8185dbcf45fc4618ba3aec580bb50c9121385d5698cb6012fe516d2015b1df6dd407a7b7c58d44be8086108236affbce1861edd6b44637c8cd52 - languageName: node - linkType: hard - "ramda@npm:^0.28.0": version: 0.28.0 resolution: "ramda@npm:0.28.0" @@ -33555,18 +31378,6 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:2.4.3": - version: 2.4.3 - resolution: "raw-body@npm:2.4.3" - dependencies: - bytes: 3.1.2 - http-errors: 1.8.1 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - checksum: d2961fa3c71c9c22dc2c3fd60ff377bf36dfed7d7a748f2b25d585934a3e9df565bb9aa5bc2e3a716ea941f4bc2a6ddc795c8b0cf7219fb071029b59b1985394 - languageName: node - linkType: hard - "raw-body@npm:2.5.1, raw-body@npm:^2.4.1": version: 2.5.1 resolution: "raw-body@npm:2.5.1" @@ -33639,19 +31450,7 @@ __metadata: languageName: node linkType: hard -"react-copy-to-clipboard@npm:5.0.4": - version: 5.0.4 - resolution: "react-copy-to-clipboard@npm:5.0.4" - dependencies: - copy-to-clipboard: ^3 - prop-types: ^15.5.8 - peerDependencies: - react: ^15.3.0 || ^16.0.0 || ^17.0.0 - checksum: dae8caae192d4937a151ec3ddad540fe4846d28646aee6d90774abcc6a077761926c99f2bcd9506a76a65524ec2c32b5ec1341e8096fcd3f6335365eaf065137 - languageName: node - linkType: hard - -"react-copy-to-clipboard@npm:^5.0.4": +"react-copy-to-clipboard@npm:5.1.0, react-copy-to-clipboard@npm:^5.0.4": version: 5.1.0 resolution: "react-copy-to-clipboard@npm:5.1.0" dependencies: @@ -33832,16 +31631,12 @@ __metadata: languageName: node linkType: hard -"react-inspector@npm:^5.1.1": - version: 5.1.1 - resolution: "react-inspector@npm:5.1.1" - dependencies: - "@babel/runtime": ^7.0.0 - is-dom: ^1.0.0 - prop-types: ^15.0.0 +"react-inspector@npm:^6.0.1": + version: 6.0.1 + resolution: "react-inspector@npm:6.0.1" peerDependencies: - react: ^16.8.4 || ^17.0.0 - checksum: ca9e4c1fedb94e4e956dd3142838c5a25a9d61375aee5e8a74dd623bae09a263098a93f220e8d84c7fd39e569e1fa4297d363ddbc91b15bca91baeb7281d7f4f + react: ^16.8.4 || ^17.0.0 || ^18.0.0 + checksum: 877cbccf36fdc6213abb9611fb9279c4bb76ef7ecb4ec554b3935419a99d55e6d30a80799a054d468d43cc59a9777f21d22d6219a4597bfbd27f3f08a4cdfdc6 languageName: node linkType: hard @@ -33859,14 +31654,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.0.0 - resolution: "react-is@npm:18.0.0" - checksum: d38f6afee4d8d791cdd69c715841c01a503c9b06da6158e0893447cea6ba50cd262dca9bde84127720cf44fd05c58185eafc32accace4bb2deb03b3cdbeb6b6b - languageName: node - linkType: hard - -"react-is@npm:^18.2.0": +"react-is@npm:^18.0.0, react-is@npm:^18.2.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e @@ -33948,18 +31736,6 @@ __metadata: languageName: node linkType: hard -"react-resize-detector@npm:^7.1.2": - version: 7.1.2 - resolution: "react-resize-detector@npm:7.1.2" - dependencies: - lodash: ^4.17.21 - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 55f4abad7f7523d16b081b5ab20f75c539a54a08253ce7e9df473d48386f42ceca6c31584ba9fa26e3528b498ef6685ec77fb9a22cffc97df05fb326d0bf1b26 - languageName: node - linkType: hard - "react-router-beta@npm:react-router@6.0.0-beta.0, react-router@npm:6.0.0-beta.0": version: 6.0.0-beta.0 resolution: "react-router@npm:6.0.0-beta.0" @@ -34020,21 +31796,6 @@ __metadata: linkType: hard "react-smooth@npm:^2.0.0": - version: 2.0.0 - resolution: "react-smooth@npm:2.0.0" - dependencies: - fast-equals: ^2.0.0 - raf: ^3.4.0 - react-transition-group: 2.9.0 - peerDependencies: - prop-types: ^15.6.0 - react: ^15.0.0 || ^16.0.0 || ^17.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 4eff3fb93067b538e046df2c56a2f99b25f4c3a2aafc1c59707d1a0150f7f0afab408afdc1a47ffa3556adbdb5c915d6035a9a28da878e68771dce7568cc6f69 - languageName: node - linkType: hard - -"react-smooth@npm:^2.0.1": version: 2.0.1 resolution: "react-smooth@npm:2.0.1" dependencies: @@ -34060,7 +31821,7 @@ __metadata: languageName: node linkType: hard -"react-syntax-highlighter@npm:^15.4.5": +"react-syntax-highlighter@npm:^15.4.5, react-syntax-highlighter@npm:^15.5.0": version: 15.5.0 resolution: "react-syntax-highlighter@npm:15.5.0" dependencies: @@ -34177,15 +31938,15 @@ __metadata: linkType: hard "react-window@npm:^1.8.6": - version: 1.8.7 - resolution: "react-window@npm:1.8.7" + version: 1.8.8 + resolution: "react-window@npm:1.8.8" dependencies: "@babel/runtime": ^7.0.0 memoize-one: ">=3.1.1 <6" peerDependencies: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 1e122c29224781e70359978287a2e850ccdf509cd71ba16b16ea258725687a62f5c16ab69f52f732b4ed20df583196dbe2a04804f3e4a176bb3e62f3fc910452 + checksum: a19f43b9015fb84e16db983617dac618a8b298881d2ca96ffc2fb00534afd958ee57a00fd0017733b56f8c34dd84e5be59337877aed3c66329ed3b84e8d018ba languageName: node linkType: hard @@ -34337,7 +32098,7 @@ __metadata: languageName: node linkType: hard -"recast@npm:^0.20.3, recast@npm:^0.20.4": +"recast@npm:^0.20.3": version: 0.20.4 resolution: "recast@npm:0.20.4" dependencies: @@ -34349,6 +32110,18 @@ __metadata: languageName: node linkType: hard +"recast@npm:^0.21.0": + version: 0.21.5 + resolution: "recast@npm:0.21.5" + dependencies: + ast-types: 0.15.2 + esprima: ~4.0.0 + source-map: ~0.6.1 + tslib: ^2.0.1 + checksum: 03cc7f57562238ba258d468be67bf7446ce7a707bc87a087891dad15afead46c36e9aaeedf2130e2ab5a465244a9c62bfd4127849761cf8f4085abe2f3e5f485 + languageName: node + linkType: hard + "recharts-scale@npm:^0.4.4": version: 0.4.5 resolution: "recharts-scale@npm:0.4.5" @@ -34358,33 +32131,7 @@ __metadata: languageName: node linkType: hard -"recharts@npm:^2.0.0": - version: 2.1.15 - resolution: "recharts@npm:2.1.15" - dependencies: - "@types/d3-interpolate": ^2.0.0 - "@types/d3-scale": ^3.0.0 - "@types/d3-shape": ^2.0.0 - classnames: ^2.2.5 - d3-interpolate: ^2.0.0 - d3-scale: ^3.0.0 - d3-shape: ^2.0.0 - eventemitter3: ^4.0.1 - lodash: ^4.17.19 - react-is: ^16.10.2 - react-resize-detector: ^7.1.2 - react-smooth: ^2.0.1 - recharts-scale: ^0.4.4 - reduce-css-calc: ^2.1.8 - peerDependencies: - prop-types: ^15.6.0 - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 2f0be89eca6da8a6d899dac8676de145001353b6072b7853d3f04091c38604f80b241b4ef04d4b28268a95df4a8134b565a192077cb6a2903048fc90f19a5def - languageName: node - linkType: hard - -"recharts@npm:^2.1.5": +"recharts@npm:^2.0.0, recharts@npm:^2.1.5": version: 2.1.9 resolution: "recharts@npm:2.1.9" dependencies: @@ -34517,22 +32264,6 @@ __metadata: languageName: node linkType: hard -"regenerate-unicode-properties@npm:^8.2.0": - version: 8.2.0 - resolution: "regenerate-unicode-properties@npm:8.2.0" - dependencies: - regenerate: ^1.4.0 - checksum: ee7db70ab25b95f2e3f39537089fc3eddba0b39fc9b982d6602f127996ce873d8c55584d5428486ca00dc0a85d174d943354943cd4a745cda475c8fe314b4f8a - languageName: node - linkType: hard - -"regenerate@npm:^1.4.0": - version: 1.4.0 - resolution: "regenerate@npm:1.4.0" - checksum: 8b74ff9d6becc577eecf59ce6eb969c1ce4e6fdabf262d024decd59757741a4598d867cde10dc4ef7ca2a1a415bbf05ddda839cd046050c909117966e118bd5b - languageName: node - linkType: hard - "regenerate@npm:^1.4.2": version: 1.4.2 resolution: "regenerate@npm:1.4.2" @@ -34570,16 +32301,6 @@ __metadata: languageName: node linkType: hard -"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": - version: 1.0.2 - resolution: "regex-not@npm:1.0.2" - dependencies: - extend-shallow: ^3.0.2 - safe-regex: ^1.1.0 - checksum: 3081403de79559387a35ef9d033740e41818a559512668cef3d12da4e8a29ef34ee13c8ed1256b07e27ae392790172e8a15c8a06b72962fd4550476cde3d8f77 - languageName: node - linkType: hard - "regexp.prototype.flags@npm:^1.4.1, regexp.prototype.flags@npm:^1.4.3": version: 1.4.3 resolution: "regexp.prototype.flags@npm:1.4.3" @@ -34598,20 +32319,6 @@ __metadata: languageName: node linkType: hard -"regexpu-core@npm:^4.7.1": - version: 4.7.1 - resolution: "regexpu-core@npm:4.7.1" - dependencies: - regenerate: ^1.4.0 - regenerate-unicode-properties: ^8.2.0 - regjsgen: ^0.5.1 - regjsparser: ^0.6.4 - unicode-match-property-ecmascript: ^1.0.4 - unicode-match-property-value-ecmascript: ^1.2.0 - checksum: 368b4aab72132ba3c8bd114822572c920d390ae99d3d219e0c7f872c6a0a3b1fbe30c88188ff90ec6f8e681667fa8e51d84a78bb05c460996a0df6a060b7ae80 - languageName: node - linkType: hard - "regexpu-core@npm:^5.1.0": version: 5.1.0 resolution: "regexpu-core@npm:5.1.0" @@ -34626,13 +32333,6 @@ __metadata: languageName: node linkType: hard -"regjsgen@npm:^0.5.1": - version: 0.5.1 - resolution: "regjsgen@npm:0.5.1" - checksum: 946e4bb6c456bb4612fcd823faffe58b0d742e7ec8b4d0d6d43546827de43479e8f9a3172582b36b90c84d7dd240cb2fec892fc699e4304a51bc377f73e13247 - languageName: node - linkType: hard - "regjsgen@npm:^0.6.0": version: 0.6.0 resolution: "regjsgen@npm:0.6.0" @@ -34640,17 +32340,6 @@ __metadata: languageName: node linkType: hard -"regjsparser@npm:^0.6.4": - version: 0.6.4 - resolution: "regjsparser@npm:0.6.4" - dependencies: - jsesc: ~0.5.0 - bin: - regjsparser: bin/parser - checksum: 6058749f802a519d37ebbd6ee6c584a65045c3ae4822a54d53666fd56dfdc3363c6905cf9840956becf34111793fe284db75d57342f4263291b29da0a404e9fe - languageName: node - linkType: hard - "regjsparser@npm:^0.8.2": version: 0.8.4 resolution: "regjsparser@npm:0.8.4" @@ -34768,14 +32457,7 @@ __metadata: languageName: node linkType: hard -"repeat-element@npm:^1.1.2": - version: 1.1.3 - resolution: "repeat-element@npm:1.1.3" - checksum: 0743a136b484117016ad587577ede60a3ffe604b74e57bd5d7d0aa041fe2f1c956e6b2f3ff83c86f4db9fac022c3fa2da8e58b9d3618b8b4cb1c3d041bcc422f - languageName: node - linkType: hard - -"repeat-string@npm:^1.5.2, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.5.2": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 @@ -34927,13 +32609,6 @@ __metadata: languageName: node linkType: hard -"resolve-url@npm:^0.2.1": - version: 0.2.1 - resolution: "resolve-url@npm:0.2.1" - checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14 - languageName: node - linkType: hard - "resolve.exports@npm:^1.1.0": version: 1.1.0 resolution: "resolve.exports@npm:1.1.0" @@ -34941,20 +32616,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0": - version: 1.21.0 - resolution: "resolve@npm:1.21.0" - dependencies: - is-core-module: ^2.8.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: d7d9092a5c04a048bea16c7e5a2eb605ac3e8363a0cc5644de1fde17d5028e8d5f4343aab1d99bd327b98e91a66ea83e242718150c64dfedcb96e5e7aad6c4f5 - languageName: node - linkType: hard - -"resolve@npm:^1.10.0": +"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0": version: 1.22.1 resolution: "resolve@npm:1.22.1" dependencies: @@ -34967,19 +32629,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.22.0": - version: 1.22.0 - resolution: "resolve@npm:1.22.0" - dependencies: - is-core-module: ^2.8.1 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: a2d14cc437b3a23996f8c7367eee5c7cf8149c586b07ca2ae00e96581ce59455555a1190be9aa92154785cf9f2042646c200d0e00e0bbd2b8a995a93a0ed3e4e - languageName: node - linkType: hard - "resolve@npm:^2.0.0-next.3": version: 2.0.0-next.3 resolution: "resolve@npm:2.0.0-next.3" @@ -35009,20 +32658,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin": - version: 1.21.0 - resolution: "resolve@patch:resolve@npm%3A1.21.0#~builtin::version=1.21.0&hash=07638b" - dependencies: - is-core-module: ^2.8.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: a0a4d1f7409e73190f31f901f8a619960bb3bd4ae38ba3a54c7ea7e1c87758d28a73256bb8d6a35996a903d1bf14f53883f0dcac6c571c063cb8162d813ad26e - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.10.0#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.0#~builtin": version: 1.22.1 resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=07638b" dependencies: @@ -35035,19 +32671,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.22.0#~builtin": - version: 1.22.0 - resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin::version=1.22.0&hash=07638b" - dependencies: - is-core-module: ^2.8.1 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: c79ecaea36c872ee4a79e3db0d3d4160b593f2ca16e031d8283735acd01715a203607e9ded3f91f68899c2937fa0d49390cddbe0fb2852629212f3cda283f4a7 - languageName: node - linkType: hard - "resolve@patch:resolve@^2.0.0-next.3#~builtin": version: 2.0.0-next.3 resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#~builtin::version=2.0.0-next.3&hash=07638b" @@ -35103,13 +32726,6 @@ __metadata: languageName: node linkType: hard -"ret@npm:~0.1.10": - version: 0.1.15 - resolution: "ret@npm:0.1.15" - checksum: d76a9159eb8c946586567bd934358dfc08a36367b3257f7a3d7255fdd7b56597235af23c6afa0d7f0254159e8051f93c918809962ebd6df24ca2a83dbe4d4151 - languageName: node - linkType: hard - "retry-request@npm:^5.0.0": version: 5.0.0 resolution: "retry-request@npm:5.0.0" @@ -35240,8 +32856,8 @@ __metadata: linkType: hard "rollup-plugin-esbuild@npm:^4.7.2": - version: 4.10.1 - resolution: "rollup-plugin-esbuild@npm:4.10.1" + version: 4.10.3 + resolution: "rollup-plugin-esbuild@npm:4.10.3" dependencies: "@rollup/pluginutils": ^4.1.1 debug: ^4.3.3 @@ -35251,7 +32867,7 @@ __metadata: peerDependencies: esbuild: ">=0.10.1" rollup: ^1.20.0 || ^2.0.0 - checksum: 8bc7c90c972e00d6757b92d6ee4c04d9b0f34b61659f4c544b3994091bc5fdfe4ffdcbf56999111da39e39e650eb93001d587843e87bc306322d9869afe4d60b + checksum: 490a6a77573672cfda64a0222bb0dc2c202060bf4e9162571e24f2c26689e0e9faffced9c409eac80b35943dab06d1f0bd8bb3e2d3c6957b6bac1c0d6e5155cc languageName: node linkType: hard @@ -35365,10 +32981,12 @@ __metadata: e2e-test: "workspace:*" eslint: ^8.6.0 eslint-plugin-notice: ^0.9.10 + eslint-plugin-testing-library: ^5.9.1 fs-extra: 10.1.0 husky: ^8.0.0 lint-staged: ^13.0.0 minimist: ^1.2.5 + node-gyp: ^9.1.0 prettier: ^2.2.1 semver: ^7.3.2 shx: ^0.3.2 @@ -35409,7 +33027,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:7.5.5, rxjs@npm:^7.1.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5": +"rxjs@npm:7.5.5": version: 7.5.5 resolution: "rxjs@npm:7.5.5" dependencies: @@ -35427,7 +33045,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.0.0": +"rxjs@npm:^7.0.0, rxjs@npm:^7.1.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5": version: 7.5.6 resolution: "rxjs@npm:7.5.6" dependencies: @@ -35475,15 +33093,6 @@ __metadata: languageName: node linkType: hard -"safe-regex@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex@npm:1.1.0" - dependencies: - ret: ~0.1.10 - checksum: 9a8bba57c87a841f7997b3b951e8e403b1128c1a4fd1182f40cc1a20e2d490593d7c2a21030fadfea320c8e859219019e136f678c6689ed5960b391b822f01d5 - languageName: node - linkType: hard - "safe-stable-stringify@npm:^2.2.0, safe-stable-stringify@npm:^2.3.1": version: 2.3.1 resolution: "safe-stable-stringify@npm:2.3.1" @@ -35629,11 +33238,11 @@ __metadata: linkType: hard "selfsigned@npm:^2.0.0, selfsigned@npm:^2.0.1": - version: 2.0.1 - resolution: "selfsigned@npm:2.0.1" + version: 2.1.1 + resolution: "selfsigned@npm:2.1.1" dependencies: node-forge: ^1 - checksum: 864e65c2f31ca877bce3ccdaa3bdef5e1e992b63b2a03641e00c24cd305bf2acce093431d1fed2e5ae9f526558db4be5e90baa2b3474c0428fcf7e25cc86ac93 + checksum: aa9ce2150a54838978d5c0aee54d7ebe77649a32e4e690eb91775f71fdff773874a4fbafd0ac73d8ec3b702ff8a395c604df4f8e8868528f36fd6c15076fb43a languageName: node linkType: hard @@ -35651,7 +33260,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.6.0, semver@npm:^5.7.1": +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.1": version: 5.7.1 resolution: "semver@npm:5.7.1" bin: @@ -35678,14 +33287,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:~7.3.0": - version: 7.3.7 - resolution: "semver@npm:7.3.7" +"semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:~7.3.0": + version: 7.3.8 + resolution: "semver@npm:7.3.8" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: 2fa3e877568cd6ce769c75c211beaed1f9fce80b28338cadd9d0b6c40f2e2862bafd62c19a6cff42f3d54292b7c623277bcab8816a2b5521cf15210d43e75232 + checksum: ba9c7cbbf2b7884696523450a61fee1a09930d888b7a8d7579025ad93d459b2d1949ee5bbfeb188b2be5f4ac163544c5e98491ad6152df34154feebc2cc337c1 languageName: node linkType: hard @@ -35756,18 +33365,18 @@ __metadata: linkType: hard "serve-handler@npm:^6.1.3": - version: 6.1.3 - resolution: "serve-handler@npm:6.1.3" + version: 6.1.5 + resolution: "serve-handler@npm:6.1.5" dependencies: bytes: 3.0.0 content-disposition: 0.5.2 fast-url-parser: 1.1.3 mime-types: 2.1.18 - minimatch: 3.0.4 + minimatch: 3.1.2 path-is-inside: 1.0.2 path-to-regexp: 2.2.1 range-parser: 1.2.0 - checksum: 384c1bc10add07a554207f918acaa75af47fcfd8fb89e070faa3468ab45ec5bbc9f976e62d659b6b63404edcf5c54efb7e0a48f3f55946eec83b62b283b9837e + checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc languageName: node linkType: hard @@ -35819,18 +33428,6 @@ __metadata: languageName: node linkType: hard -"set-value@npm:^2.0.0, set-value@npm:^2.0.1": - version: 2.0.1 - resolution: "set-value@npm:2.0.1" - dependencies: - extend-shallow: ^2.0.1 - is-extendable: ^0.1.1 - is-plain-object: ^2.0.3 - split-string: ^3.0.1 - checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601 - languageName: node - linkType: hard - "set-value@npm:^4.1.0": version: 4.1.0 resolution: "set-value@npm:4.1.0" @@ -36026,6 +33623,20 @@ __metadata: languageName: node linkType: hard +"sinon@npm:^11.1.1": + version: 11.1.2 + resolution: "sinon@npm:11.1.2" + dependencies: + "@sinonjs/commons": ^1.8.3 + "@sinonjs/fake-timers": ^7.1.2 + "@sinonjs/samsam": ^6.0.2 + diff: ^5.0.0 + nise: ^5.1.0 + supports-color: ^7.2.0 + checksum: 1d01377e230c9ba976bf33f28b588bae7901b0b5a503d2f6b2a7914b0dbaa9f09823481926c6f2abed820123c7fa865519695af3ae2e9ba18d8b025616163501 + languageName: node + linkType: hard + "sinon@npm:^13.0.2": version: 13.0.2 resolution: "sinon@npm:13.0.2" @@ -36054,6 +33665,13 @@ __metadata: languageName: node linkType: hard +"slash@npm:^2.0.0": + version: 2.0.0 + resolution: "slash@npm:2.0.0" + checksum: 512d4350735375bd11647233cb0e2f93beca6f53441015eea241fe784d8068281c3987fbaa93e7ef1c38df68d9c60013045c92837423c69115297d6169aa85e6 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -36126,42 +33744,6 @@ __metadata: languageName: node linkType: hard -"snapdragon-node@npm:^2.0.1": - version: 2.1.1 - resolution: "snapdragon-node@npm:2.1.1" - dependencies: - define-property: ^1.0.0 - isobject: ^3.0.0 - snapdragon-util: ^3.0.1 - checksum: 9bb57d759f9e2a27935dbab0e4a790137adebace832b393e350a8bf5db461ee9206bb642d4fe47568ee0b44080479c8b4a9ad0ebe3712422d77edf9992a672fd - languageName: node - linkType: hard - -"snapdragon-util@npm:^3.0.1": - version: 3.0.1 - resolution: "snapdragon-util@npm:3.0.1" - dependencies: - kind-of: ^3.2.0 - checksum: 684997dbe37ec995c03fd3f412fba2b711fc34cb4010452b7eb668be72e8811a86a12938b511e8b19baf853b325178c56d8b78d655305e5cfb0bb8b21677e7b7 - languageName: node - linkType: hard - -"snapdragon@npm:^0.8.1": - version: 0.8.2 - resolution: "snapdragon@npm:0.8.2" - dependencies: - base: ^0.11.1 - debug: ^2.2.0 - define-property: ^0.2.5 - extend-shallow: ^2.0.1 - map-cache: ^0.2.2 - source-map: ^0.5.6 - source-map-resolve: ^0.5.0 - use: ^3.1.0 - checksum: a197f242a8f48b11036563065b2487e9b7068f50a20dd81d9161eca6af422174fc158b8beeadbe59ce5ef172aa5718143312b3aebaae551c124b7824387c8312 - languageName: node - linkType: hard - "socket.io-adapter@npm:~1.1.0": version: 1.1.2 resolution: "socket.io-adapter@npm:1.1.2" @@ -36189,13 +33771,13 @@ __metadata: linkType: hard "socket.io-parser@npm:~3.3.0": - version: 3.3.2 - resolution: "socket.io-parser@npm:3.3.2" + version: 3.3.3 + resolution: "socket.io-parser@npm:3.3.3" dependencies: component-emitter: ~1.3.0 debug: ~3.1.0 isarray: 2.0.1 - checksum: 794b3f374faff583a74e2b4fdf55a01761622022d763a0261e3e13889f3088b288caa0f42f092451f7bcc088a4bbad1c48d86871388ff7d5cc5dfc1b15a928b5 + checksum: 6cf464e324e4207811dbf994822c0aa18ba01d615fbed8e3f069927e0e402fdc9b3ac3d2657f18d481fb8c584b1fd40152ced15b3686982a51ec843c6a76dbc2 languageName: node linkType: hard @@ -36235,7 +33817,7 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^6.0.0, socks-proxy-agent@npm:^6.1.1": +"socks-proxy-agent@npm:^6.0.0": version: 6.1.1 resolution: "socks-proxy-agent@npm:6.1.1" dependencies: @@ -36291,19 +33873,6 @@ __metadata: languageName: node linkType: hard -"source-map-resolve@npm:^0.5.0": - version: 0.5.3 - resolution: "source-map-resolve@npm:0.5.3" - dependencies: - atob: ^2.1.2 - decode-uri-component: ^0.2.0 - resolve-url: ^0.2.1 - source-map-url: ^0.4.0 - urix: ^0.1.0 - checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae - languageName: node - linkType: hard - "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -36324,13 +33893,6 @@ __metadata: languageName: node linkType: hard -"source-map-url@npm:^0.4.0": - version: 0.4.0 - resolution: "source-map-url@npm:0.4.0" - checksum: 63ed54045fcd7b4ec7ca17513f48fdc23b573eef679326ecf1a31333e1aaecc0a9c085adaa7d118283b160e65b71cc72da9e1385f2de4ac5ed68294e3920d719 - languageName: node - linkType: hard - "source-map@npm:0.5.6": version: 0.5.6 resolution: "source-map@npm:0.5.6" @@ -36338,13 +33900,6 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.5.0, source-map@npm:^0.5.6": - version: 0.5.7 - resolution: "source-map@npm:0.5.7" - checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d - languageName: node - linkType: hard - "source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" @@ -36472,15 +34027,6 @@ __metadata: languageName: node linkType: hard -"split-string@npm:^3.0.1, split-string@npm:^3.0.2": - version: 3.1.0 - resolution: "split-string@npm:3.1.0" - dependencies: - extend-shallow: ^3.0.0 - checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c - languageName: node - linkType: hard - "split2@npm:^3.0.0": version: 3.2.2 resolution: "split2@npm:3.2.2" @@ -36690,16 +34236,6 @@ __metadata: languageName: node linkType: hard -"static-extend@npm:^0.1.1": - version: 0.1.2 - resolution: "static-extend@npm:0.1.2" - dependencies: - define-property: ^0.2.5 - object-copy: ^0.1.0 - checksum: 8657485b831f79e388a437260baf22784540417a9b29e11572c87735df24c22b84eda42107403a64b30861b2faf13df9f7fc5525d51f9d1d2303aba5cbf4e12c - languageName: node - linkType: hard - "statuses@npm:2.0.1, statuses@npm:^2.0.0": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -36707,7 +34243,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2": +"statuses@npm:>= 1.4.0 < 2": version: 1.5.0 resolution: "statuses@npm:1.5.0" checksum: c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c @@ -36792,25 +34328,7 @@ __metadata: languageName: node linkType: hard -"strict-event-emitter@npm:^0.2.0": - version: 0.2.0 - resolution: "strict-event-emitter@npm:0.2.0" - dependencies: - events: ^3.3.0 - checksum: b2bc33aa01e66010f6356368df7b043cc2a96645b5a8caf47226f349d1702f844375ece9d90e69ff1714599c4ef959031d23d3ffb224738a286b88fedcb42a4a - languageName: node - linkType: hard - -"strict-event-emitter@npm:^0.2.4": - version: 0.2.4 - resolution: "strict-event-emitter@npm:0.2.4" - dependencies: - events: ^3.3.0 - checksum: fe6af7baf4002910ffd04d16f37c994e7b9f56b4c01c8846a3b394efcea6689a9eba3ebcd5283774476c3a7632aae6b47ef89061b0fbf7f2256b8e07a5cab32d - languageName: node - linkType: hard - -"strict-event-emitter@npm:^0.2.6": +"strict-event-emitter@npm:^0.2.0, strict-event-emitter@npm:^0.2.4, strict-event-emitter@npm:^0.2.6": version: 0.2.7 resolution: "strict-event-emitter@npm:0.2.7" dependencies: @@ -36906,7 +34424,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.4, string.prototype.trimend@npm:^1.0.5": +"string.prototype.trimend@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimend@npm:1.0.5" dependencies: @@ -36917,7 +34435,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trimstart@npm:^1.0.4, string.prototype.trimstart@npm:^1.0.5": +"string.prototype.trimstart@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimstart@npm:1.0.5" dependencies: @@ -37167,8 +34685,8 @@ __metadata: linkType: hard "sucrase@npm:^3.18.0, sucrase@npm:^3.20.2": - version: 3.25.0 - resolution: "sucrase@npm:3.25.0" + version: 3.28.0 + resolution: "sucrase@npm:3.28.0" dependencies: commander: ^4.0.0 glob: 7.1.6 @@ -37179,7 +34697,7 @@ __metadata: bin: sucrase: bin/sucrase sucrase-node: bin/sucrase-node - checksum: 4a20a4a821f46e1010da22417e6edafe637bac9a5414e71fc626a569fd3d266a1fcf010073c7627c296223e41fc871fb30678b6238fb95873e49be7973b8743b + checksum: 6a2369c140cee674988ebcf83538f38b11270e47ebaffc811baabe1db3fc586f1a357d4bbc66388a6b99054ba06a08f31b44b764e777abbd457b9e29332b12d0 languageName: node linkType: hard @@ -37302,8 +34820,8 @@ __metadata: linkType: hard "swagger-ui-react@npm:^4.11.1": - version: 4.14.3 - resolution: "swagger-ui-react@npm:4.14.3" + version: 4.15.5 + resolution: "swagger-ui-react@npm:4.15.5" dependencies: "@babel/runtime-corejs3": ^7.18.9 "@braintree/sanitize-url": =6.0.0 @@ -37317,16 +34835,17 @@ __metadata: js-file-download: ^0.4.12 js-yaml: =4.1.0 lodash: ^4.17.21 + patch-package: ^6.5.0 prop-types: ^15.8.1 randexp: ^0.5.3 randombytes: ^2.1.0 - react-copy-to-clipboard: 5.0.4 + react-copy-to-clipboard: 5.1.0 react-debounce-input: =3.3.0 react-immutable-proptypes: 2.2.0 react-immutable-pure-component: ^2.2.0 - react-inspector: ^5.1.1 + react-inspector: ^6.0.1 react-redux: ^7.2.4 - react-syntax-highlighter: ^15.4.5 + react-syntax-highlighter: ^15.5.0 redux: ^4.1.2 redux-immutable: ^4.0.0 remarkable: ^2.0.1 @@ -37341,7 +34860,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: ae8e932ff7eb0b4be71fd1ad7f00ef3eb461636a83985bd36ea28647f60769e6234a9921ff2f84aa33c370f30b8fa1c30a6ca7cf3c4a6ded963aaf9a337aa197 + checksum: 22a72947da865ebfa9269f66b42c2b50105b6285bcb6546f8f356cf73961f76e397b7d79003641c9569bfb2163ea98e2f3f73a27b5b66843d308786c37362e1c languageName: node linkType: hard @@ -37387,16 +34906,6 @@ __metadata: languageName: node linkType: hard -"sync-fetch@npm:^0.4.0": - version: 0.4.1 - resolution: "sync-fetch@npm:0.4.1" - dependencies: - buffer: ^5.7.1 - node-fetch: ^2.6.1 - checksum: cbd1932d9a8de9da52880c23124313bbc5a81887330e66645d192857ee05eeda2ac5700cd6e89f61eeb57a7c44f2c3da96323ed73a657862fb4a6c82bdbd13bd - languageName: node - linkType: hard - "taffydb@npm:2.6.2": version: 2.6.2 resolution: "taffydb@npm:2.6.2" @@ -37455,9 +34964,9 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.11 - resolution: "tar@npm:6.1.11" +"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.11, tar@npm:^6.1.12, tar@npm:^6.1.2": + version: 6.1.12 + resolution: "tar@npm:6.1.12" dependencies: chownr: ^2.0.0 fs-minipass: ^2.0.0 @@ -37465,7 +34974,7 @@ __metadata: minizlib: ^2.1.1 mkdirp: ^1.0.3 yallist: ^4.0.0 - checksum: a04c07bb9e2d8f46776517d4618f2406fb977a74d914ad98b264fc3db0fe8224da5bec11e5f8902c5b9bcb8ace22d95fbe3c7b36b8593b7dfc8391a25898f32f + checksum: 49d72e4420944e7ede2782d6b0826a6ede6cdab23c7de63470917e7a78166bc4d5b1a96279d3d79a85f1ba5a17cd37c0acbb3cbff19a07447691445b8b051c55 languageName: node linkType: hard @@ -37615,8 +35124,8 @@ __metadata: linkType: hard "testcontainers@npm:^8.1.2": - version: 8.13.1 - resolution: "testcontainers@npm:8.13.1" + version: 8.16.0 + resolution: "testcontainers@npm:8.16.0" dependencies: "@balena/dockerignore": ^1.0.2 "@types/archiver": ^5.3.1 @@ -37630,7 +35139,7 @@ __metadata: properties-reader: ^2.2.0 ssh-remote-port-forward: ^1.0.4 tar-fs: ^2.1.1 - checksum: a15345bed5a7e28cf521a01348ca5c0a9de67e274b628345ac91e6db69793c0f2044fb7634166d849eac1d9ea592c79319bdc7e1ec6c5a0208e2e74548c57a5a + checksum: 2fb8250591691a4bd86640b53e13236ad507ba9e03ac3043683de5e9dd632bc29d52827c22ccfe2b0d28dec6896cbaa56dcb153ce65f7f74212ddefc204e8d6a languageName: node linkType: hard @@ -37839,25 +35348,6 @@ __metadata: languageName: node linkType: hard -"to-object-path@npm:^0.3.0": - version: 0.3.0 - resolution: "to-object-path@npm:0.3.0" - dependencies: - kind-of: ^3.0.2 - checksum: 9425effee5b43e61d720940fa2b889623f77473d459c2ce3d4a580a4405df4403eec7be6b857455908070566352f9e2417304641ed158dda6f6a365fe3e66d70 - languageName: node - linkType: hard - -"to-regex-range@npm:^2.1.0": - version: 2.1.1 - resolution: "to-regex-range@npm:2.1.1" - dependencies: - is-number: ^3.0.0 - repeat-string: ^1.6.1 - checksum: 46093cc14be2da905cc931e442d280b2e544e2bfdb9a24b3cf821be8d342f804785e5736c108d5be026021a05d7b38144980a61917eee3c88de0a5e710e10320 - languageName: node - linkType: hard - "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -37867,18 +35357,6 @@ __metadata: languageName: node linkType: hard -"to-regex@npm:^3.0.1, to-regex@npm:^3.0.2": - version: 3.0.2 - resolution: "to-regex@npm:3.0.2" - dependencies: - define-property: ^2.0.2 - extend-shallow: ^3.0.2 - regex-not: ^1.0.2 - safe-regex: ^1.1.0 - checksum: 4ed4a619059b64e204aad84e4e5f3ea82d97410988bcece7cf6cbfdbf193d11bff48cf53842d88b8bb00b1bfc0d048f61f20f0709e6f393fd8fe0122662d9db4 - languageName: node - linkType: hard - "toggle-selection@npm:^1.0.6": version: 1.0.6 resolution: "toggle-selection@npm:1.0.6" @@ -38133,21 +35611,21 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.3.1, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:~2.3.0": +"tslib@npm:2.3.1, tslib@npm:~2.3.0": version: 2.3.1 resolution: "tslib@npm:2.3.1" checksum: de17a98d4614481f7fcb5cd53ffc1aaf8654313be0291e1bfaee4b4bb31a20494b7d218ff2e15017883e8ea9626599b3b0e0229c18383ba9dce89da2adf15cb9 languageName: node linkType: hard -"tslib@npm:^1.10.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": +"tslib@npm:^1.10.0, tslib@npm:^1.11.1, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:~2.4.0": +"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:~2.4.0": version: 2.4.0 resolution: "tslib@npm:2.4.0" checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 @@ -38386,16 +35864,7 @@ __metadata: languageName: node linkType: hard -"uglify-js@npm:^3.1.4": - version: 3.14.3 - resolution: "uglify-js@npm:3.14.3" - bin: - uglifyjs: bin/uglifyjs - checksum: eef57b4fec031f687bef46182c33de5eff6bc40fec8d46152f3b92bb044602dd524a04e33ca5f7391f82db969b92ef6aded860f8a4ee5f4bf796d7420b030236 - languageName: node - linkType: hard - -"uglify-js@npm:^3.7.7": +"uglify-js@npm:^3.1.4, uglify-js@npm:^3.7.7": version: 3.17.0 resolution: "uglify-js@npm:3.17.0" bin: @@ -38427,7 +35896,7 @@ __metadata: languageName: node linkType: hard -"unbox-primitive@npm:^1.0.1, unbox-primitive@npm:^1.0.2": +"unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" dependencies: @@ -38463,27 +35932,13 @@ __metadata: languageName: node linkType: hard -"underscore@npm:^1.12.1, underscore@npm:^1.9.1": - version: 1.13.1 - resolution: "underscore@npm:1.13.1" - checksum: 69bb4e6dd92c387ad322dd5b105f496fa64896d92ff1eea987610920d452667a12bca0938def4c4d60acd12da62410540fd268e7ca4f2480d89324498382fcac - languageName: node - linkType: hard - -"underscore@npm:~1.13.2": +"underscore@npm:^1.12.1, underscore@npm:^1.9.1, underscore@npm:~1.13.2": version: 1.13.4 resolution: "underscore@npm:1.13.4" checksum: 6b04f66cd454e8793a552dc49c71e24e5208a29b9d9c0af988a96948af79103399c36fb15db43f3629bfed152f8b1fe94f44e1249e9d196069c0fc7edfadb636 languageName: node linkType: hard -"undici@npm:5.5.1": - version: 5.5.1 - resolution: "undici@npm:5.5.1" - checksum: c041c9093df7ec683479a9555581206a7c7bebfc1ed6e8669920e55618461fc4ce08938e2fbf8ef7d692c2813c44392b5ed25c58396ee4a72ffd1f1f953712c9 - languageName: node - linkType: hard - "undici@npm:^5.8.0": version: 5.8.0 resolution: "undici@npm:5.8.0" @@ -38491,13 +35946,6 @@ __metadata: languageName: node linkType: hard -"unicode-canonical-property-names-ecmascript@npm:^1.0.4": - version: 1.0.4 - resolution: "unicode-canonical-property-names-ecmascript@npm:1.0.4" - checksum: cc1973b18d0e1a151711e5551f87f4b3086c4f542cd5142aa691307d5720fd725fa7d36c24e12e944e108b91c72554237b0c236772d35592839434da5506c40f - languageName: node - linkType: hard - "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -38505,16 +35953,6 @@ __metadata: languageName: node linkType: hard -"unicode-match-property-ecmascript@npm:^1.0.4": - version: 1.0.4 - resolution: "unicode-match-property-ecmascript@npm:1.0.4" - dependencies: - unicode-canonical-property-names-ecmascript: ^1.0.4 - unicode-property-aliases-ecmascript: ^1.0.4 - checksum: 08e269fac71b5ace0f8331df9e87b9b533fe97b00c43ea58de69ae81816581490f846050e0c472279a3e7434524feba99915a93816f90dbbc0a30bcbd082da88 - languageName: node - linkType: hard - "unicode-match-property-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-match-property-ecmascript@npm:2.0.0" @@ -38525,13 +35963,6 @@ __metadata: languageName: node linkType: hard -"unicode-match-property-value-ecmascript@npm:^1.2.0": - version: 1.2.0 - resolution: "unicode-match-property-value-ecmascript@npm:1.2.0" - checksum: 2e663cfec8e2cf317b69613566314979f717034ea8f58a237dd63234795044a87337410064fe839774d71e1d7e12195520e9edd69ed8e28f2a9eb28a2db38595 - languageName: node - linkType: hard - "unicode-match-property-value-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-match-property-value-ecmascript@npm:2.0.0" @@ -38539,13 +35970,6 @@ __metadata: languageName: node linkType: hard -"unicode-property-aliases-ecmascript@npm:^1.0.4": - version: 1.1.0 - resolution: "unicode-property-aliases-ecmascript@npm:1.1.0" - checksum: 1a96dc462d251bb1c5237f7bc77956b29f01cefce7f3e7448430742930961557c3d1515a9669715ebb06209bf01072e2f78ba1627247017daa84346414bc02f1 - languageName: node - linkType: hard - "unicode-property-aliases-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-property-aliases-ecmascript@npm:2.0.0" @@ -38577,25 +36001,6 @@ __metadata: languageName: node linkType: hard -"union-value@npm:^1.0.0": - version: 1.0.1 - resolution: "union-value@npm:1.0.1" - dependencies: - arr-union: ^3.1.0 - get-value: ^2.0.6 - is-extendable: ^0.1.1 - set-value: ^2.0.1 - checksum: a3464097d3f27f6aa90cf103ed9387541bccfc006517559381a10e0dffa62f465a9d9a09c9b9c3d26d0f4cbe61d4d010e2fbd710fd4bf1267a768ba8a774b0ba - languageName: node - linkType: hard - -"uniq@npm:^1.0.1": - version: 1.0.1 - resolution: "uniq@npm:1.0.1" - checksum: 8206535f83745ea83f9da7035f3b983fd6ed5e35b8ed7745441944e4065b616bc67cf0d0a23a86b40ee0074426f0607f0a138f9b78e124eb6a7a6a6966055709 - languageName: node - linkType: hard - "unique-filename@npm:^1.1.1": version: 1.1.1 resolution: "unique-filename@npm:1.1.1" @@ -38742,16 +36147,6 @@ __metadata: languageName: node linkType: hard -"unset-value@npm:^1.0.0": - version: 1.0.0 - resolution: "unset-value@npm:1.0.0" - dependencies: - has-value: ^0.3.1 - isobject: ^3.0.0 - checksum: 5990ecf660672be2781fc9fb322543c4aa592b68ed9a3312fa4df0e9ba709d42e823af090fc8f95775b4cd2c9a5169f7388f0cec39238b6d0d55a69fc2ab6b29 - languageName: node - linkType: hard - "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -38759,20 +36154,6 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.4": - version: 1.0.5 - resolution: "update-browserslist-db@npm:1.0.5" - dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 - peerDependencies: - browserslist: ">= 4.21.0" - bin: - browserslist-lint: cli.js - checksum: 7e425fe5dbbebdccf72a84ce70ec47fc74dce561d28f47bc2b84a1c2b84179a862c2261b18ab66a5e73e261c7e2ef9e11c6129112989d4d52e8f75a56bb923f8 - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.0.9": version: 1.0.9 resolution: "update-browserslist-db@npm:1.0.9" @@ -38814,13 +36195,6 @@ __metadata: languageName: node linkType: hard -"urix@npm:^0.1.0": - version: 0.1.0 - resolution: "urix@npm:0.1.0" - checksum: 4c076ecfbf3411e888547fe844e52378ab5ada2d2f27625139011eada79925e77f7fbf0e4016d45e6a9e9adb6b7e64981bd49b22700c7c401c5fc15f423303b3 - languageName: node - linkType: hard - "url-parse@npm:^1.5.8": version: 1.5.10 resolution: "url-parse@npm:1.5.10" @@ -38910,13 +36284,6 @@ __metadata: languageName: node linkType: hard -"use@npm:^3.1.0": - version: 3.1.1 - resolution: "use@npm:3.1.1" - checksum: 08a130289f5238fcbf8f59a18951286a6e660d17acccc9d58d9b69dfa0ee19aa038e8f95721b00b432c36d1629a9e32a464bf2e7e0ae6a244c42ddb30bdd8b33 - languageName: node - linkType: hard - "utf8-byte-length@npm:^1.0.1": version: 1.0.4 resolution: "utf8-byte-length@npm:1.0.4" @@ -39797,17 +37164,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^4.0.0": - version: 4.0.1 - resolution: "write-file-atomic@npm:4.0.1" - dependencies: - imurmurhash: ^0.1.4 - signal-exit: ^3.0.7 - checksum: 8f780232533ca6223c63c9b9c01c4386ca8c625ebe5017a9ed17d037aec19462ae17109e0aa155bff5966ee4ae7a27b67a99f55caf3f32ffd84155e9da3929fc - languageName: node - linkType: hard - -"write-file-atomic@npm:^4.0.1": +"write-file-atomic@npm:^4.0.0, write-file-atomic@npm:^4.0.1": version: 4.0.2 resolution: "write-file-atomic@npm:4.0.2" dependencies: @@ -39817,7 +37174,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.8.1, ws@npm:^8.3.0, ws@npm:^8.8.0": +"ws@npm:8.8.1, ws@npm:^8.3.0, ws@npm:^8.4.2, ws@npm:^8.8.0": version: 8.8.1 resolution: "ws@npm:8.8.1" peerDependencies: @@ -39832,7 +37189,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^5.2.0 || ^6.0.0 || ^7.0.0": +"ws@npm:^5.2.0 || ^6.0.0 || ^7.0.0, ws@npm:^7.3.1, ws@npm:^7.4.6": version: 7.5.9 resolution: "ws@npm:7.5.9" peerDependencies: @@ -39847,36 +37204,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.3.1, ws@npm:^7.4.6": - version: 7.5.6 - resolution: "ws@npm:7.5.6" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 0c2ffc9a539dd61dd2b00ff6cc5c98a3371e2521011fe23da4b3578bb7ac26cbdf7ca8a68e8e08023c122ae247013216dde2a20c908de415a6bcc87bdef68c87 - languageName: node - linkType: hard - -"ws@npm:^8.4.2": - version: 8.5.0 - resolution: "ws@npm:8.5.0" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 76f2f90e40344bf18fd544194e7067812fb1372b2a37865678d8f12afe4b478ff2ebc0c7c0aff82cd5e6b66fc43d889eec0f1865c2365d8f7a66d92da7744a77 - languageName: node - linkType: hard - "ws@npm:~7.4.2": version: 7.4.6 resolution: "ws@npm:7.4.6" @@ -40188,22 +37515,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.0, yargs@npm:^17.2.1": - version: 17.3.1 - resolution: "yargs@npm:17.3.1" - dependencies: - cliui: ^7.0.2 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.3 - y18n: ^5.0.5 - yargs-parser: ^21.0.0 - checksum: 64fc2e32c56739f1d14d2d24acd17a6944c3c8e3e3558f09fc1953ac112e868cc16013d282886b9d5be22187f8b9ed4f60741a6b1011f595ce2718805a656852 - languageName: node - linkType: hard - -"yargs@npm:^17.1.1, yargs@npm:^17.3.1": +"yargs@npm:^17.0.0, yargs@npm:^17.1.1, yargs@npm:^17.2.1, yargs@npm:^17.3.1": version: 17.5.1 resolution: "yargs@npm:17.5.1" dependencies: @@ -40390,6 +37702,13 @@ __metadata: languageName: node linkType: hard +"zen-observable@npm:^0.9.0": + version: 0.9.0 + resolution: "zen-observable@npm:0.9.0" + checksum: d770639f7cb47c89e442b0b87e6955079b9d0f3f7da220f081c3a478ee7b837ee792be4ae8764f2d49fe0afaaa3fbcdc7a88042c3ed471df9ae551de90e82ea2 + languageName: node + linkType: hard + "zenscroll@npm:^4.0.2": version: 4.0.2 resolution: "zenscroll@npm:4.0.2"