diff --git a/.changeset/angry-badgers-beg.md b/.changeset/angry-badgers-beg.md deleted file mode 100644 index 38952aef98..0000000000 --- a/.changeset/angry-badgers-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Internal update for removal of experimental plugin configuration API. diff --git a/.changeset/angry-clocks-exercise.md b/.changeset/angry-clocks-exercise.md deleted file mode 100644 index e7eb6ae1d9..0000000000 --- a/.changeset/angry-clocks-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-nomad-backend': patch ---- - -Added support for the [new backend system](https://backstage.io/docs/backend-system/) diff --git a/.changeset/big-spies-beam.md b/.changeset/big-spies-beam.md deleted file mode 100644 index e5f0ad3eff..0000000000 --- a/.changeset/big-spies-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. diff --git a/.changeset/breezy-dryers-thank.md b/.changeset/breezy-dryers-thank.md deleted file mode 100644 index 7a742db1bf..0000000000 --- a/.changeset/breezy-dryers-thank.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/backend-tasks': patch ---- - -Instrument `backend-tasks` with some counters and histograms for duration. - -`backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. -`backend_tasks.task.runs.duration`: Histogram with the run durations for each task. - -Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. diff --git a/.changeset/calm-carpets-kiss.md b/.changeset/calm-carpets-kiss.md deleted file mode 100644 index b946e4d9c6..0000000000 --- a/.changeset/calm-carpets-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -The `HostDiscovery` export has been deprecated, import it from `@backstage/backend-app-api` instead. diff --git a/.changeset/calm-scissors-rescue.md b/.changeset/calm-scissors-rescue.md deleted file mode 100644 index 4a5318d240..0000000000 --- a/.changeset/calm-scissors-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Create unique temp directory for each `create-app` execution. diff --git a/.changeset/chatty-cobras-cheer.md b/.changeset/chatty-cobras-cheer.md new file mode 100644 index 0000000000..c8203e58c0 --- /dev/null +++ b/.changeset/chatty-cobras-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +Correctly resolve config targets into absolute paths diff --git a/.changeset/chatty-papayas-care.md b/.changeset/chatty-papayas-care.md deleted file mode 100644 index 9f29e94a85..0000000000 --- a/.changeset/chatty-papayas-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-pagerduty': patch ---- - -Minor fix to avoid usage of deprecated prop diff --git a/.changeset/chilled-knives-rule.md b/.changeset/chilled-knives-rule.md new file mode 100644 index 0000000000..f246beabbd --- /dev/null +++ b/.changeset/chilled-knives-rule.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-import': patch +--- + +Create an experimental plugin that is compatible with the declarative integration system, it is exported from the `/alpha` subpath. diff --git a/.changeset/chilly-terms-behave.md b/.changeset/chilly-terms-behave.md new file mode 100644 index 0000000000..8ee1ad8375 --- /dev/null +++ b/.changeset/chilly-terms-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-module-stack-overflow-collator': minor +--- + +Extract a package for the Stack Overflow new backend system plugin. diff --git a/.changeset/clean-forks-love.md b/.changeset/clean-forks-love.md deleted file mode 100644 index f81fe3066b..0000000000 --- a/.changeset/clean-forks-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-sonarqube-backend': patch ---- - -Added support for the [new backend system](https://backstage.io/docs/backend-system/) diff --git a/.changeset/cold-bees-jam.md b/.changeset/cold-bees-jam.md deleted file mode 100644 index 3c6e652d2b..0000000000 --- a/.changeset/cold-bees-jam.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. -This allows the already existing recursive method to work properly when children of entity have children themselves. diff --git a/.changeset/cold-seas-repeat.md b/.changeset/cold-seas-repeat.md deleted file mode 100644 index 0072c4327d..0000000000 --- a/.changeset/cold-seas-repeat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-code-coverage': patch ---- - -Fixed the coverage history statistics to compare newest with oldest record diff --git a/.changeset/create-app-1696937840.md b/.changeset/create-app-1696937840.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1696937840.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/dirty-doors-wave.md b/.changeset/dirty-doors-wave.md deleted file mode 100644 index aad6e8f414..0000000000 --- a/.changeset/dirty-doors-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `github:issues:label` scaffolder action & improve related tests diff --git a/.changeset/dirty-ducks-behave.md b/.changeset/dirty-ducks-behave.md new file mode 100644 index 0000000000..c7bea8ea0a --- /dev/null +++ b/.changeset/dirty-ducks-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fix `RoutedTabs` so that it does not explode without tabs. diff --git a/.changeset/dry-days-invite.md b/.changeset/dry-days-invite.md new file mode 100644 index 0000000000..dcf052acd2 --- /dev/null +++ b/.changeset/dry-days-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Switch from using deprecated `@esbuild-kit/*` packages to using `tsx`. This also switches to using the new module loader `register` API when available, avoiding the experimental warning when starting backends. diff --git a/.changeset/dull-bugs-build.md b/.changeset/dull-bugs-build.md deleted file mode 100644 index 7acfe2a8a2..0000000000 --- a/.changeset/dull-bugs-build.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-elasticsearch': patch -'@backstage/integration': patch ---- - -Ensure that all relevant config fields are properly marked as secret diff --git a/.changeset/dull-dolls-explode.md b/.changeset/dull-dolls-explode.md deleted file mode 100644 index 10088e0818..0000000000 --- a/.changeset/dull-dolls-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-playlist-backend': patch ---- - -Added support to the playlist plugin for the new backend diff --git a/.changeset/dull-experts-kiss.md b/.changeset/dull-experts-kiss.md deleted file mode 100644 index eaea346e49..0000000000 --- a/.changeset/dull-experts-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Fixed an issue causing `EntityPage` to show an error for entities containing special characters diff --git a/.changeset/dull-laws-camp.md b/.changeset/dull-laws-camp.md deleted file mode 100644 index 9a9c7436c5..0000000000 --- a/.changeset/dull-laws-camp.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. - -You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` diff --git a/.changeset/early-toes-develop.md b/.changeset/early-toes-develop.md deleted file mode 100644 index 3262ff0b98..0000000000 --- a/.changeset/early-toes-develop.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': minor -'@backstage/plugin-techdocs-node': minor ---- - -Allow prepared directory clean up for custom preparers - -When using custom preparer for TechDocs, the `preparedDir` might -end up taking disk space. This requires all custom preparers to -implement a new method `shouldCleanPreparedDirectory` which indicates -whether the prepared directory should be cleaned after generation. diff --git a/.changeset/eight-melons-cough.md b/.changeset/eight-melons-cough.md deleted file mode 100644 index 23d7b901f1..0000000000 --- a/.changeset/eight-melons-cough.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/eight-spiders-fold.md b/.changeset/eight-spiders-fold.md deleted file mode 100644 index e4d35cd11d..0000000000 --- a/.changeset/eight-spiders-fold.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Update typescript-eslint to 6.7.x, adding compatibility with TypeScript 5.2. - -This includes a major update on typescript-eslint, you can see the details in the [release notes](https://typescript-eslint.io/blog/announcing-typescript-eslint-v6/). diff --git a/.changeset/eight-suns-tan.md b/.changeset/eight-suns-tan.md deleted file mode 100644 index 4b8634a9e1..0000000000 --- a/.changeset/eight-suns-tan.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': minor ---- - -Extension attachment point is now configured via `attachTo: { id, input }` instead of `at: 'id/input'`. diff --git a/.changeset/eighty-actors-type.md b/.changeset/eighty-actors-type.md deleted file mode 100644 index 5c55a7b0c6..0000000000 --- a/.changeset/eighty-actors-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/test-utils': patch ---- - -Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. diff --git a/.changeset/eighty-chairs-camp.md b/.changeset/eighty-chairs-camp.md new file mode 100644 index 0000000000..6a240609d4 --- /dev/null +++ b/.changeset/eighty-chairs-camp.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': minor +--- + +Added `RouteRef`, `SubRouteRef`, `ExternalRouteRef`, and related types. All exports from this package that previously relied on the types with the same name from `@backstage/core-plugin-api` now use the new types instead. To convert and existing legacy route ref to be compatible with the APIs from this package, use the `convertLegacyRouteRef` utility from `@backstage/core-plugin-api/alpha`. diff --git a/.changeset/eleven-hounds-invent.md b/.changeset/eleven-hounds-invent.md deleted file mode 100644 index ba863ebc28..0000000000 --- a/.changeset/eleven-hounds-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -In frontend builds and tests `process.env.HAS_REACT_DOM_CLIENT` will now be defined if `react-dom/client` is present, i.e. if using React 18. This allows for conditional imports of `react-dom/client`. diff --git a/.changeset/empty-clocks-argue.md b/.changeset/empty-clocks-argue.md deleted file mode 100644 index e3c5985f8a..0000000000 --- a/.changeset/empty-clocks-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Fixed bug in `AppRouter` to determine the correct `signOutTargetUrl` if `app.baseUrl` contains a `basePath` diff --git a/.changeset/empty-schools-check.md b/.changeset/empty-schools-check.md deleted file mode 100644 index c69bbaabb3..0000000000 --- a/.changeset/empty-schools-check.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/frontend-plugin-api': minor -'@backstage/frontend-app-api': minor ---- - -Removed support for the new `useRouteRef`. diff --git a/.changeset/fair-frogs-enjoy.md b/.changeset/fair-frogs-enjoy.md deleted file mode 100644 index 12eb57489e..0000000000 --- a/.changeset/fair-frogs-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/fair-parrots-lick.md b/.changeset/fair-parrots-lick.md new file mode 100644 index 0000000000..dffe6be1e2 --- /dev/null +++ b/.changeset/fair-parrots-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': patch +--- + +Remove the duplicate versions of `@rjsf/*` as they're no longer needed diff --git a/.changeset/fifty-taxis-allow.md b/.changeset/fifty-taxis-allow.md new file mode 100644 index 0000000000..1b818f45e7 --- /dev/null +++ b/.changeset/fifty-taxis-allow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Add missing required property `type` in `Template.v1beta3.schema.json` schema diff --git a/.changeset/five-hornets-provide.md b/.changeset/five-hornets-provide.md deleted file mode 100644 index a422c5fbc8..0000000000 --- a/.changeset/five-hornets-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -The app will now reject any extensions that attach to nonexistent inputs. diff --git a/.changeset/flat-ducks-buy.md b/.changeset/flat-ducks-buy.md new file mode 100644 index 0000000000..5c952faaf1 --- /dev/null +++ b/.changeset/flat-ducks-buy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': patch +--- + +Fix highlighting for non-string fields on the `Lunr` search engine implementation. diff --git a/.changeset/flat-pandas-tan.md b/.changeset/flat-pandas-tan.md deleted file mode 100644 index dfe7965bec..0000000000 --- a/.changeset/flat-pandas-tan.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Added `createMockDirectory()` to help out with file system mocking in tests. diff --git a/.changeset/flat-rules-rush.md b/.changeset/flat-rules-rush.md deleted file mode 100644 index a95772bb6f..0000000000 --- a/.changeset/flat-rules-rush.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -fix: use REST API to get root group memberships for GitLab SaaS users listing - -This API is the only one that shows `email` field for enterprise users and -allows to filter out bot users not using a license using the `is_using_seat` -field. - -We also added the annotation `gitlab.com/saml-external-uid` taking the value -of `group_saml_identity.extern_uid` of the `groups/:group-id/members` endpoint -response. This is useful in case you want to create a `SignInResolver` that -references the user with the id of your identity provider (e.g. OneLogin). - -ref: - -https://docs.gitlab.com/ee/user/enterprise_user/#get-users-email-addresses-through-the-api -https://docs.gitlab.com/ee/api/members.html#limitations diff --git a/.changeset/fluffy-years-shake.md b/.changeset/fluffy-years-shake.md new file mode 100644 index 0000000000..9612690d62 --- /dev/null +++ b/.changeset/fluffy-years-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Use default extensions boundary and suspense on the alpha declarative `createCatalogFilterExtension` extension factory. diff --git a/.changeset/four-jars-protect.md b/.changeset/four-jars-protect.md deleted file mode 100644 index 8469839856..0000000000 --- a/.changeset/four-jars-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-rollbar-backend': patch ---- - -ensure rollbar token is hidden diff --git a/.changeset/four-onions-clap.md b/.changeset/four-onions-clap.md deleted file mode 100644 index 44d0cf9ae7..0000000000 --- a/.changeset/four-onions-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix for the new backend `start` command to make it work on Windows. diff --git a/.changeset/four-pans-sin.md b/.changeset/four-pans-sin.md deleted file mode 100644 index 46d31c242c..0000000000 --- a/.changeset/four-pans-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. diff --git a/.changeset/fresh-badgers-study.md b/.changeset/fresh-badgers-study.md deleted file mode 100644 index 4c9e7ee627..0000000000 --- a/.changeset/fresh-badgers-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Wrap entire app in ``, enabling support for using translations outside plugins. diff --git a/.changeset/fresh-crews-promise.md b/.changeset/fresh-crews-promise.md new file mode 100644 index 0000000000..fc9859086a --- /dev/null +++ b/.changeset/fresh-crews-promise.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-techdocs': patch +--- + +Fixed navigation bug that caused users to not be scrolled to the top of a new page. Fixed navigation bug where using backwards and forwards browser navigation did not scroll users to the correct place on the TechDoc page. diff --git a/.changeset/fresh-kangaroos-tap.md b/.changeset/fresh-kangaroos-tap.md deleted file mode 100644 index 5ac4d184eb..0000000000 --- a/.changeset/fresh-kangaroos-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. diff --git a/.changeset/fuzzy-pillows-remain.md b/.changeset/fuzzy-pillows-remain.md deleted file mode 100644 index 59e3dd7896..0000000000 --- a/.changeset/fuzzy-pillows-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Improved `DocsTable` to display pagination controls dynamically, appearing only when needed. diff --git a/.changeset/gentle-elephants-fold.md b/.changeset/gentle-elephants-fold.md deleted file mode 100644 index 480ee41e7a..0000000000 --- a/.changeset/gentle-elephants-fold.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: - -```ts -import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; - -const app = createApp({ - __experimentalTranslations: { - resources: [ - createTranslationMessages({ - ref: catalogTranslationRef, - catalog_page_create_button_title: 'Create Software', - }), - ], - }, -}); -``` diff --git a/.changeset/gentle-spies-deny.md b/.changeset/gentle-spies-deny.md deleted file mode 100644 index f2d0ea7d79..0000000000 --- a/.changeset/gentle-spies-deny.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-catalog-backend-module-puppetdb': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-ldap': patch -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -Make sure to include the error message when ingestion fails diff --git a/.changeset/giant-cars-walk.md b/.changeset/giant-cars-walk.md new file mode 100644 index 0000000000..5e313faa3b --- /dev/null +++ b/.changeset/giant-cars-walk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Export alpha routes and nav item extension, only available for applications that uses the new Frontend system. diff --git a/.changeset/giant-cycles-end.md b/.changeset/giant-cycles-end.md new file mode 100644 index 0000000000..f69938ea25 --- /dev/null +++ b/.changeset/giant-cycles-end.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-stack-overflow-backend': patch +--- + +Deprecate package in favor of the new `@backstage/plugin-search-backend-module-stack-overflow-collator` module. + +The search collator `requestParams` option is optional now, so its default value is `{ order: 'desc', sort: 'activity', site: 'stackoverflow' }` as defined in the `Try It` section on the [official Stack Overflow API documentation](https://api.stackexchange.com/docs/questions). diff --git a/.changeset/good-plums-confess.md b/.changeset/good-plums-confess.md new file mode 100644 index 0000000000..941adec8b3 --- /dev/null +++ b/.changeset/good-plums-confess.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Refactor internal extension instance system into an app graph. diff --git a/.changeset/great-walls-brake.md b/.changeset/great-walls-brake.md deleted file mode 100644 index dd71c81a07..0000000000 --- a/.changeset/great-walls-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Properly close write stream when writing temporary archive for processing zip-based `.readTree()` responses. diff --git a/.changeset/happy-books-smoke.md b/.changeset/happy-books-smoke.md deleted file mode 100644 index 68ea19ea5e..0000000000 --- a/.changeset/happy-books-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Adds Top/Recently Visited components to homepage diff --git a/.changeset/healthy-laws-divide.md b/.changeset/healthy-laws-divide.md deleted file mode 100644 index 4ab29e6426..0000000000 --- a/.changeset/healthy-laws-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Implement `toString()` and `toJSON()` for extension instances. diff --git a/.changeset/heavy-forks-tie.md b/.changeset/heavy-forks-tie.md deleted file mode 100644 index f5af5975b7..0000000000 --- a/.changeset/heavy-forks-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-node': patch ---- - -Added docs to `processingResult` diff --git a/.changeset/heavy-ladybugs-leave.md b/.changeset/heavy-ladybugs-leave.md deleted file mode 100644 index 5af2324260..0000000000 --- a/.changeset/heavy-ladybugs-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-newrelic': patch ---- - -Fixed sorting and searching in the NewRelic table. diff --git a/.changeset/heavy-plants-doubt.md b/.changeset/heavy-plants-doubt.md deleted file mode 100644 index 3988a16752..0000000000 --- a/.changeset/heavy-plants-doubt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -Added experimental support for declarative integration via the `/alpha` subpath. diff --git a/.changeset/hip-mugs-camp.md b/.changeset/hip-mugs-camp.md new file mode 100644 index 0000000000..3413b5ac0a --- /dev/null +++ b/.changeset/hip-mugs-camp.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Add info about the entity when tech docs fail to build diff --git a/.changeset/hungry-paws-dress.md b/.changeset/hungry-paws-dress.md new file mode 100644 index 0000000000..b227a77e72 --- /dev/null +++ b/.changeset/hungry-paws-dress.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-user-settings': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-search': patch +--- + +Updated alpha exports according to routing changes in `@backstage/frontend-plugin-api`. diff --git a/.changeset/hungry-radios-play.md b/.changeset/hungry-radios-play.md new file mode 100644 index 0000000000..ce7f524f4a --- /dev/null +++ b/.changeset/hungry-radios-play.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-user-settings-backend': patch +--- + +Added dependency on `@backstage/config` diff --git a/.changeset/itchy-bobcats-fly.md b/.changeset/itchy-bobcats-fly.md deleted file mode 100644 index e91d944478..0000000000 --- a/.changeset/itchy-bobcats-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository diff --git a/.changeset/itchy-monkeys-reply.md b/.changeset/itchy-monkeys-reply.md deleted file mode 100644 index 3773fe3ff8..0000000000 --- a/.changeset/itchy-monkeys-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-dev-utils': patch ---- - -Fix an issue where early IPC responses would be lost. diff --git a/.changeset/itchy-rabbits-exist.md b/.changeset/itchy-rabbits-exist.md deleted file mode 100644 index 6a16ac5648..0000000000 --- a/.changeset/itchy-rabbits-exist.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': minor ---- - -**BREAKING** The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior set `LEGACY_BACKEND_START`, which is recommended if you haven't migrated to the new backend system. - -This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. diff --git a/.changeset/khaki-tools-tease.md b/.changeset/khaki-tools-tease.md deleted file mode 100644 index e4383c9e33..0000000000 --- a/.changeset/khaki-tools-tease.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Updated `publish:gitlab` action properties to support additional Gitlab project settings: - -- general project settings provided by gitlab project create API (new `settings` property) -- branch level settings to create additional branches and make them protected (new `branches` property) -- project level environment variables settings (new `projectVariables` property) - -Marked existed properties `repoVisibility` and `topics` as deprecated, as they are covered by `settings` property. diff --git a/.changeset/large-balloons-brush.md b/.changeset/large-balloons-brush.md deleted file mode 100644 index 0dcada12bf..0000000000 --- a/.changeset/large-balloons-brush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': minor ---- - -**BREAKING**: The recently introduced `ProxyAuthenticator.initialize()` method is no longer `async` to match the way the OAuth equivalent is implemented. diff --git a/.changeset/large-comics-knock.md b/.changeset/large-comics-knock.md deleted file mode 100644 index 860172579e..0000000000 --- a/.changeset/large-comics-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -fixed issue related template editor fails with multiple templates per file. diff --git a/.changeset/late-papayas-push.md b/.changeset/late-papayas-push.md deleted file mode 100644 index 07422e1b1b..0000000000 --- a/.changeset/late-papayas-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Add support for `SidebarGroup` on the sidebar item extension. diff --git a/.changeset/lazy-doors-wink.md b/.changeset/lazy-doors-wink.md deleted file mode 100644 index aafbb3500e..0000000000 --- a/.changeset/lazy-doors-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. diff --git a/.changeset/renovate-2633beb.md b/.changeset/lazy-hotels-wait.md similarity index 93% rename from .changeset/renovate-2633beb.md rename to .changeset/lazy-hotels-wait.md index ff4c574c85..85879880f5 100644 --- a/.changeset/renovate-2633beb.md +++ b/.changeset/lazy-hotels-wait.md @@ -1,104 +1,109 @@ --- -'@backstage/app-defaults': patch -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/dev-utils': patch -'@backstage/frontend-app-api': patch -'@backstage/frontend-plugin-api': patch -'@backstage/integration-react': patch -'@backstage/test-utils': patch -'@backstage/version-bridge': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-analytics-module-ga4': patch '@backstage/plugin-analytics-module-newrelic-browser': patch -'@backstage/plugin-apache-airflow': patch '@backstage/plugin-api-docs-module-protoc-gen-doc': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bazaar': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-react': patch +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-cicd-statistics-module-gitlab': patch '@backstage/plugin-catalog-unprocessed-entities': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-entity-feedback': patch -'@backstage/plugin-entity-validation': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch '@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-graphql-voyager': patch -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch +'@backstage/plugin-techdocs-addons-test-utils': patch +'@backstage/frontend-plugin-api': patch +'@backstage/plugin-analytics-module-ga4': patch +'@backstage/plugin-analytics-module-ga': patch +'@backstage/plugin-git-release-manager': patch +'@backstage/integration-react': patch +'@backstage/plugin-github-deployments': patch '@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-linguist': patch '@backstage/plugin-microsoft-calendar': patch '@backstage/plugin-newrelic-dashboard': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-nomad': patch -'@backstage/plugin-octopus-deploy': patch -'@backstage/plugin-opencost': patch -'@backstage/plugin-org-react': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop': patch +'@backstage/frontend-app-api': patch +'@backstage/plugin-entity-validation': patch +'@backstage/core-components': patch +'@backstage/core-plugin-api': patch +'@backstage/plugin-kubernetes-react': patch '@backstage/plugin-permission-react': patch -'@backstage/plugin-playlist': patch -'@backstage/plugin-puppetdb': patch -'@backstage/plugin-rollbar': patch '@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search-react': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube': patch +'@backstage/version-bridge': patch +'@backstage/plugin-apollo-explorer': patch +'@backstage/plugin-catalog-graphql': patch +'@backstage/plugin-cicd-statistics': patch +'@backstage/plugin-entity-feedback': patch +'@backstage/plugin-gitops-profiles': patch +'@backstage/plugin-graphql-voyager': patch +'@backstage/plugin-sonarqube-react': patch +'@backstage/plugin-apache-airflow': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-github-actions': patch +'@backstage/plugin-octopus-deploy': patch '@backstage/plugin-splunk-on-call': patch '@backstage/plugin-stack-overflow': patch -'@backstage/plugin-stackstorm': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch '@backstage/plugin-techdocs-react': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo': patch +'@backstage/app-defaults': patch +'@backstage/core-app-api': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-config-schema': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-explore-react': patch +'@backstage/plugin-github-issues': patch +'@backstage/plugin-tech-insights': patch '@backstage/plugin-user-settings': patch -'@backstage/plugin-vault': patch +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-code-climate': patch +'@backstage/plugin-gcp-projects': patch +'@backstage/plugin-search-react': patch +'@backstage/create-app': patch +'@backstage/test-utils': patch +'@backstage/plugin-azure-sites': patch +'@backstage/plugin-firehydrant': patch +'@backstage/plugin-cloudbuild': patch +'@backstage/plugin-home-react': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-lighthouse': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-stackstorm': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-codescene': patch +'@backstage/plugin-dynatrace': patch +'@backstage/plugin-gcalendar': patch +'@backstage/plugin-org-react': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-shortcuts': patch +'@backstage/plugin-sonarqube': patch '@backstage/plugin-xcmetrics': patch +'@backstage/plugin-airbrake': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-circleci': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-linguist': patch +'@backstage/plugin-newrelic': patch +'@backstage/plugin-opencost': patch +'@backstage/plugin-periskop': patch +'@backstage/plugin-playlist': patch +'@backstage/plugin-puppetdb': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-bitrise': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-jenkins': patch +'@backstage/plugin-rollbar': patch +'@backstage/theme': patch +'@backstage/plugin-allure': patch +'@backstage/plugin-badges': patch +'@backstage/plugin-bazaar': patch +'@backstage/plugin-search': patch +'@backstage/plugin-sentry': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-ilert': patch +'@backstage/plugin-kafka': patch +'@backstage/plugin-nomad': patch +'@backstage/plugin-vault': patch +'@backstage/plugin-gocd': patch +'@backstage/plugin-home': patch +'@backstage/plugin-todo': patch +'@backstage/plugin-adr': patch +'@backstage/plugin-org': patch --- -Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +Add official support for React 18. diff --git a/.changeset/lemon-cups-wait.md b/.changeset/lemon-cups-wait.md deleted file mode 100644 index 4dd08c21b0..0000000000 --- a/.changeset/lemon-cups-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -include owner chip in catalog search result item diff --git a/.changeset/lemon-masks-greet.md b/.changeset/lemon-masks-greet.md deleted file mode 100644 index 79c7b7e92b..0000000000 --- a/.changeset/lemon-masks-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. diff --git a/.changeset/light-squids-deny.md b/.changeset/light-squids-deny.md deleted file mode 100644 index 07a124bed3..0000000000 --- a/.changeset/light-squids-deny.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-graphql': minor -'@backstage/plugin-graphql-backend': minor ---- - -This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. diff --git a/.changeset/little-ligers-cheat.md b/.changeset/little-ligers-cheat.md deleted file mode 100644 index 30b4238c59..0000000000 --- a/.changeset/little-ligers-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Make entity picker more reliable with only one available entity diff --git a/.changeset/long-owls-complain.md b/.changeset/long-owls-complain.md deleted file mode 100644 index f96b0f0987..0000000000 --- a/.changeset/long-owls-complain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Fixed an issue preventing the routing system to match subroutes diff --git a/.changeset/long-turkeys-argue.md b/.changeset/long-turkeys-argue.md new file mode 100644 index 0000000000..f051d42478 --- /dev/null +++ b/.changeset/long-turkeys-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Add examples for `github:environment:create` scaffolder action & improve related tests diff --git a/.changeset/loud-hotels-hunt.md b/.changeset/loud-hotels-hunt.md deleted file mode 100644 index b977d2c1d9..0000000000 --- a/.changeset/loud-hotels-hunt.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/integration-react': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/backend-common': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-cicd-statistics': patch -'@backstage/catalog-model': patch -'@backstage/config-loader': patch -'@backstage/plugin-catalog-react': patch -'@backstage/integration': patch -'@backstage/plugin-tech-radar': patch -'@backstage/errors': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-ilert': patch ---- - -Removed some unused dependencies diff --git a/.changeset/lovely-coins-occur.md b/.changeset/lovely-coins-occur.md deleted file mode 100644 index 34a6774388..0000000000 --- a/.changeset/lovely-coins-occur.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. diff --git a/.changeset/lovely-fans-sniff.md b/.changeset/lovely-fans-sniff.md deleted file mode 100644 index af8aebb89b..0000000000 --- a/.changeset/lovely-fans-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-radar': patch ---- - -Added experimental support for the declarative integration. diff --git a/.changeset/many-impalas-wait.md b/.changeset/many-impalas-wait.md deleted file mode 100644 index 843adf66a1..0000000000 --- a/.changeset/many-impalas-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Plugins can now be assigned `routes` and `externalRoutes` when created. diff --git a/.changeset/many-pianos-bow.md b/.changeset/many-pianos-bow.md deleted file mode 100644 index 6c4e3be47f..0000000000 --- a/.changeset/many-pianos-bow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-adr': patch ---- - -Fix icon alignment in `AdrSearchResultListItem` diff --git a/.changeset/many-swans-eat.md b/.changeset/many-swans-eat.md deleted file mode 100644 index 86580d7cfe..0000000000 --- a/.changeset/many-swans-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-badges-backend': patch ---- - -Make sure the default badge factory is used if nothing is defined diff --git a/.changeset/mean-dancers-burn.md b/.changeset/mean-dancers-burn.md deleted file mode 100644 index a51ca7b8de..0000000000 --- a/.changeset/mean-dancers-burn.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/app-defaults': patch -'@backstage/test-utils': patch ---- - -Add missing resource and template app icons diff --git a/.changeset/metal-peas-beam.md b/.changeset/metal-peas-beam.md deleted file mode 100644 index a4ebdeb69a..0000000000 --- a/.changeset/metal-peas-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Display log visibility button on the template panel diff --git a/.changeset/mighty-crews-attack.md b/.changeset/mighty-crews-attack.md new file mode 100644 index 0000000000..c0b8587fe0 --- /dev/null +++ b/.changeset/mighty-crews-attack.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Initial entity page implementation for new frontend system at `/alpha`, with an overview page enabled by default and the about card available as an optional card. diff --git a/.changeset/modern-ducks-battle.md b/.changeset/modern-ducks-battle.md new file mode 100644 index 0000000000..e8359cf4ac --- /dev/null +++ b/.changeset/modern-ducks-battle.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': minor +--- + +Added the ability to configure bound routes through `app.routes.bindings`. The routing system used by `createApp` has been replaced by one that only supports route refs of the new format from `@backstage/frontend-plugin-api`. The requirement for route refs to have the same ID as their associated extension has been removed. diff --git a/.changeset/moody-lobsters-rescue.md b/.changeset/moody-lobsters-rescue.md deleted file mode 100644 index c739e995c5..0000000000 --- a/.changeset/moody-lobsters-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bump `cypress` to fix the end-to-end tests diff --git a/.changeset/nasty-needles-hear.md b/.changeset/nasty-needles-hear.md deleted file mode 100644 index 32a9d0dfb7..0000000000 --- a/.changeset/nasty-needles-hear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Added `/testUtils` entry point, with a utility for mocking resolve package paths as returned by `resolvePackagePath`. diff --git a/.changeset/nervous-hounds-sleep.md b/.changeset/nervous-hounds-sleep.md deleted file mode 100644 index 530ff348f7..0000000000 --- a/.changeset/nervous-hounds-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Make themes configurable through extensions, and switched default themes to use extensions instead. diff --git a/.changeset/new-beers-drive.md b/.changeset/new-beers-drive.md new file mode 100644 index 0000000000..370734b7c5 --- /dev/null +++ b/.changeset/new-beers-drive.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Create declarative extensions for the `Catalog` plugin; this initial plugin preset contains sidebar item, index page and filter extensions, all distributed via `/alpha` subpath. + +The `EntityPage` will be migrated in a follow-up patch. diff --git a/.changeset/nice-apes-kneel.md b/.changeset/nice-apes-kneel.md new file mode 100644 index 0000000000..1ecff9d223 --- /dev/null +++ b/.changeset/nice-apes-kneel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Added entity page content for the new plugin exported via `/alpha`. diff --git a/.changeset/nice-clocks-smash.md b/.changeset/nice-clocks-smash.md deleted file mode 100644 index 8a289370e5..0000000000 --- a/.changeset/nice-clocks-smash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Increase the maximum allowed length of an entity filter for tech insights fact schemas. diff --git a/.changeset/nice-dancers-explain.md b/.changeset/nice-dancers-explain.md deleted file mode 100644 index 5e54a66c05..0000000000 --- a/.changeset/nice-dancers-explain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-github-provider': patch ---- - -Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. diff --git a/.changeset/nice-ghosts-build.md b/.changeset/nice-ghosts-build.md deleted file mode 100644 index abdad08c3b..0000000000 --- a/.changeset/nice-ghosts-build.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-node': minor -'@backstage/plugin-kubernetes-backend': patch ---- - -A new plugin has been introduced to house the extension points for Kubernetes backend plugin; at the moment only the `KubernetesObjectsProviderExtensionPoint` is present. The `kubernetes-backend` plugin was modified to use this new extension point. diff --git a/.changeset/nice-pillows-poke.md b/.changeset/nice-pillows-poke.md new file mode 100644 index 0000000000..64034c39d2 --- /dev/null +++ b/.changeset/nice-pillows-poke.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +Migrate package to the new Frontend system, the new module is distributed with a `/alpha` subpath. diff --git a/.changeset/nine-flies-move.md b/.changeset/nine-flies-move.md deleted file mode 100644 index 0e7bca2836..0000000000 --- a/.changeset/nine-flies-move.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@techdocs/cli': minor -'@backstage/plugin-techdocs-node': minor ---- - -Add possibility to use a mkdocs config file with a different name than `mkdocs. with the serve command using the `--mkdocs-config-file-name` argument diff --git a/.changeset/nine-garlics-attend.md b/.changeset/nine-garlics-attend.md deleted file mode 100644 index a9cdac4a32..0000000000 --- a/.changeset/nine-garlics-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-tasks': patch ---- - -Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup diff --git a/.changeset/ninety-numbers-study.md b/.changeset/ninety-numbers-study.md new file mode 100644 index 0000000000..e77131fab9 --- /dev/null +++ b/.changeset/ninety-numbers-study.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-components': patch +--- + +Fixed compatibility with Safari <16.3 by eliminating RegEx lookbehind in `extractInitials`. + +This PR also changed how initials are generated resulting in _John Jonathan Doe_ => _JD_ instead of _JJ_. diff --git a/.changeset/odd-pants-sleep.md b/.changeset/odd-pants-sleep.md deleted file mode 100644 index ad0b95d973..0000000000 --- a/.changeset/odd-pants-sleep.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-codescene': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-ilert': patch ---- - -Internal refactor to avoid using the deprecated `.icon.svg` extension. diff --git a/.changeset/old-apricots-taste.md b/.changeset/old-apricots-taste.md new file mode 100644 index 0000000000..544ba11536 --- /dev/null +++ b/.changeset/old-apricots-taste.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system. diff --git a/.changeset/olive-cars-rescue.md b/.changeset/olive-cars-rescue.md deleted file mode 100644 index fd6c8fe331..0000000000 --- a/.changeset/olive-cars-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. diff --git a/.changeset/olive-geese-rest.md b/.changeset/olive-geese-rest.md deleted file mode 100644 index 547fb828d8..0000000000 --- a/.changeset/olive-geese-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-jenkins-backend': patch ---- - -Added support for the [new backend system](https://backstage.io/docs/backend-system/) diff --git a/.changeset/olive-islands-sneeze.md b/.changeset/olive-islands-sneeze.md deleted file mode 100644 index b44f071acc..0000000000 --- a/.changeset/olive-islands-sneeze.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/cli': patch ---- - -Request slightly smaller pages of data from GitHub diff --git a/.changeset/olive-paws-divide.md b/.changeset/olive-paws-divide.md new file mode 100644 index 0000000000..688b6025bf --- /dev/null +++ b/.changeset/olive-paws-divide.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Updated `app.extensions` configuration schema. diff --git a/.changeset/orange-cycles-wait.md b/.changeset/orange-cycles-wait.md deleted file mode 100644 index 5e71b69e80..0000000000 --- a/.changeset/orange-cycles-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Added the `bindRoutes` option to `createApp`. diff --git a/.changeset/perfect-cobras-bake.md b/.changeset/perfect-cobras-bake.md deleted file mode 100644 index bf66c12e83..0000000000 --- a/.changeset/perfect-cobras-bake.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-jenkins-backend': minor -'@backstage/plugin-jenkins': minor ---- - -Added JobRunTable Component. -Added new Route and extended Api to get buildJobs. -Actions column has a new icon button, clicking on which takes us to page where we -can see all the job runs. diff --git a/.changeset/perfect-pumas-protect.md b/.changeset/perfect-pumas-protect.md deleted file mode 100644 index 7d6bf8d6d7..0000000000 --- a/.changeset/perfect-pumas-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-code-coverage-backend': patch ---- - -Added option to set body size limit diff --git a/.changeset/perfect-shrimps-attend.md b/.changeset/perfect-shrimps-attend.md deleted file mode 100644 index b530d0e2a2..0000000000 --- a/.changeset/perfect-shrimps-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed overflowing messages in `WarningPanel`. diff --git a/.changeset/plenty-llamas-double.md b/.changeset/plenty-llamas-double.md deleted file mode 100644 index b2691a2f17..0000000000 --- a/.changeset/plenty-llamas-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -Fix for persisted scopes not being properly restored on sign-in. diff --git a/.changeset/plenty-tigers-argue.md b/.changeset/plenty-tigers-argue.md new file mode 100644 index 0000000000..ef9e58d63b --- /dev/null +++ b/.changeset/plenty-tigers-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +Add `factRetrieverId` to the fact retriever's logger metadata. diff --git a/.changeset/plenty-toys-cheer.md b/.changeset/plenty-toys-cheer.md deleted file mode 100644 index 3c16002632..0000000000 --- a/.changeset/plenty-toys-cheer.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-search-react': patch -'@backstage/plugin-graphiql': patch ---- - -Updated `/alpha` exports to use new `attachTo` option. diff --git a/.changeset/polite-cooks-perform.md b/.changeset/polite-cooks-perform.md deleted file mode 100644 index 40766c84a3..0000000000 --- a/.changeset/polite-cooks-perform.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': minor ---- - -The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. diff --git a/.changeset/polite-donuts-fail.md b/.changeset/polite-donuts-fail.md deleted file mode 100644 index 9c03faaf44..0000000000 --- a/.changeset/polite-donuts-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). diff --git a/.changeset/polite-trainers-grin.md b/.changeset/polite-trainers-grin.md deleted file mode 100644 index 878596702d..0000000000 --- a/.changeset/polite-trainers-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` diff --git a/.changeset/popular-dots-design.md b/.changeset/popular-dots-design.md deleted file mode 100644 index c333ce0105..0000000000 --- a/.changeset/popular-dots-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Changed SupportButton menuitems to support text wrap diff --git a/.changeset/pre.json b/.changeset/pre.json index d6534f2b5a..4a9428d0cd 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,389 +2,255 @@ "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.87", - "@backstage/app-defaults": "1.4.3", - "example-app-next": "0.0.1", - "app-next-example-plugin": "0.0.1", - "example-backend": "0.2.87", - "@backstage/backend-app-api": "0.5.3", - "@backstage/backend-common": "0.19.5", - "@backstage/backend-defaults": "0.2.3", - "@backstage/backend-dev-utils": "0.1.1", - "example-backend-next": "0.0.15", - "@backstage/backend-openapi-utils": "0.0.4", - "@backstage/backend-plugin-api": "0.6.3", - "@backstage/backend-plugin-manager": "0.0.1", - "@backstage/backend-tasks": "0.5.8", - "@backstage/backend-test-utils": "0.2.3", - "@backstage/catalog-client": "1.4.4", - "@backstage/catalog-model": "1.4.2", - "@backstage/cli": "0.22.13", - "@backstage/cli-common": "0.1.12", - "@backstage/cli-node": "0.1.4", - "@backstage/codemods": "0.1.45", - "@backstage/config": "1.1.0", - "@backstage/config-loader": "1.5.0", - "@backstage/core-app-api": "1.10.0", - "@backstage/core-components": "0.13.5", - "@backstage/core-plugin-api": "1.6.0", - "@backstage/create-app": "0.5.5", - "@backstage/dev-utils": "1.0.21", - "e2e-test": "0.2.7", - "@backstage/errors": "1.2.2", + "example-app": "0.2.88", + "@backstage/app-defaults": "1.4.4", + "example-app-next": "0.0.2", + "app-next-example-plugin": "0.0.2", + "example-backend": "0.2.88", + "@backstage/backend-app-api": "0.5.6", + "@backstage/backend-common": "0.19.8", + "@backstage/backend-defaults": "0.2.6", + "@backstage/backend-dev-utils": "0.1.2", + "example-backend-next": "0.0.16", + "@backstage/backend-openapi-utils": "0.0.5", + "@backstage/backend-plugin-api": "0.6.6", + "@backstage/backend-plugin-manager": "0.0.2", + "@backstage/backend-tasks": "0.5.11", + "@backstage/backend-test-utils": "0.2.7", + "@backstage/catalog-client": "1.4.5", + "@backstage/catalog-model": "1.4.3", + "@backstage/cli": "0.23.0", + "@backstage/cli-common": "0.1.13", + "@backstage/cli-node": "0.1.5", + "@backstage/codemods": "0.1.46", + "@backstage/config": "1.1.1", + "@backstage/config-loader": "1.5.1", + "@backstage/core-app-api": "1.11.0", + "@backstage/core-components": "0.13.6", + "@backstage/core-plugin-api": "1.7.0", + "@backstage/create-app": "0.5.6", + "@backstage/dev-utils": "1.0.22", + "e2e-test": "0.2.8", + "@backstage/e2e-test-utils": "0.1.0", + "@backstage/errors": "1.2.3", "@backstage/eslint-plugin": "0.1.3", - "@backstage/frontend-app-api": "0.1.0", - "@backstage/frontend-plugin-api": "0.1.0", - "@backstage/integration": "1.7.0", - "@backstage/integration-aws-node": "0.1.6", - "@backstage/integration-react": "1.1.19", + "@backstage/frontend-app-api": "0.2.0", + "@backstage/frontend-plugin-api": "0.2.0", + "@backstage/integration": "1.7.1", + "@backstage/integration-aws-node": "0.1.7", + "@backstage/integration-react": "1.1.20", "@backstage/release-manifests": "0.0.10", - "@backstage/repo-tools": "0.3.4", - "@techdocs/cli": "1.5.0", - "techdocs-cli-embedded-app": "0.2.86", - "@backstage/test-utils": "1.4.3", - "@backstage/theme": "0.4.2", + "@backstage/repo-tools": "0.3.5", + "@techdocs/cli": "1.6.0", + "techdocs-cli-embedded-app": "0.2.87", + "@backstage/test-utils": "1.4.4", + "@backstage/theme": "0.4.3", "@backstage/types": "1.1.1", - "@backstage/version-bridge": "1.0.5", - "@backstage/plugin-adr": "0.6.7", - "@backstage/plugin-adr-backend": "0.4.0", - "@backstage/plugin-adr-common": "0.2.15", - "@backstage/plugin-airbrake": "0.3.24", - "@backstage/plugin-airbrake-backend": "0.3.0", - "@backstage/plugin-allure": "0.1.40", - "@backstage/plugin-analytics-module-ga": "0.1.33", - "@backstage/plugin-analytics-module-ga4": "0.1.4", - "@backstage/plugin-analytics-module-newrelic-browser": "0.0.2", - "@backstage/plugin-apache-airflow": "0.2.15", - "@backstage/plugin-api-docs": "0.9.11", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.3", - "@backstage/plugin-apollo-explorer": "0.1.15", - "@backstage/plugin-app-backend": "0.3.51", - "@backstage/plugin-app-node": "0.1.3", - "@backstage/plugin-auth-backend": "0.19.0", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-github-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-google-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.0", - "@backstage/plugin-auth-node": "0.3.0", - "@backstage/plugin-azure-devops": "0.3.6", - "@backstage/plugin-azure-devops-backend": "0.4.0", + "@backstage/version-bridge": "1.0.6", + "@backstage/plugin-adr": "0.6.8", + "@backstage/plugin-adr-backend": "0.4.3", + "@backstage/plugin-adr-common": "0.2.16", + "@backstage/plugin-airbrake": "0.3.25", + "@backstage/plugin-airbrake-backend": "0.3.3", + "@backstage/plugin-allure": "0.1.41", + "@backstage/plugin-analytics-module-ga": "0.1.34", + "@backstage/plugin-analytics-module-ga4": "0.1.5", + "@backstage/plugin-analytics-module-newrelic-browser": "0.0.3", + "@backstage/plugin-apache-airflow": "0.2.16", + "@backstage/plugin-api-docs": "0.9.12", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.4", + "@backstage/plugin-apollo-explorer": "0.1.16", + "@backstage/plugin-app-backend": "0.3.54", + "@backstage/plugin-app-node": "0.1.6", + "@backstage/plugin-auth-backend": "0.19.3", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.0", + "@backstage/plugin-auth-backend-module-github-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-google-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.0", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.0", + "@backstage/plugin-auth-node": "0.4.0", + "@backstage/plugin-azure-devops": "0.3.7", + "@backstage/plugin-azure-devops-backend": "0.4.3", "@backstage/plugin-azure-devops-common": "0.3.1", - "@backstage/plugin-azure-sites": "0.1.13", - "@backstage/plugin-azure-sites-backend": "0.1.13", + "@backstage/plugin-azure-sites": "0.1.14", + "@backstage/plugin-azure-sites-backend": "0.1.16", "@backstage/plugin-azure-sites-common": "0.1.1", - "@backstage/plugin-badges": "0.2.48", - "@backstage/plugin-badges-backend": "0.3.0", - "@backstage/plugin-bazaar": "0.2.16", - "@backstage/plugin-bazaar-backend": "0.3.0", - "@backstage/plugin-bitbucket-cloud-common": "0.2.12", - "@backstage/plugin-bitrise": "0.1.51", - "@backstage/plugin-catalog": "1.13.0", - "@backstage/plugin-catalog-backend": "1.13.0", - "@backstage/plugin-catalog-backend-module-aws": "0.2.6", - "@backstage/plugin-catalog-backend-module-azure": "0.1.22", - "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.18", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.18", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.16", - "@backstage/plugin-catalog-backend-module-gcp": "0.1.3", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.19", - "@backstage/plugin-catalog-backend-module-github": "0.4.0", - "@backstage/plugin-catalog-backend-module-gitlab": "0.3.0", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.6", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.18", - "@backstage/plugin-catalog-backend-module-msgraph": "0.5.10", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.19", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.8", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.0", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.0", - "@backstage/plugin-catalog-common": "1.0.16", - "@internal/plugin-catalog-customized": "0.0.14", - "@backstage/plugin-catalog-graph": "0.2.36", - "@backstage/plugin-catalog-graphql": "0.3.23", - "@backstage/plugin-catalog-import": "0.10.0", - "@backstage/plugin-catalog-node": "1.4.4", - "@backstage/plugin-catalog-react": "1.8.4", - "@backstage/plugin-catalog-unprocessed-entities": "0.1.3", - "@backstage/plugin-cicd-statistics": "0.1.26", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.20", - "@backstage/plugin-circleci": "0.3.24", - "@backstage/plugin-cloudbuild": "0.3.24", - "@backstage/plugin-code-climate": "0.1.24", - "@backstage/plugin-code-coverage": "0.2.17", - "@backstage/plugin-code-coverage-backend": "0.2.17", - "@backstage/plugin-codescene": "0.1.17", - "@backstage/plugin-config-schema": "0.1.45", - "@backstage/plugin-cost-insights": "0.12.13", + "@backstage/plugin-badges": "0.2.49", + "@backstage/plugin-badges-backend": "0.3.3", + "@backstage/plugin-bazaar": "0.2.17", + "@backstage/plugin-bazaar-backend": "0.3.3", + "@backstage/plugin-bitbucket-cloud-common": "0.2.13", + "@backstage/plugin-bitrise": "0.1.52", + "@backstage/plugin-catalog": "1.14.0", + "@backstage/plugin-catalog-backend": "1.14.0", + "@backstage/plugin-catalog-backend-module-aws": "0.3.0", + "@backstage/plugin-catalog-backend-module-azure": "0.1.25", + "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.21", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.21", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.19", + "@backstage/plugin-catalog-backend-module-gcp": "0.1.6", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.22", + "@backstage/plugin-catalog-backend-module-github": "0.4.4", + "@backstage/plugin-catalog-backend-module-github-org": "0.1.0", + "@backstage/plugin-catalog-backend-module-gitlab": "0.3.3", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.10", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.21", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.13", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.23", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.11", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.3", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.3", + "@backstage/plugin-catalog-common": "1.0.17", + "@backstage/plugin-catalog-graph": "0.2.37", + "@backstage/plugin-catalog-graphql": "0.4.0", + "@backstage/plugin-catalog-import": "0.10.1", + "@backstage/plugin-catalog-node": "1.4.7", + "@backstage/plugin-catalog-react": "1.8.5", + "@backstage/plugin-catalog-unprocessed-entities": "0.1.4", + "@backstage/plugin-cicd-statistics": "0.1.27", + "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.21", + "@backstage/plugin-circleci": "0.3.25", + "@backstage/plugin-cloudbuild": "0.3.25", + "@backstage/plugin-code-climate": "0.1.25", + "@backstage/plugin-code-coverage": "0.2.18", + "@backstage/plugin-code-coverage-backend": "0.2.20", + "@backstage/plugin-codescene": "0.1.18", + "@backstage/plugin-config-schema": "0.1.46", + "@backstage/plugin-cost-insights": "0.12.14", "@backstage/plugin-cost-insights-common": "0.1.2", - "@backstage/plugin-devtools": "0.1.4", - "@backstage/plugin-devtools-backend": "0.2.0", - "@backstage/plugin-devtools-common": "0.1.4", - "@backstage/plugin-dynatrace": "7.0.4", - "@backstage/plugin-entity-feedback": "0.2.7", - "@backstage/plugin-entity-feedback-backend": "0.2.0", + "@backstage/plugin-devtools": "0.1.5", + "@backstage/plugin-devtools-backend": "0.2.3", + "@backstage/plugin-devtools-common": "0.1.5", + "@backstage/plugin-dynatrace": "7.0.5", + "@backstage/plugin-entity-feedback": "0.2.8", + "@backstage/plugin-entity-feedback-backend": "0.2.3", "@backstage/plugin-entity-feedback-common": "0.1.3", - "@backstage/plugin-entity-validation": "0.1.9", - "@backstage/plugin-events-backend": "0.2.12", - "@backstage/plugin-events-backend-module-aws-sqs": "0.2.6", - "@backstage/plugin-events-backend-module-azure": "0.1.13", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.13", - "@backstage/plugin-events-backend-module-gerrit": "0.1.13", - "@backstage/plugin-events-backend-module-github": "0.1.13", - "@backstage/plugin-events-backend-module-gitlab": "0.1.13", - "@backstage/plugin-events-backend-test-utils": "0.1.13", - "@backstage/plugin-events-node": "0.2.12", - "@internal/plugin-todo-list": "1.0.17", - "@internal/plugin-todo-list-backend": "1.0.17", - "@internal/plugin-todo-list-common": "1.0.13", - "@backstage/plugin-explore": "0.4.10", - "@backstage/plugin-explore-backend": "0.0.13", + "@backstage/plugin-entity-validation": "0.1.10", + "@backstage/plugin-events-backend": "0.2.15", + "@backstage/plugin-events-backend-module-aws-sqs": "0.2.9", + "@backstage/plugin-events-backend-module-azure": "0.1.16", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.16", + "@backstage/plugin-events-backend-module-gerrit": "0.1.16", + "@backstage/plugin-events-backend-module-github": "0.1.16", + "@backstage/plugin-events-backend-module-gitlab": "0.1.16", + "@backstage/plugin-events-backend-test-utils": "0.1.16", + "@backstage/plugin-events-node": "0.2.15", + "@internal/plugin-todo-list": "1.0.18", + "@internal/plugin-todo-list-backend": "1.0.18", + "@internal/plugin-todo-list-common": "1.0.14", + "@backstage/plugin-explore": "0.4.11", + "@backstage/plugin-explore-backend": "0.0.16", "@backstage/plugin-explore-common": "0.0.2", - "@backstage/plugin-explore-react": "0.0.31", - "@backstage/plugin-firehydrant": "0.2.8", - "@backstage/plugin-fossa": "0.2.56", - "@backstage/plugin-gcalendar": "0.3.18", - "@backstage/plugin-gcp-projects": "0.3.41", - "@backstage/plugin-git-release-manager": "0.3.37", - "@backstage/plugin-github-actions": "0.6.5", - "@backstage/plugin-github-deployments": "0.1.55", - "@backstage/plugin-github-issues": "0.2.13", - "@backstage/plugin-github-pull-requests-board": "0.1.18", - "@backstage/plugin-gitops-profiles": "0.3.40", - "@backstage/plugin-gocd": "0.1.30", - "@backstage/plugin-graphiql": "0.2.54", - "@backstage/plugin-graphql-backend": "0.1.41", - "@backstage/plugin-graphql-voyager": "0.1.7", - "@backstage/plugin-home": "0.5.8", - "@backstage/plugin-home-react": "0.1.3", - "@backstage/plugin-ilert": "0.2.13", - "@backstage/plugin-jenkins": "0.8.6", - "@backstage/plugin-jenkins-backend": "0.2.6", - "@backstage/plugin-jenkins-common": "0.1.19", - "@backstage/plugin-kafka": "0.3.24", - "@backstage/plugin-kafka-backend": "0.3.0", - "@backstage/plugin-kubernetes": "0.10.3", - "@backstage/plugin-kubernetes-backend": "0.12.0", - "@backstage/plugin-kubernetes-common": "0.6.6", - "@backstage/plugin-lighthouse": "0.4.9", - "@backstage/plugin-lighthouse-backend": "0.3.0", - "@backstage/plugin-lighthouse-common": "0.1.3", - "@backstage/plugin-linguist": "0.1.9", - "@backstage/plugin-linguist-backend": "0.5.0", + "@backstage/plugin-explore-react": "0.0.32", + "@backstage/plugin-firehydrant": "0.2.9", + "@backstage/plugin-fossa": "0.2.57", + "@backstage/plugin-gcalendar": "0.3.19", + "@backstage/plugin-gcp-projects": "0.3.42", + "@backstage/plugin-git-release-manager": "0.3.38", + "@backstage/plugin-github-actions": "0.6.6", + "@backstage/plugin-github-deployments": "0.1.56", + "@backstage/plugin-github-issues": "0.2.14", + "@backstage/plugin-github-pull-requests-board": "0.1.19", + "@backstage/plugin-gitops-profiles": "0.3.41", + "@backstage/plugin-gocd": "0.1.31", + "@backstage/plugin-graphiql": "0.2.55", + "@backstage/plugin-graphql-backend": "0.2.0", + "@backstage/plugin-graphql-voyager": "0.1.8", + "@backstage/plugin-home": "0.5.9", + "@backstage/plugin-home-react": "0.1.4", + "@backstage/plugin-ilert": "0.2.14", + "@backstage/plugin-jenkins": "0.9.0", + "@backstage/plugin-jenkins-backend": "0.3.0", + "@backstage/plugin-jenkins-common": "0.1.20", + "@backstage/plugin-kafka": "0.3.25", + "@backstage/plugin-kafka-backend": "0.3.3", + "@backstage/plugin-kubernetes": "0.11.0", + "@backstage/plugin-kubernetes-backend": "0.13.0", + "@backstage/plugin-kubernetes-cluster": "0.0.1", + "@backstage/plugin-kubernetes-common": "0.7.0", + "@backstage/plugin-kubernetes-node": "0.1.0", + "@backstage/plugin-kubernetes-react": "0.1.0", + "@backstage/plugin-lighthouse": "0.4.10", + "@backstage/plugin-lighthouse-backend": "0.3.3", + "@backstage/plugin-lighthouse-common": "0.1.4", + "@backstage/plugin-linguist": "0.1.10", + "@backstage/plugin-linguist-backend": "0.5.3", "@backstage/plugin-linguist-common": "0.1.2", - "@backstage/plugin-microsoft-calendar": "0.1.7", - "@backstage/plugin-newrelic": "0.3.40", - "@backstage/plugin-newrelic-dashboard": "0.2.17", - "@backstage/plugin-nomad": "0.1.5", - "@backstage/plugin-nomad-backend": "0.1.5", - "@backstage/plugin-octopus-deploy": "0.2.6", - "@backstage/plugin-opencost": "0.2.0", - "@backstage/plugin-org": "0.6.14", - "@backstage/plugin-org-react": "0.1.13", - "@backstage/plugin-pagerduty": "0.6.5", - "@backstage/plugin-periskop": "0.1.22", - "@backstage/plugin-periskop-backend": "0.2.0", - "@backstage/plugin-permission-backend": "0.5.26", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.0", - "@backstage/plugin-permission-common": "0.7.8", - "@backstage/plugin-permission-node": "0.7.14", - "@backstage/plugin-permission-react": "0.4.15", - "@backstage/plugin-playlist": "0.1.16", - "@backstage/plugin-playlist-backend": "0.3.7", - "@backstage/plugin-playlist-common": "0.1.10", - "@backstage/plugin-proxy-backend": "0.4.0", - "@backstage/plugin-puppetdb": "0.1.7", - "@backstage/plugin-rollbar": "0.4.24", - "@backstage/plugin-rollbar-backend": "0.1.48", - "@backstage/plugin-scaffolder": "1.15.0", - "@backstage/plugin-scaffolder-backend": "1.17.0", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.4", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.27", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.6", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.20", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.11", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.24", - "@backstage/plugin-scaffolder-common": "1.4.1", - "@backstage/plugin-scaffolder-node": "0.2.3", - "@backstage/plugin-scaffolder-react": "1.5.5", - "@backstage/plugin-search": "1.4.0", - "@backstage/plugin-search-backend": "1.4.3", - "@backstage/plugin-search-backend-module-catalog": "0.1.7", - "@backstage/plugin-search-backend-module-elasticsearch": "1.3.6", - "@backstage/plugin-search-backend-module-explore": "0.1.7", - "@backstage/plugin-search-backend-module-pg": "0.5.12", - "@backstage/plugin-search-backend-module-techdocs": "0.1.7", - "@backstage/plugin-search-backend-node": "1.2.7", - "@backstage/plugin-search-common": "1.2.6", - "@backstage/plugin-search-react": "1.7.0", - "@backstage/plugin-sentry": "0.5.9", - "@backstage/plugin-shortcuts": "0.3.14", - "@backstage/plugin-sonarqube": "0.7.5", - "@backstage/plugin-sonarqube-backend": "0.2.5", - "@backstage/plugin-sonarqube-react": "0.1.8", - "@backstage/plugin-splunk-on-call": "0.4.13", - "@backstage/plugin-stack-overflow": "0.1.20", - "@backstage/plugin-stack-overflow-backend": "0.2.7", - "@backstage/plugin-stackstorm": "0.1.6", - "@backstage/plugin-tech-insights": "0.3.16", - "@backstage/plugin-tech-insights-backend": "0.5.17", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.35", + "@backstage/plugin-microsoft-calendar": "0.1.8", + "@backstage/plugin-newrelic": "0.3.41", + "@backstage/plugin-newrelic-dashboard": "0.3.0", + "@backstage/plugin-nomad": "0.1.6", + "@backstage/plugin-nomad-backend": "0.1.8", + "@backstage/plugin-octopus-deploy": "0.2.7", + "@backstage/plugin-opencost": "0.2.1", + "@backstage/plugin-org": "0.6.15", + "@backstage/plugin-org-react": "0.1.14", + "@backstage/plugin-pagerduty": "0.6.6", + "@backstage/plugin-periskop": "0.1.23", + "@backstage/plugin-periskop-backend": "0.2.3", + "@backstage/plugin-permission-backend": "0.5.29", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.3", + "@backstage/plugin-permission-common": "0.7.9", + "@backstage/plugin-permission-node": "0.7.17", + "@backstage/plugin-permission-react": "0.4.16", + "@backstage/plugin-playlist": "0.1.17", + "@backstage/plugin-playlist-backend": "0.3.10", + "@backstage/plugin-playlist-common": "0.1.11", + "@backstage/plugin-proxy-backend": "0.4.3", + "@backstage/plugin-puppetdb": "0.1.8", + "@backstage/plugin-rollbar": "0.4.25", + "@backstage/plugin-rollbar-backend": "0.1.51", + "@backstage/plugin-scaffolder": "1.15.1", + "@backstage/plugin-scaffolder-backend": "1.18.0", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.7", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.30", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.9", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.23", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.14", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.27", + "@backstage/plugin-scaffolder-common": "1.4.2", + "@backstage/plugin-scaffolder-node": "0.2.6", + "@backstage/plugin-scaffolder-react": "1.5.6", + "@backstage/plugin-search": "1.4.1", + "@backstage/plugin-search-backend": "1.4.6", + "@backstage/plugin-search-backend-module-catalog": "0.1.10", + "@backstage/plugin-search-backend-module-elasticsearch": "1.3.9", + "@backstage/plugin-search-backend-module-explore": "0.1.10", + "@backstage/plugin-search-backend-module-pg": "0.5.15", + "@backstage/plugin-search-backend-module-techdocs": "0.1.10", + "@backstage/plugin-search-backend-node": "1.2.10", + "@backstage/plugin-search-common": "1.2.7", + "@backstage/plugin-search-react": "1.7.1", + "@backstage/plugin-sentry": "0.5.10", + "@backstage/plugin-shortcuts": "0.3.15", + "@backstage/plugin-sonarqube": "0.7.6", + "@backstage/plugin-sonarqube-backend": "0.2.8", + "@backstage/plugin-sonarqube-react": "0.1.9", + "@backstage/plugin-splunk-on-call": "0.4.14", + "@backstage/plugin-stack-overflow": "0.1.21", + "@backstage/plugin-stack-overflow-backend": "0.2.10", + "@backstage/plugin-stackstorm": "0.1.7", + "@backstage/plugin-tech-insights": "0.3.17", + "@backstage/plugin-tech-insights-backend": "0.5.20", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.38", "@backstage/plugin-tech-insights-common": "0.2.12", - "@backstage/plugin-tech-insights-node": "0.4.9", - "@backstage/plugin-tech-radar": "0.6.8", - "@backstage/plugin-techdocs": "1.7.0", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.21", - "@backstage/plugin-techdocs-backend": "1.7.0", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.0", - "@backstage/plugin-techdocs-node": "1.8.0", - "@backstage/plugin-techdocs-react": "1.1.11", - "@backstage/plugin-todo": "0.2.27", - "@backstage/plugin-todo-backend": "0.3.1", - "@backstage/plugin-user-settings": "0.7.10", - "@backstage/plugin-user-settings-backend": "0.2.1", - "@backstage/plugin-vault": "0.1.19", - "@backstage/plugin-vault-backend": "0.3.8", - "@backstage/plugin-xcmetrics": "0.2.43", - "@backstage/e2e-test-utils": "0.0.0", - "@backstage/plugin-kubernetes-react": "0.0.0", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.0.0", - "@backstage/plugin-catalog-backend-module-github-org": "0.0.0", - "@backstage/plugin-kubernetes-cluster": "0.0.0", - "@backstage/plugin-kubernetes-node": "0.0.0" + "@backstage/plugin-tech-insights-node": "0.4.12", + "@backstage/plugin-tech-radar": "0.6.9", + "@backstage/plugin-techdocs": "1.8.0", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.22", + "@backstage/plugin-techdocs-backend": "1.8.0", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.1", + "@backstage/plugin-techdocs-node": "1.9.0", + "@backstage/plugin-techdocs-react": "1.1.12", + "@backstage/plugin-todo": "0.2.28", + "@backstage/plugin-todo-backend": "0.3.4", + "@backstage/plugin-user-settings": "0.7.11", + "@backstage/plugin-user-settings-backend": "0.2.4", + "@backstage/plugin-vault": "0.1.20", + "@backstage/plugin-vault-backend": "0.3.11", + "@backstage/plugin-xcmetrics": "0.2.44" }, - "changesets": [ - "angry-badgers-beg", - "angry-clocks-exercise", - "big-spies-beam", - "breezy-dryers-thank", - "calm-carpets-kiss", - "calm-scissors-rescue", - "chatty-papayas-care", - "clean-forks-love", - "cold-bees-jam", - "cold-seas-repeat", - "create-app-1696937840", - "dirty-doors-wave", - "dull-bugs-build", - "dull-dolls-explode", - "dull-experts-kiss", - "dull-laws-camp", - "early-toes-develop", - "eight-melons-cough", - "eight-spiders-fold", - "eight-suns-tan", - "eighty-actors-type", - "empty-schools-check", - "fair-frogs-enjoy", - "flat-pandas-tan", - "flat-rules-rush", - "four-jars-protect", - "four-onions-clap", - "four-pans-sin", - "fresh-badgers-study", - "fresh-kangaroos-tap", - "fuzzy-pillows-remain", - "gentle-elephants-fold", - "gentle-spies-deny", - "great-walls-brake", - "happy-books-smoke", - "healthy-laws-divide", - "heavy-forks-tie", - "heavy-ladybugs-leave", - "itchy-bobcats-fly", - "itchy-monkeys-reply", - "itchy-rabbits-exist", - "khaki-tools-tease", - "large-balloons-brush", - "large-comics-knock", - "late-papayas-push", - "lazy-doors-wink", - "lemon-cups-wait", - "lemon-masks-greet", - "little-ligers-cheat", - "loud-hotels-hunt", - "lovely-coins-occur", - "lovely-fans-sniff", - "many-pianos-bow", - "many-swans-eat", - "mean-dancers-burn", - "metal-peas-beam", - "moody-lobsters-rescue", - "nasty-needles-hear", - "nervous-hounds-sleep", - "nice-clocks-smash", - "nice-dancers-explain", - "nice-ghosts-build", - "nine-flies-move", - "nine-garlics-attend", - "odd-pants-sleep", - "olive-cars-rescue", - "olive-geese-rest", - "perfect-pumas-protect", - "perfect-shrimps-attend", - "plenty-llamas-double", - "plenty-toys-cheer", - "polite-cooks-perform", - "polite-donuts-fail", - "polite-trainers-grin", - "popular-dots-design", - "pretty-apes-sneeze", - "pretty-steaks-serve", - "purple-chefs-wait", - "purple-forks-fetch", - "quick-weeks-explode", - "rare-pants-reply", - "red-bees-try", - "red-geese-clean", - "renovate-7d08f6a", - "renovate-a1c52e8", - "rotten-rings-confess", - "serious-pants-lie", - "serious-penguins-tease", - "short-terms-check", - "shy-clouds-reflect", - "shy-seas-sip", - "silent-years-bake", - "silly-swans-invent", - "six-weeks-raise", - "slow-dodos-remember", - "small-books-deliver", - "small-pugs-build", - "smooth-rings-mate", - "spicy-chairs-film", - "spicy-poets-sell", - "spotty-badgers-wash", - "stale-eagles-reply", - "stale-stingrays-explode", - "strange-dodos-film", - "strong-falcons-tickle", - "stupid-drinks-trade", - "stupid-eagles-shave", - "swift-steaks-fetch", - "tame-trainers-visit", - "tasty-avocados-hope", - "tasty-doors-switch", - "ten-seals-wait", - "tender-pears-work", - "thirty-coins-sneeze", - "tiny-garlics-cheer", - "twelve-clouds-design", - "twelve-days-walk", - "twenty-bags-sin", - "twenty-carrots-smile", - "two-dingos-dream", - "two-terms-play", - "unlucky-experts-breathe", - "violet-apes-beam", - "violet-beers-cross", - "warm-drinks-argue", - "wet-olives-wave", - "wet-timers-chew", - "wicked-rings-flash", - "wild-jobs-greet", - "wild-queens-grab", - "yellow-numbers-own", - "yellow-rings-invent", - "young-toes-knock" - ] + "changesets": [] } diff --git a/.changeset/pretty-apes-sneeze.md b/.changeset/pretty-apes-sneeze.md deleted file mode 100644 index a1008dc951..0000000000 --- a/.changeset/pretty-apes-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -Fixed a bug where the theme icons would not be colored according to their active state. diff --git a/.changeset/pretty-steaks-serve.md b/.changeset/pretty-steaks-serve.md deleted file mode 100644 index 8ec78e0aea..0000000000 --- a/.changeset/pretty-steaks-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added a template for creating `node-library` packages with `yarn new`. diff --git a/.changeset/purple-chefs-wait.md b/.changeset/purple-chefs-wait.md deleted file mode 100644 index 9a8b1f9799..0000000000 --- a/.changeset/purple-chefs-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. diff --git a/.changeset/purple-forks-fetch.md b/.changeset/purple-forks-fetch.md deleted file mode 100644 index 022fc32e71..0000000000 --- a/.changeset/purple-forks-fetch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Register default api implementations when creating declarative integrated apps. diff --git a/.changeset/modern-owls-mate.md b/.changeset/quick-pumpkins-shave.md similarity index 71% rename from .changeset/modern-owls-mate.md rename to .changeset/quick-pumpkins-shave.md index bed33c6bbc..cbb4c48dce 100644 --- a/.changeset/modern-owls-mate.md +++ b/.changeset/quick-pumpkins-shave.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-techdocs': minor +'@backstage/plugin-home': patch --- Added experimental support for declarative integration via the `/alpha` subpath. diff --git a/.changeset/quick-roses-move.md b/.changeset/quick-roses-move.md new file mode 100644 index 0000000000..767ad0919e --- /dev/null +++ b/.changeset/quick-roses-move.md @@ -0,0 +1,6 @@ +--- +'@backstage/dev-utils': patch +'@backstage/plugin-techdocs': patch +--- + +Switched the conditional `react-dom/client` import to use `import(...)` rather than `require(...)`. diff --git a/.changeset/quick-weeks-explode.md b/.changeset/quick-weeks-explode.md deleted file mode 100644 index fcc88263ec..0000000000 --- a/.changeset/quick-weeks-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Remove third type parameter used for `MockInstance`, in order to be compatible with older versions of `@types/jest`. diff --git a/.changeset/rare-glasses-play.md b/.changeset/rare-glasses-play.md deleted file mode 100644 index 7613f6f1bc..0000000000 --- a/.changeset/rare-glasses-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Handle mixed decimals and bigint when calculating k8s resource usage diff --git a/.changeset/rare-pants-reply.md b/.changeset/rare-pants-reply.md deleted file mode 100644 index d37192048c..0000000000 --- a/.changeset/rare-pants-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-gcp-iap-provider': minor ---- - -**BREAKING** `gcpIapAuthenticator.initialize()` is no longer `async` diff --git a/.changeset/real-carrots-brake.md b/.changeset/real-carrots-brake.md new file mode 100644 index 0000000000..e9ae1f0c27 --- /dev/null +++ b/.changeset/real-carrots-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-react': patch +--- + +Fixed a rare occurrence where a race in the search bar could throw away user input or cause the clear button not to work. diff --git a/.changeset/real-jars-yawn.md b/.changeset/real-jars-yawn.md new file mode 100644 index 0000000000..a89a687971 --- /dev/null +++ b/.changeset/real-jars-yawn.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +If create app installs dependencies, don't suggest to user that they also need to do it. diff --git a/.changeset/red-baboons-warn.md b/.changeset/red-baboons-warn.md deleted file mode 100644 index 80b7cd3cad..0000000000 --- a/.changeset/red-baboons-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/dev-utils': patch ---- - -Moving development `dependencies` to `devDependencies` diff --git a/.changeset/red-bees-try.md b/.changeset/red-bees-try.md deleted file mode 100644 index de7eacfe14..0000000000 --- a/.changeset/red-bees-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. diff --git a/.changeset/red-geese-clean.md b/.changeset/red-geese-clean.md deleted file mode 100644 index b4fc9c0808..0000000000 --- a/.changeset/red-geese-clean.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/backend-openapi-utils': patch ---- - -Adds new public utility types for common OpenAPI values, like request and response shapes and parameters available on an endpoint. - -**deprecated** `internal` namespace -The internal namespace will continue to be exported but now uses OpenAPI format for path parameters. You should use the new utility types. diff --git a/.changeset/renovate-0a0b7ba.md b/.changeset/renovate-0a0b7ba.md deleted file mode 100644 index dd43bcc8fa..0000000000 --- a/.changeset/renovate-0a0b7ba.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-common': patch -'@backstage/plugin-kubernetes': patch ---- - -Updated dependency `@kubernetes/client-node` to `0.19.0`. diff --git a/.changeset/renovate-37d5549.md b/.changeset/renovate-37d5549.md deleted file mode 100644 index 4aae56e839..0000000000 --- a/.changeset/renovate-37d5549.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/core-components': patch -'@backstage/core-plugin-api': patch -'@backstage/dev-utils': patch -'@backstage/integration-react': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-analytics-module-ga4': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-entity-feedback': patch -'@backstage/plugin-entity-validation': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-graphql-voyager': patch -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-linguist': patch -'@backstage/plugin-microsoft-calendar': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-octopus-deploy': patch -'@backstage/plugin-org-react': patch -'@backstage/plugin-org': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-playlist': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search-react': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-stackstorm': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-xcmetrics': patch ---- - -Updated dependency `@testing-library/dom` to `^9.0.0`. diff --git a/.changeset/renovate-7d08f6a.md b/.changeset/renovate-7d08f6a.md deleted file mode 100644 index 4e8111f1b3..0000000000 --- a/.changeset/renovate-7d08f6a.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Updated dependency `typescript-json-schema` to `^0.61.0`. diff --git a/.changeset/renovate-a1c52e8.md b/.changeset/renovate-a1c52e8.md deleted file mode 100644 index c11c866b68..0000000000 --- a/.changeset/renovate-a1c52e8.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Updated dependency `@types/pluralize` to `^0.0.31`. diff --git a/.changeset/renovate-a6a783f.md b/.changeset/renovate-a6a783f.md deleted file mode 100644 index a4c6188ee6..0000000000 --- a/.changeset/renovate-a6a783f.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes': patch ---- - -Updated dependency `xterm-addon-attach` to `^0.9.0`. -Updated dependency `xterm-addon-fit` to `^0.8.0`. diff --git a/.changeset/renovate-c204e0d.md b/.changeset/renovate-c204e0d.md deleted file mode 100644 index 1f3e366540..0000000000 --- a/.changeset/renovate-c204e0d.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@typescript-eslint/eslint-plugin` to `6.7.5`. diff --git a/.changeset/rich-pugs-chew.md b/.changeset/rich-pugs-chew.md new file mode 100644 index 0000000000..6c5aa0af62 --- /dev/null +++ b/.changeset/rich-pugs-chew.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The experimental package detection will now ignore packages that don't make `package.json` available. diff --git a/.changeset/rotten-rings-confess.md b/.changeset/rotten-rings-confess.md deleted file mode 100644 index 8948a90347..0000000000 --- a/.changeset/rotten-rings-confess.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-newrelic-dashboard': minor ---- - -Changes in `newrelic-dashboard` plugin: - -- Make DashboardSnapshotList component public -- Settle discrepancies in the exported API -- Deprecate DashboardSnapshotComponent diff --git a/.changeset/rude-tomatoes-itch.md b/.changeset/rude-tomatoes-itch.md new file mode 100644 index 0000000000..1071f65756 --- /dev/null +++ b/.changeset/rude-tomatoes-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Installed features are now deduplicated both by reference and ID when available. Features passed to `createApp` now override both discovered and loaded features. diff --git a/.changeset/serious-pants-lie.md b/.changeset/serious-pants-lie.md deleted file mode 100644 index e67f01dd53..0000000000 --- a/.changeset/serious-pants-lie.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Support for the `.icon.svg` extension has been deprecated and will be removed in the future. The implementation of this extension is too tied to a particular version of MUI and the SVGO, and it makes it harder to evolve the build system. We may introduce the ability to reintroduce this kind of functionality in the future through configuration for use in internal plugins, but for now we're forced to remove it. - -To migrate existing code, rename the `.icon.svg` file to `.tsx` and replace the `` element with `` from MUI and add necessary imports. For example: - -```tsx -import React from 'react'; -import SvgIcon from '@material-ui/core/SvgIcon'; -import { IconComponent } from '@backstage/core-plugin-api'; - -export const CodeSceneIcon = (props: SvgIconProps) => ( - - - - - -); -``` diff --git a/.changeset/serious-penguins-tease.md b/.changeset/serious-penguins-tease.md deleted file mode 100644 index aa6aba7208..0000000000 --- a/.changeset/serious-penguins-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Updated to import `HostDiscovery` from `@backstage/backend-app-api`. diff --git a/.changeset/serious-ravens-serve.md b/.changeset/serious-ravens-serve.md deleted file mode 100644 index 66cbd795c0..0000000000 --- a/.changeset/serious-ravens-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The scaffolder-module template now recommends usage of `createMockDirectory` instead of `mock-fs`. diff --git a/.changeset/sharp-falcons-clean.md b/.changeset/sharp-falcons-clean.md new file mode 100644 index 0000000000..bc247be451 --- /dev/null +++ b/.changeset/sharp-falcons-clean.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Register default implementation for the `Translation API` on the new `createApp`. diff --git a/.changeset/shiny-birds-melt.md b/.changeset/shiny-birds-melt.md deleted file mode 100644 index 16591b6d2f..0000000000 --- a/.changeset/shiny-birds-melt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Fixed a bug in `TranslationApi` implementation where in some cases it wouldn't notify subscribers of language changes. diff --git a/.changeset/shiny-geese-watch.md b/.changeset/shiny-geese-watch.md new file mode 100644 index 0000000000..5394a0776d --- /dev/null +++ b/.changeset/shiny-geese-watch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +--- + +Removed `prompt=consent` from start method to fix #20641 diff --git a/.changeset/short-ears-rescue.md b/.changeset/short-ears-rescue.md deleted file mode 100644 index 41968f3da4..0000000000 --- a/.changeset/short-ears-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-pinniped-provider': minor ---- - -Add new Pinniped auth module and authenticator to be used alongside the new Pinniped auth provider. diff --git a/.changeset/short-terms-check.md b/.changeset/short-terms-check.md deleted file mode 100644 index 69d85fcb9c..0000000000 --- a/.changeset/short-terms-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Removed `mock-fs` dev dependency. diff --git a/.changeset/shy-clouds-reflect.md b/.changeset/shy-clouds-reflect.md deleted file mode 100644 index 2861bad9f3..0000000000 --- a/.changeset/shy-clouds-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. diff --git a/.changeset/shy-seas-sip.md b/.changeset/shy-seas-sip.md deleted file mode 100644 index dfbc4ff0e0..0000000000 --- a/.changeset/shy-seas-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': patch ---- - -Make sure the archived projects are skipped with the Gitlab API diff --git a/.changeset/silent-years-bake.md b/.changeset/silent-years-bake.md deleted file mode 100644 index 4f50c37c31..0000000000 --- a/.changeset/silent-years-bake.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-rails': patch -'@techdocs/cli': patch -'@backstage/cli': patch -'@backstage/cli-common': patch -'@backstage/create-app': patch -'@backstage/codemods': patch -'@backstage/repo-tools': patch ---- - -Bumped dev dependencies `@types/node` and `mock-fs`. diff --git a/.changeset/silent-years-marry.md b/.changeset/silent-years-marry.md deleted file mode 100644 index 6053261784..0000000000 --- a/.changeset/silent-years-marry.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': minor ---- - -**BREAKING** Allow passing undefined `labelSelector` to `KubernetesFetcher` - -`KubernetesFetch` no longer auto-adds `labelSelector` when empty string was passed. -This is only applicable if you have custom ObjectProvider implementation, as build-in `KubernetesFanOutHandler` already does this diff --git a/.changeset/silly-chefs-allow.md b/.changeset/silly-chefs-allow.md deleted file mode 100644 index 6a1ff5dc09..0000000000 --- a/.changeset/silly-chefs-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Added `createExtensionOverrides` which can be used to install a collection of extensions in an app that will replace any existing ones. diff --git a/.changeset/silly-swans-invent.md b/.changeset/silly-swans-invent.md deleted file mode 100644 index 68b094aba7..0000000000 --- a/.changeset/silly-swans-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Added `createThemeExtension` and `coreExtensionData.theme`. diff --git a/.changeset/six-weeks-raise.md b/.changeset/six-weeks-raise.md deleted file mode 100644 index 319555afa4..0000000000 --- a/.changeset/six-weeks-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-app-api': patch ---- - -Moved `HostDiscovery` from `@backstage/backend-common`. diff --git a/.changeset/sixty-tips-argue.md b/.changeset/sixty-tips-argue.md new file mode 100644 index 0000000000..9fc965a281 --- /dev/null +++ b/.changeset/sixty-tips-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Improve the extension boundary component and create a default extension suspense component. diff --git a/.changeset/slow-cameras-grab.md b/.changeset/slow-cameras-grab.md deleted file mode 100644 index d2ffaac73d..0000000000 --- a/.changeset/slow-cameras-grab.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': minor ---- - -The hidden `'root'` extension has been removed and has instead been made an input of the `'core'` extension. The checks for rejecting configuration of the `'root'` extension to rejects configuration of the `'core'` extension instead. diff --git a/.changeset/slow-dodos-remember.md b/.changeset/slow-dodos-remember.md deleted file mode 100644 index fcc49e3f45..0000000000 --- a/.changeset/slow-dodos-remember.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-kubernetes': patch ---- - -Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage diff --git a/.changeset/small-avocados-live.md b/.changeset/small-avocados-live.md deleted file mode 100644 index ddb01a9dfa..0000000000 --- a/.changeset/small-avocados-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Adds the optional flag for useRedisSets for the Redis cache to the config. diff --git a/.changeset/small-books-deliver.md b/.changeset/small-books-deliver.md deleted file mode 100644 index 0d09f7ae1c..0000000000 --- a/.changeset/small-books-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Updates for `at` -> `attachTo` refactor. diff --git a/.changeset/small-pugs-build.md b/.changeset/small-pugs-build.md deleted file mode 100644 index 68e11cd967..0000000000 --- a/.changeset/small-pugs-build.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. - -You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` diff --git a/.changeset/smooth-rings-mate.md b/.changeset/smooth-rings-mate.md deleted file mode 100644 index f46ef2cb5c..0000000000 --- a/.changeset/smooth-rings-mate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/theme': patch ---- - -Added support for string `fontSize` values (e.g. `"2.5rem"`) in themes in addition to numbers. Also added an optional `fontFamily` prop for header typography variants to allow further customization. diff --git a/.changeset/spicy-chairs-film.md b/.changeset/spicy-chairs-film.md deleted file mode 100644 index 475d786330..0000000000 --- a/.changeset/spicy-chairs-film.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-kubernetes-common': minor -'@backstage/plugin-kubernetes-react': minor -'@backstage/plugin-kubernetes': minor ---- - -Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet diff --git a/.changeset/spicy-poets-sell.md b/.changeset/spicy-poets-sell.md deleted file mode 100644 index 4bebd71344..0000000000 --- a/.changeset/spicy-poets-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-jenkins': patch ---- - -Extend EntityJenkinsContent to receive columns as prop diff --git a/.changeset/spotty-badgers-wash.md b/.changeset/spotty-badgers-wash.md deleted file mode 100644 index 1ce9c66aee..0000000000 --- a/.changeset/spotty-badgers-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Instrumenting some missing metrics with `OpenTelemetry` diff --git a/.changeset/stale-eagles-reply.md b/.changeset/stale-eagles-reply.md deleted file mode 100644 index 4584355a59..0000000000 --- a/.changeset/stale-eagles-reply.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/config-loader': patch -'@backstage/backend-app-api': patch ---- - -Added `watch` option to configuration loaders that can be used to disable file watching by setting it to `false`. diff --git a/.changeset/stale-rice-count.md b/.changeset/stale-rice-count.md new file mode 100644 index 0000000000..3d2caf168d --- /dev/null +++ b/.changeset/stale-rice-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Deprecated several types related to the routing system that are scheduled to be removed, as well as several fields on the route ref types themselves. diff --git a/.changeset/stale-stingrays-explode.md b/.changeset/stale-stingrays-explode.md deleted file mode 100644 index b8b66b8398..0000000000 --- a/.changeset/stale-stingrays-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -Fixed cookie persisted scope not returned in OAuth refresh handler response. diff --git a/.changeset/strange-dodos-film.md b/.changeset/strange-dodos-film.md deleted file mode 100644 index 78b9119a2b..0000000000 --- a/.changeset/strange-dodos-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github-org': minor ---- - -Added `catalogModuleGithubOrgEntityProvider` to ingest users and teams from multiple Github organizations. diff --git a/.changeset/strong-falcons-tickle.md b/.changeset/strong-falcons-tickle.md deleted file mode 100644 index d6fa0eb565..0000000000 --- a/.changeset/strong-falcons-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-adr': patch ---- - -Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/strong-taxis-wait.md b/.changeset/strong-taxis-wait.md new file mode 100644 index 0000000000..13cfa9a1ba --- /dev/null +++ b/.changeset/strong-taxis-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Added a workaround for double `default` wrapping when dynamically importing CommonJS modules with default exports. diff --git a/.changeset/stupid-drinks-trade.md b/.changeset/stupid-drinks-trade.md deleted file mode 100644 index a9eeacec8a..0000000000 --- a/.changeset/stupid-drinks-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Add kind column by default to TechDocsTable diff --git a/.changeset/stupid-eagles-shave.md b/.changeset/stupid-eagles-shave.md deleted file mode 100644 index 9bd88290ee..0000000000 --- a/.changeset/stupid-eagles-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-code-coverage': patch ---- - -Updated layout to improve contrasts and consistency with other plugins diff --git a/.changeset/sweet-countries-share.md b/.changeset/sweet-countries-share.md new file mode 100644 index 0000000000..e1327a74b8 --- /dev/null +++ b/.changeset/sweet-countries-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Add examples for `github:webhook` scaffolder action & improve related tests diff --git a/.changeset/swift-kings-add.md b/.changeset/swift-kings-add.md deleted file mode 100644 index 9e9c158eec..0000000000 --- a/.changeset/swift-kings-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-newrelic-dashboard': patch ---- - -Fix the styles for NewRelicDashboard, add more responsiveness diff --git a/.changeset/swift-mice-care.md b/.changeset/swift-mice-care.md new file mode 100644 index 0000000000..1d0d7d8703 --- /dev/null +++ b/.changeset/swift-mice-care.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added `EXPERIMENTAL_VITE` flag for using [vite](https://vitejs.dev) as dev server instead of Webpack diff --git a/.changeset/swift-steaks-fetch.md b/.changeset/swift-steaks-fetch.md deleted file mode 100644 index 80b23e7658..0000000000 --- a/.changeset/swift-steaks-fetch.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': minor -'@backstage/plugin-auth-backend': patch ---- - -Migrated the Microsoft auth provider to new `@backstage/plugin-auth-backend-module-microsoft-provider` module package. diff --git a/.changeset/tame-trainers-visit.md b/.changeset/tame-trainers-visit.md deleted file mode 100644 index 5315f3e1d5..0000000000 --- a/.changeset/tame-trainers-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Removed `catalogModuleGithubOrgEntityProvider`. Import from `@backstage/plugin-catalog-backend-module-github-org` instead. diff --git a/.changeset/tasty-avocados-hope.md b/.changeset/tasty-avocados-hope.md deleted file mode 100644 index 0772b55683..0000000000 --- a/.changeset/tasty-avocados-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. diff --git a/.changeset/tasty-doors-switch.md b/.changeset/tasty-doors-switch.md deleted file mode 100644 index e35bf9cfa4..0000000000 --- a/.changeset/tasty-doors-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Explicitly set `exports: 'named'` for CJS builds, ensuring that they have e.g. `exports["default"] = catalogPlugin;` diff --git a/.changeset/ten-seals-wait.md b/.changeset/ten-seals-wait.md deleted file mode 100644 index 780422449c..0000000000 --- a/.changeset/ten-seals-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. diff --git a/.changeset/tender-experts-yell.md b/.changeset/tender-experts-yell.md deleted file mode 100644 index a4d321073b..0000000000 --- a/.changeset/tender-experts-yell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': minor ---- - -Added support for installing `ExtensionOverrides` via `createApp` options. As part of this change the `plugins` option has been renamed to `features`, and the `pluginLoader` has been renamed to `featureLoader`. diff --git a/.changeset/tender-maps-type.md b/.changeset/tender-maps-type.md new file mode 100644 index 0000000000..11aa814a17 --- /dev/null +++ b/.changeset/tender-maps-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': minor +--- + +Introduced `AnyRouteRefParams` as a replacement for `AnyParams`, which is now deprecated. diff --git a/.changeset/tender-pears-work.md b/.changeset/tender-pears-work.md deleted file mode 100644 index 7770e4c087..0000000000 --- a/.changeset/tender-pears-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -`RepoUrlPickerRepoName` now correctly handles value changes in allowed repos. diff --git a/.changeset/thirty-coins-sneeze.md b/.changeset/thirty-coins-sneeze.md deleted file mode 100644 index 58a93065b8..0000000000 --- a/.changeset/thirty-coins-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/e2e-test-utils': minor ---- - -Initial release. diff --git a/.changeset/three-moles-mix.md b/.changeset/three-moles-mix.md new file mode 100644 index 0000000000..d1e48194a1 --- /dev/null +++ b/.changeset/three-moles-mix.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Fixed incorrect plugin ID in `/alpha` export. diff --git a/.changeset/tidy-camels-boil.md b/.changeset/tidy-camels-boil.md new file mode 100644 index 0000000000..6e59f96f34 --- /dev/null +++ b/.changeset/tidy-camels-boil.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Add component data `core.type` marker for `AppRouter` and `FlatRoutes`. diff --git a/.changeset/tiny-garlics-cheer.md b/.changeset/tiny-garlics-cheer.md deleted file mode 100644 index 992ed7f007..0000000000 --- a/.changeset/tiny-garlics-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@techdocs/cli': patch ---- - -Restructured tests. diff --git a/.changeset/tiny-suns-deny.md b/.changeset/tiny-suns-deny.md deleted file mode 100644 index b00830c75c..0000000000 --- a/.changeset/tiny-suns-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bump dev dependencies `lerna@7.3.0` on the template diff --git a/.changeset/tricky-cups-hammer.md b/.changeset/tricky-cups-hammer.md new file mode 100644 index 0000000000..4e1b6fe9ce --- /dev/null +++ b/.changeset/tricky-cups-hammer.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Added a new `/alpha` export `convertLegacyRouteRef`, which is a temporary utility to allow existing route refs to be used with the new experimental packages. diff --git a/.changeset/twelve-clouds-design.md b/.changeset/twelve-clouds-design.md deleted file mode 100644 index d71d6caec0..0000000000 --- a/.changeset/twelve-clouds-design.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. - -The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. - -The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. diff --git a/.changeset/twelve-days-walk.md b/.changeset/twelve-days-walk.md deleted file mode 100644 index 0b2d261c1a..0000000000 --- a/.changeset/twelve-days-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': minor ---- - -URL encode some well known unsafe characters in `RouteResolver` (and therefore `useRouteRef`) diff --git a/.changeset/twelve-snakes-sell.md b/.changeset/twelve-snakes-sell.md deleted file mode 100644 index 7f91b2910f..0000000000 --- a/.changeset/twelve-snakes-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend': patch ---- - -Set the default length limit to search query to 100. To override it, define `search.maxTermLength` in the config file. diff --git a/.changeset/twenty-bags-sin.md b/.changeset/twenty-bags-sin.md deleted file mode 100644 index 797fd5bfef..0000000000 --- a/.changeset/twenty-bags-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch ---- - -Export `ScorecardInfo` and `ScorecardsList` components to be able to use manually queried check results directly. diff --git a/.changeset/twenty-carrots-smile.md b/.changeset/twenty-carrots-smile.md deleted file mode 100644 index 873af7dcd3..0000000000 --- a/.changeset/twenty-carrots-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add examples for `publish:Azure` scaffolder action. diff --git a/.changeset/two-dingos-dream.md b/.changeset/two-dingos-dream.md deleted file mode 100644 index 9ebefacc69..0000000000 --- a/.changeset/two-dingos-dream.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-kubernetes-common': patch ---- - -The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies diff --git a/.changeset/two-terms-play.md b/.changeset/two-terms-play.md deleted file mode 100644 index 6c7edc01db..0000000000 --- a/.changeset/two-terms-play.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-issues': patch ---- - -Filters out entities that belonged to a different github instance other than the one configured by the plugin diff --git a/.changeset/unlucky-experts-breathe.md b/.changeset/unlucky-experts-breathe.md deleted file mode 100644 index 018b1826d2..0000000000 --- a/.changeset/unlucky-experts-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Added support for the existing routing system. diff --git a/.changeset/violet-apes-beam.md b/.changeset/violet-apes-beam.md deleted file mode 100644 index 544dcf72b2..0000000000 --- a/.changeset/violet-apes-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-newrelic-dashboard': patch ---- - -Fixed React Warning: "Each child in a list should have a unique 'key' prop" during the rendering of `EntityNewRelicDashboardCard` diff --git a/.changeset/violet-beers-cross.md b/.changeset/violet-beers-cross.md deleted file mode 100644 index bdbb9da64e..0000000000 --- a/.changeset/violet-beers-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Change overlay header colors in the mobile menu to use navigation color from the theme diff --git a/.changeset/violet-lamps-appear.md b/.changeset/violet-lamps-appear.md new file mode 100644 index 0000000000..23536fb728 --- /dev/null +++ b/.changeset/violet-lamps-appear.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-scaffolder': minor +'@backstage/plugin-scaffolder-react': minor +--- + +Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries. + +This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose) + +The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively. + +The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release. diff --git a/.changeset/warm-drinks-argue.md b/.changeset/warm-drinks-argue.md deleted file mode 100644 index 5bd4fa63f1..0000000000 --- a/.changeset/warm-drinks-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-explore': patch ---- - -Create an experimental `ExploreSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/wet-olives-wave.md b/.changeset/wet-olives-wave.md deleted file mode 100644 index 5b35e0ad90..0000000000 --- a/.changeset/wet-olives-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -added aria-label on api definition button for better a11y. diff --git a/.changeset/wet-timers-chew.md b/.changeset/wet-timers-chew.md deleted file mode 100644 index 3be6368331..0000000000 --- a/.changeset/wet-timers-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. diff --git a/.changeset/wicked-rings-flash.md b/.changeset/wicked-rings-flash.md deleted file mode 100644 index b872c0c71f..0000000000 --- a/.changeset/wicked-rings-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-react': patch ---- - -Create `createSearchResultListItem` alpha version that only supports declarative integration. diff --git a/.changeset/wild-jobs-greet.md b/.changeset/wild-jobs-greet.md deleted file mode 100644 index fdbe6d56ac..0000000000 --- a/.changeset/wild-jobs-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -Prevents root extension override and duplicated plugin extensions. diff --git a/.changeset/wild-queens-grab.md b/.changeset/wild-queens-grab.md deleted file mode 100644 index 287dc0482e..0000000000 --- a/.changeset/wild-queens-grab.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-playlist': patch ---- - -Updated Playlist read me with additional screenshots diff --git a/.changeset/wild-toys-arrive.md b/.changeset/wild-toys-arrive.md deleted file mode 100644 index 4aad036a96..0000000000 --- a/.changeset/wild-toys-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-newrelic-dashboard': minor ---- - -Add storybook for newrelic-dashboard plugin. diff --git a/.changeset/wise-waves-approve.md b/.changeset/wise-waves-approve.md new file mode 100644 index 0000000000..f543f8918c --- /dev/null +++ b/.changeset/wise-waves-approve.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Ignore `stdin` when spawning backend child process for the `start` command. Fixing an issue where backend startup would hang. diff --git a/.changeset/wise-weeks-design.md b/.changeset/wise-weeks-design.md new file mode 100644 index 0000000000..657a8e23d5 --- /dev/null +++ b/.changeset/wise-weeks-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Add examples for `publish:github:pull-request` scaffolder action & improve related tests diff --git a/.changeset/yellow-numbers-own.md b/.changeset/yellow-numbers-own.md deleted file mode 100644 index 3a6e8937eb..0000000000 --- a/.changeset/yellow-numbers-own.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Added missing `.eslintignore` file - -To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: - -```diff -+ playwright.config.ts -``` diff --git a/.changeset/yellow-rings-invent.md b/.changeset/yellow-rings-invent.md deleted file mode 100644 index f0335ff492..0000000000 --- a/.changeset/yellow-rings-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. diff --git a/.changeset/young-days-talk.md b/.changeset/young-days-talk.md new file mode 100644 index 0000000000..b7420c7894 --- /dev/null +++ b/.changeset/young-days-talk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-react': patch +--- + +Use default extensions boundary and suspense on the alpha declarative `createSearchResultListItem` extension factory. diff --git a/.changeset/young-ducks-heal.md b/.changeset/young-ducks-heal.md deleted file mode 100644 index 28614e47bc..0000000000 --- a/.changeset/young-ducks-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -Adding optional audience parameter to OAuthState type declaration diff --git a/.changeset/young-toes-knock.md b/.changeset/young-toes-knock.md deleted file mode 100644 index 6371dec193..0000000000 --- a/.changeset/young-toes-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-opencost': patch ---- - -Fix for broken image reference. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 25073c9556..92f2d57885 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -32,6 +32,7 @@ yarn.lock @backstage/maintainers @backst /plugins/catalog-backend-module-msgraph @backstage/maintainers @backstage/reviewers @backstage/catalog-maintainers @pjungermann /plugins/catalog-backend-module-puppetdb @backstage/maintainers @backstage/reviewers @backstage/catalog-maintainers /plugins/catalog-graph @backstage/maintainers @backstage/reviewers @backstage/catalog-maintainers @backstage/sda-se-reviewers +/plugins/cicd-statistics @backstage/sharks /plugins/circleci @backstage/maintainers @backstage/reviewers @adamdmharvey /plugins/code-coverage @backstage/maintainers @backstage/reviewers @alde /plugins/code-coverage-backend @backstage/maintainers @backstage/reviewers @alde diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index e6c0aa9632..e1c65fec06 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -430,6 +430,7 @@ Valentina validator validators varchar +vite VMware Vodafone VPCs @@ -455,3 +456,4 @@ Pulumi Lightsail PR rebasing +lookbehind diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index 3d616506e1..dfb60c9243 100644 --- a/.github/workflows/automate_area-labels.yml +++ b/.github/workflows/automate_area-labels.yml @@ -2,11 +2,22 @@ name: Automate area labels on: - pull_request_target +permissions: + contents: read + jobs: triage: + permissions: + contents: read # for actions/labeler to determine modified files + pull-requests: write # for actions/labeler to add labels to PRs runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/labeler@v4.3.0 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' sync-labels: true diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index 9cadf12b4f..483d59dc8c 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -22,7 +22,12 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.pull_request.user.login != 'backstage-service' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 with: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml index 9fed796aa5..4cbf6c69a2 100644 --- a/.github/workflows/automate_merge_message.yml +++ b/.github/workflows/automate_merge_message.yml @@ -23,7 +23,12 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.pull_request.merged == true runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 with: ref: '${{ github.event.pull_request.merge_commit_sha }}' @@ -39,7 +44,7 @@ jobs: node generate.js ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} > message.txt - name: Post Message - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 env: ISSUE_NUMBER: ${{ github.event.pull_request.number }} with: diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index 452ecc48d6..40ebdf8a3e 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -4,11 +4,22 @@ on: schedule: - cron: '*/10 * * * *' # run every 10 minutes as it also removes labels. +permissions: + contents: read + jobs: stale: + permissions: + issues: write # for actions/stale to close stale issues + pull-requests: write # for actions/stale to close stale PRs runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/stale@v7.0.0 id: stale with: stale-issue-message: > diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml index 16bf11dd1a..7234e945e3 100644 --- a/.github/workflows/ci-noop.yml +++ b/.github/workflows/ci-noop.yml @@ -7,6 +7,9 @@ on: paths: - 'microsite/**' +permissions: + contents: read + jobs: # The verify jobs runs all the verification that doesn't require a # diff towards master, since it takes some time to fetch that. @@ -19,6 +22,11 @@ jobs: name: Verify ${{ matrix.node-version }} steps: + # - name: Harden Runner + # uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + # with: + # egress-policy: audit + - run: echo NOOP test-noop: @@ -30,4 +38,9 @@ jobs: name: Test ${{ matrix.node-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12c19075a6..81ea6f96d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,10 +26,15 @@ jobs: name: Install ${{ matrix.node-version }} steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -57,10 +62,15 @@ jobs: name: Verify ${{ matrix.node-version }} steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -186,12 +196,12 @@ jobs: INTEGRATION_TEST_AZURE_TOKEN: ${{ secrets.INTEGRATION_TEST_AZURE_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3.6.0 - name: fetch branch master run: git fetch origin master - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index ef8906818f..2874be512c 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -8,6 +8,11 @@ jobs: cron: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - uses: backstage/actions/cron@v0.6.4 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 231b81598e..30e7badcd0 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -13,14 +13,19 @@ jobs: node-version: [18.x] steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: path: backstage ref: v${{ github.event.client_payload.version }} - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -40,17 +45,17 @@ jobs: working-directory: ./example-app - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v2.2.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v2.10.0 - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v4.2.1 with: context: './example-app' file: ./example-app/packages/backend/Dockerfile diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index dddb2de4af..f614db31ca 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -4,8 +4,13 @@ on: branches: - master +permissions: + contents: read + jobs: deploy-microsite-and-storybook: + permissions: + contents: write # for JamesIves/github-pages-deploy-action to push changes in repo runs-on: ubuntu-latest env: @@ -18,10 +23,15 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js 18.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth @@ -56,7 +66,7 @@ jobs: run: ls microsite/build && ls microsite/build/storybook - name: Deploy both microsite and storybook to gh-pages - uses: JamesIves/github-pages-deploy-action@v4.4.3 + uses: JamesIves/github-pages-deploy-action@a1ea191d508feb8485aceba848389d49f80ca2dc # v4.4.3 with: branch: gh-pages folder: microsite/build diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index e48a6b97ab..d5fe9f5a64 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -14,15 +14,20 @@ jobs: NODE_OPTIONS: --max-old-space-size=4096 steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: use node.js 18.x - uses: actions/setup-node@v3 + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.6.4 + uses: backstage/actions/yarn-install@497722d45fb5a35c14c721f63ed74e6ad5f629dd # v0.6.4 with: cache-prefix: ${{ runner.os }}-v18.x @@ -59,7 +64,7 @@ jobs: - name: Discord notification if: ${{ failure() }} - uses: Ilshidur/action-discord@0.3.2 + uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # 0.3.2 env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} with: diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 2329101eb0..f5ebfd7ee2 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -60,10 +60,10 @@ jobs: INTEGRATION_TEST_AZURE_TOKEN: ${{ secrets.INTEGRATION_TEST_AZURE_TOKEN }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -112,7 +112,7 @@ jobs: - name: Discord notification if: ${{ failure() }} - uses: Ilshidur/action-discord@0.3.2 + uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # 0.3.2 env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} with: @@ -137,10 +137,15 @@ jobs: NODE_OPTIONS: --max-old-space-size=4096 steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -185,7 +190,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} - name: Dispatch repository event - uses: peter-evans/repository-dispatch@v2 + uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 # v2.1.2 with: token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} event-type: release-published @@ -193,7 +198,7 @@ jobs: # Notify everyone about this great new release :D - name: Discord notification - uses: Ilshidur/action-discord@0.3.2 + uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # 0.3.2 env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }} TAG_NAME: ${{ steps.create_tag.outputs.tag_name }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 89595db189..1c1c028f20 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -9,5 +9,10 @@ jobs: if: github.repository == 'backstage/backstage' steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Issue sync uses: backstage/actions/issue-sync@v0.6.4 diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml index 67e4c5abba..784dc6cf79 100644 --- a/.github/workflows/pr-review-comment-trigger.yaml +++ b/.github/workflows/pr-review-comment-trigger.yaml @@ -7,6 +7,9 @@ on: types: - created +permissions: + contents: read + jobs: trigger: runs-on: ubuntu-latest @@ -16,13 +19,18 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.comment.user.id == github.event.pull_request.user.id steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Save PR number env: PR_NUMBER: ${{ github.event.pull_request.number }} run: | mkdir -p ./pr echo $PR_NUMBER > ./pr/pr_number - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v3.1.3 with: name: pr_number-${{ github.event.pull_request.number }} path: pr/ diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index 0930c75ddd..e557c85d51 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -16,9 +16,14 @@ jobs: steps: # Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Read PR Number id: pr-number - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index a92effbd14..8c99f105a9 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -17,6 +17,11 @@ jobs: # Avoid running on issue comments if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: PR sync uses: backstage/actions/pr-sync@v0.6.4 with: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index ab53549052..c9078f0086 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -28,8 +28,13 @@ jobs: id-token: write steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: 'Checkout code' - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@v3.6.0 with: persist-credentials: false @@ -53,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: 'Upload artifact' - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@v3.1.3 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 6471b265bc..fa8d91f25a 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -9,13 +9,18 @@ jobs: name: Autofix Markdown files using Prettier runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: # Fetch changes to previous commit - required for 'only_changed' in Prettier action fetch-depth: 0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -25,7 +30,7 @@ jobs: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: Run Prettier on ADOPTERS.md - uses: creyD/prettier_action@v4.3 + uses: creyD/prettier_action@31355f8eef017f8aeba2e0bc09d8502b13dbbad1 # v4.3 with: # Modifies commit only if prettier autofixed the ADOPTERS.md prettier_options: --config docs/prettier.config.js --write ADOPTERS.md diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index d5f6f9a36c..2ac6d7f0d0 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -10,8 +10,13 @@ jobs: runs-on: ubuntu-latest if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage' steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: fetch-depth: 2 ref: ${{ github.head_ref }} @@ -21,7 +26,7 @@ jobs: git config --global user.email noreply@backstage.io git config --global user.name 'Github changeset workflow' - name: Generate changeset - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: script: | const { promises: fs } = require('fs'); diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index df8d3909f4..46d5d5382a 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -7,8 +7,13 @@ jobs: create-new-version: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + # Setup node & install deps before checkout, keeping install quick - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v3.8.1 with: node-version: 18.x - name: Install dependencies @@ -16,7 +21,7 @@ jobs: run: npm install semver@7.3.5 fs-extra@10.0.0 @manypkg/get-packages@1.1.1 - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: path: backstage # 'v' prefix is added here for the tag, we keep it out of the manifest logic @@ -24,7 +29,7 @@ jobs: # Checkout backstage/versions into /backstage/versions, which is where store the output - name: Checkout versions - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: repository: backstage/versions path: backstage/versions @@ -48,7 +53,7 @@ jobs: git push - name: Dispatch update-helper update - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} # TODO(Rugvip): Remove the create-app dispatch once we've been on the release version for a while diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index cd67fa9954..738abcf773 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -10,8 +10,13 @@ jobs: runs-on: ubuntu-latest if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: fetch-depth: 2 ref: ${{ github.head_ref }} @@ -21,7 +26,7 @@ jobs: git config --global user.email noreply@backstage.io git config --global user.name 'Github changeset workflow' - name: Generate changeset - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: script: | const { promises: fs } = require("fs"); diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index 6b55609bd5..690e2fb76e 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -11,10 +11,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js 18.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ # Needed for auth @@ -24,7 +29,7 @@ jobs: cache-prefix: ${{ runner.os }}-v18.x - name: Create Snyk report - uses: snyk/actions/node@master + uses: snyk/actions/node@299cde98a08ff8b1c2bfde1e5a067bce67a6d2b8 # master continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found with: args: > diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index 8bfa90d726..6450b1bd51 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -14,13 +14,24 @@ on: # ignore policies in the .snyk files and then have them show up in the snyk web # UI, and also automatically adds any new packages that are created. +permissions: + contents: read + jobs: sync: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: Monitor and Synchronize Snyk Policies - uses: snyk/actions/node@master + uses: snyk/actions/node@299cde98a08ff8b1c2bfde1e5a067bce67a6d2b8 # master with: command: monitor args: > @@ -35,7 +46,7 @@ jobs: # Above we run the `monitor` command, this runs the `test` command which is # the one that generates the SARIF report that we can upload to GitHub. - name: Create Snyk report - uses: snyk/actions/node@master + uses: snyk/actions/node@299cde98a08ff8b1c2bfde1e5a067bce67a6d2b8 # master continue-on-error: true # To make sure that SARIF upload gets called with: args: > @@ -47,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v2.21.8 with: sarif_file: snyk.sarif diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml index 127c11791d..929fb9cc89 100644 --- a/.github/workflows/sync_version-packages.yml +++ b/.github/workflows/sync_version-packages.yml @@ -13,7 +13,12 @@ jobs: name: Create Changeset PR runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 with: fetch-depth: 20000 fetch-tags: true @@ -21,7 +26,7 @@ jobs: - name: Install Dependencies run: yarn --immutable - name: Create Release Pull Request - uses: backstage/changesets-action@v2 + uses: backstage/changesets-action@v2.1.0 with: # Calls out to `changeset version`, but also runs prettier version: yarn release @@ -31,7 +36,7 @@ jobs: - name: Discord notification if: ${{ failure() }} - uses: Ilshidur/action-discord@0.3.2 + uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # 0.3.2 env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} with: diff --git a/.github/workflows/uffizzi-build.yml b/.github/workflows/uffizzi-build.yml index 1bcd5ebcd8..3107b87b8f 100644 --- a/.github/workflows/uffizzi-build.yml +++ b/.github/workflows/uffizzi-build.yml @@ -19,11 +19,16 @@ jobs: outputs: tags: ${{ steps.meta.outputs.tags }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 - name: setup-node - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: 18.x registry-url: https://registry.npmjs.org/ @@ -46,7 +51,7 @@ jobs: yarn workspace example-backend build - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0 - name: Generate UUID image name id: uuid @@ -54,13 +59,13 @@ jobs: - name: Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 with: images: registry.uffizzi.com/${{ env.UUID_TAG_APP }} tags: type=raw,value=60d - name: Build Image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@0a97817b6ade9f46837855d676c4cca3a2471fc9 # v4.2.1 with: context: . file: packages/backend/Dockerfile @@ -76,8 +81,13 @@ jobs: outputs: compose-file-cache-key: ${{ steps.hash.outputs.hash }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Checkout git repo - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 - name: Render Compose File run: | BACKSTAGE_IMAGE=$(echo ${{ needs.build-backstage.outputs.tags }}) @@ -86,13 +96,13 @@ jobs: envsubst '$BACKSTAGE_IMAGE $GITHUB_SHA' < .github/uffizzi/docker-compose.uffizzi.yml > docker-compose.rendered.yml cat docker-compose.rendered.yml - name: Upload Rendered Compose File as Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v3.1.3 with: name: preview-spec path: docker-compose.rendered.yml retention-days: 2 - name: Upload PR Event as Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v3.1.3 with: name: preview-spec path: ${{ github.event_path }} @@ -103,9 +113,14 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.action == 'closed' }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + # If this PR is closing, we will not render a compose file nor pass it to the next workflow. - name: Upload PR Event as Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v3.1.3 with: name: preview-spec path: ${{ github.event_path }} diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index 87c1eaa02f..deebf356bf 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -17,9 +17,14 @@ jobs: git-ref: ${{ env.GIT_REF }} pr-number: ${{ env.PR_NUMBER }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: 'Download artifacts' # Fetch output (zip archive) from the workflow run that triggered this workflow. - uses: actions/github-script@v6 + uses: actions/github-script@v6.4.1 with: script: | let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -59,7 +64,7 @@ jobs: - name: Cache Rendered Compose File if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} - uses: actions/cache@v3 + uses: actions/cache@v3.3.2 with: path: docker-compose.rendered.yml key: ${{ env.COMPOSE_FILE_HASH }} diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml index bde483eece..e2b1860b28 100644 --- a/.github/workflows/verify_accessibility-noop.yml +++ b/.github/workflows/verify_accessibility-noop.yml @@ -17,9 +17,17 @@ on: - 'plugins/search/src/**' - 'plugins/search-react/src/**' +permissions: + contents: read + jobs: noop: name: Accessibility runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml index 32ded3bd3a..d53f3834d2 100644 --- a/.github/workflows/verify_accessibility.yml +++ b/.github/workflows/verify_accessibility.yml @@ -19,9 +19,14 @@ jobs: name: Accessibility runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: Use Node.js 18.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: 18.x - name: yarn install diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index f3417ac582..666bd5f0f4 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -19,8 +19,15 @@ on: schedule: - cron: '0 8 * * 6' +permissions: + contents: read + jobs: analyze: + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/autobuild to send a status report name: Analyze runs-on: ubuntu-latest @@ -34,8 +41,13 @@ jobs: # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -43,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v2.21.8 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -54,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v2.21.8 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -68,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v2.21.8 diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index dc1d942e32..ce457a234f 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -11,7 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 # Vale does not support file excludes, so we use the script to generate a list of files instead # The action also does not allow args or a local config file to be passed in, so the files array @@ -21,7 +26,7 @@ jobs: run: echo "args=$(node scripts/check-docs-quality.js --ci-args)" >> $GITHUB_OUTPUT - name: documentation quality check - uses: errata-ai/vale-action@v2.0.1 + uses: errata-ai/vale-action@c4213d4de3d5f718b8497bd86161531c78992084 # v2.0.1 with: # This also contains --config=.github/vale/config.ini ... :/ files: '${{ steps.generate.outputs.args }}' diff --git a/.github/workflows/verify_e2e-kubernetes-noop.yml b/.github/workflows/verify_e2e-kubernetes-noop.yml index bedf357079..5c52968820 100644 --- a/.github/workflows/verify_e2e-kubernetes-noop.yml +++ b/.github/workflows/verify_e2e-kubernetes-noop.yml @@ -9,6 +9,9 @@ on: - '.github/workflows/verify_e2e-kubernetes.yml' - 'packages/backend-common/src/**' +permissions: + contents: read + jobs: verify: runs-on: ubuntu-latest @@ -19,4 +22,9 @@ jobs: name: Kubernetes ${{ matrix.node-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_e2e-kubernetes.yml b/.github/workflows/verify_e2e-kubernetes.yml index 0c78c1f933..cddd6589d7 100644 --- a/.github/workflows/verify_e2e-kubernetes.yml +++ b/.github/workflows/verify_e2e-kubernetes.yml @@ -21,10 +21,15 @@ jobs: name: Kubernetes ${{ matrix.node-version }} steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -35,7 +40,7 @@ jobs: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: bootstrap kind - uses: helm/kind-action@v1.8.0 + uses: helm/kind-action@dda0770415bac9fc20092cacbc54aa298604d140 # v1.8.0 - name: kubernetes test working-directory: packages/backend-common diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml index 1384b83378..27e08c7055 100644 --- a/.github/workflows/verify_e2e-linux-noop.yml +++ b/.github/workflows/verify_e2e-linux-noop.yml @@ -14,6 +14,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: noop: runs-on: ubuntu-latest @@ -24,4 +27,9 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 61ce55e385..744a5d7e74 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -39,7 +39,12 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: Configure Git run: | @@ -47,7 +52,7 @@ jobs: git config --global user.name 'GitHub e2e user' - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index fd5c4f0956..94f08a491f 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -12,6 +12,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: verify: runs-on: ubuntu-latest @@ -26,8 +29,13 @@ jobs: name: Techdocs steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 + - uses: actions/setup-python@v4.7.0 with: python-version: '3.9' diff --git a/.github/workflows/verify_e2e-windows-noop.yml b/.github/workflows/verify_e2e-windows-noop.yml index f042c350c2..e4b8556f58 100644 --- a/.github/workflows/verify_e2e-windows-noop.yml +++ b/.github/workflows/verify_e2e-windows-noop.yml @@ -11,6 +11,9 @@ on: - 'packages/e2e-test/**' - 'packages/create-app/**' +permissions: + contents: read + jobs: noop: runs-on: windows-2019 @@ -21,4 +24,9 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index b1decefd10..1385983c24 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -30,6 +30,11 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + # In order to have the create-app template function as if it was downloaded from NPM # we need to make sure we checkout files with LF line endings only - name: Set git to use LF @@ -37,7 +42,7 @@ jobs: git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@v3 + - uses: actions/checkout@v3.6.0 - name: Configure Git run: | @@ -45,13 +50,13 @@ jobs: git config --global user.name 'GitHub e2e user' - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v4.7.0 with: python-version: '3.10' @@ -70,7 +75,7 @@ jobs: npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"} - name: setup chrome - uses: browser-actions/setup-chrome@latest + uses: browser-actions/setup-chrome@803ef6dfb4fdf22089c9563225d95e4a515820a0 # latest - name: yarn install uses: backstage/actions/yarn-install@v0.6.4 diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml index 8c6b25d2e4..393bcf9631 100644 --- a/.github/workflows/verify_fossa.yml +++ b/.github/workflows/verify_fossa.yml @@ -5,13 +5,21 @@ on: pull_request: branches: [master] +permissions: + contents: read + jobs: analyze: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3.6.0 - name: Install Fossa run: "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash" diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml index cca7e512c5..8c329a0f27 100644 --- a/.github/workflows/verify_microsite-noop.yml +++ b/.github/workflows/verify_microsite-noop.yml @@ -11,10 +11,18 @@ on: - 'mkdocs.yml' - 'docs/**' +permissions: + contents: read + jobs: noop: runs-on: ubuntu-latest name: Microsite steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index d219d0ea74..f0705bedc7 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -9,6 +9,9 @@ on: - 'mkdocs.yml' - 'docs/**' +permissions: + contents: read + jobs: build-microsite: runs-on: ubuntu-latest @@ -20,10 +23,15 @@ jobs: name: Microsite steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js 18.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: 18.x diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml index c1f16e4fbd..aee4623d5a 100644 --- a/.github/workflows/verify_storybook-noop.yml +++ b/.github/workflows/verify_storybook-noop.yml @@ -18,10 +18,18 @@ on: - 'packages/core-components/src/**' - '**/*.stories.tsx' +permissions: + contents: read + jobs: noop: runs-on: ubuntu-latest name: Storybook steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + - run: echo NOOP diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index bcb0cfe178..f0354df296 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -27,12 +27,17 @@ jobs: name: Storybook steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 with: fetch-depth: 0 # Required to retrieve git history - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth @@ -46,7 +51,7 @@ jobs: - run: yarn build-storybook - - uses: chromaui/action@v1 + - uses: chromaui/action@807600692d28833b717c155e15ed20905cdc865c # v1 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 312c662b5a..f2c61938d8 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -7,6 +7,9 @@ on: paths: - '.github/workflows/verify_windows.yml' +permissions: + contents: read + jobs: build: runs-on: windows-2022 @@ -25,10 +28,15 @@ jobs: INTEGRATION_TEST_AZURE_TOKEN: ${{ secrets.INTEGRATION_TEST_AZURE_TOKEN }} steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + egress-policy: audit + + - uses: actions/checkout@v3.6.0 - name: use node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.8.1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth diff --git a/.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch b/.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch new file mode 100644 index 0000000000..1e3c82e9dd --- /dev/null +++ b/.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch @@ -0,0 +1,112 @@ +diff --git a/DateTimePicker/DateTimePickerTabs.d.ts b/DateTimePicker/DateTimePickerTabs.d.ts +index 52396cccbb66861dd6519459141e7744aa25aaf8..75c5a9053a88abf2454b7783c0101a1a8c9375f1 100644 +--- a/DateTimePicker/DateTimePickerTabs.d.ts ++++ b/DateTimePicker/DateTimePickerTabs.d.ts +@@ -7,5 +7,5 @@ export interface DateTimePickerTabsProps { + timeIcon?: React.ReactNode; + } + export declare const useStyles: (props?: any) => Record<"tabs", string>; +-export declare const DateTimePickerTabs: React.SFC; ++export declare const DateTimePickerTabs: React.FC; + export default DateTimePickerTabs; +diff --git a/_shared/ModalDialog.d.ts b/_shared/ModalDialog.d.ts +index 067070067ccf6e7699d17f422934daf14370d225..c45a583adef09a2091865db91b2687e66af81b47 100644 +--- a/_shared/ModalDialog.d.ts ++++ b/_shared/ModalDialog.d.ts +@@ -15,7 +15,7 @@ export interface ModalDialogProps extends DialogProps { + showTabs?: boolean; + wider?: boolean; + } +-export declare const ModalDialog: React.SFC>; ++export declare const ModalDialog: React.FC>; + export declare const styles: Record<"dialog" | "dialogRoot" | "dialogRootWider" | "withAdditionalAction", import("@material-ui/core/styles/withStyles").CSSProperties | import("@material-ui/core/styles/withStyles").CreateCSSProperties<{}> | ((props: {}) => import("@material-ui/core/styles/withStyles").CreateCSSProperties<{}>)>; + declare const _default: React.ComponentType; +diff --git a/_shared/PickerToolbar.d.ts b/_shared/PickerToolbar.d.ts +index f1ccd368bf9ab853cf0356d03fce0390becad8cd..e75ef734788cb26cc07dc079c714f759f525c447 100644 +--- a/_shared/PickerToolbar.d.ts ++++ b/_shared/PickerToolbar.d.ts +@@ -5,5 +5,5 @@ export declare const useStyles: (props?: any) => Record<"toolbar" | "toolbarLand + interface PickerToolbarProps extends ExtendMui { + isLandscape: boolean; + } +-declare const PickerToolbar: React.SFC; ++declare const PickerToolbar: React.FC; + export default PickerToolbar; +diff --git a/_shared/WithUtils.d.ts b/_shared/WithUtils.d.ts +index 22fe0425817be182a6c9a1a21a0f9eefb61696e7..b5b2a966ec0ea8427c4355227d8425b9c1af3790 100644 +--- a/_shared/WithUtils.d.ts ++++ b/_shared/WithUtils.d.ts +@@ -4,4 +4,4 @@ import { MaterialUiPickersDate } from '../typings/date'; + export interface WithUtilsProps { + utils: IUtils; + } +-export declare const withUtils: () =>

(Component: React.ComponentType

) => React.SFC>>; ++export declare const withUtils: () =>

(Component: React.ComponentType

) => React.FC>>; +diff --git a/_shared/icons/ArrowLeftIcon.d.ts b/_shared/icons/ArrowLeftIcon.d.ts +index ce0f208a2aa6dae03a77dfe830a10a95c2085030..95a516da22e02b9a4167ee4a52bf2cd0a1b4aec6 100644 +--- a/_shared/icons/ArrowLeftIcon.d.ts ++++ b/_shared/icons/ArrowLeftIcon.d.ts +@@ -1,3 +1,3 @@ + import React from 'react'; + import { SvgIconProps } from '@material-ui/core/SvgIcon'; +-export declare const ArrowLeftIcon: React.SFC; ++export declare const ArrowLeftIcon: React.FC; +diff --git a/_shared/icons/ArrowRightIcon.d.ts b/_shared/icons/ArrowRightIcon.d.ts +index 71443a34f7bbd2cef8c2af487c817b7ea788dd7a..a96314aa8750180773f1d006ed766e5a7e8e071d 100644 +--- a/_shared/icons/ArrowRightIcon.d.ts ++++ b/_shared/icons/ArrowRightIcon.d.ts +@@ -1,3 +1,3 @@ + import React from 'react'; + import { SvgIconProps } from '@material-ui/core/SvgIcon'; +-export declare const ArrowRightIcon: React.SFC; ++export declare const ArrowRightIcon: React.FC; +diff --git a/_shared/icons/DateRangeIcon.d.ts b/_shared/icons/DateRangeIcon.d.ts +index 722f8736d86f248d464c5af855795663d9e220d3..6018043d41861d96335f060ea1dc78336892ce66 100644 +--- a/_shared/icons/DateRangeIcon.d.ts ++++ b/_shared/icons/DateRangeIcon.d.ts +@@ -1,3 +1,3 @@ + import React from 'react'; + import { SvgIconProps } from '@material-ui/core/SvgIcon'; +-export declare const DateRangeIcon: React.SFC; ++export declare const DateRangeIcon: React.FC; +diff --git a/_shared/icons/KeyboardIcon.d.ts b/_shared/icons/KeyboardIcon.d.ts +index c1a0a111d831acc58cf19aa6d54f8324e68de9d8..8d7d1dac47815cef02215c4f11f36e73509b4219 100644 +--- a/_shared/icons/KeyboardIcon.d.ts ++++ b/_shared/icons/KeyboardIcon.d.ts +@@ -1,3 +1,3 @@ + import React from 'react'; + import { SvgIconProps } from '@material-ui/core/SvgIcon'; +-export declare const KeyboardIcon: React.SFC; ++export declare const KeyboardIcon: React.FC; +diff --git a/_shared/icons/TimeIcon.d.ts b/_shared/icons/TimeIcon.d.ts +index 49e0b627132f7d31d1b0a205548229a9f7a2c0a6..15ebc6e630992edb3b01790c0dd651651adf51de 100644 +--- a/_shared/icons/TimeIcon.d.ts ++++ b/_shared/icons/TimeIcon.d.ts +@@ -1,3 +1,3 @@ + import React from 'react'; + import { SvgIconProps } from '@material-ui/core/SvgIcon'; +-export declare const TimeIcon: React.SFC; ++export declare const TimeIcon: React.FC; +diff --git a/views/Calendar/CalendarHeader.d.ts b/views/Calendar/CalendarHeader.d.ts +index 842cbd8e021eb6d8e6553ba68033f13140485b61..7f60b4bffce1a96ade02e2671fd705c8fe87dfa2 100644 +--- a/views/Calendar/CalendarHeader.d.ts ++++ b/views/Calendar/CalendarHeader.d.ts +@@ -15,5 +15,5 @@ export interface CalendarHeaderProps { + onMonthChange: (date: MaterialUiPickersDate, direction: SlideDirection) => void | Promise; + } + export declare const useStyles: (props?: any) => Record<"transitionContainer" | "switchHeader" | "iconButton" | "daysHeader" | "dayLabel", string>; +-export declare const CalendarHeader: React.SFC; ++export declare const CalendarHeader: React.FC; + export default CalendarHeader; +diff --git a/views/Calendar/SlideTransition.d.ts b/views/Calendar/SlideTransition.d.ts +index f00e98a72bd0e6cfd80ab45b33b905e802b60e9b..699119009fa5ea886e7f782425aee39b7608b8c2 100644 +--- a/views/Calendar/SlideTransition.d.ts ++++ b/views/Calendar/SlideTransition.d.ts +@@ -7,5 +7,5 @@ interface SlideTransitionProps { + children: React.ReactChild; + } + export declare const useStyles: (props?: any) => Record<"transitionContainer" | "slideEnter-left" | "slideEnter-right" | "slideEnterActive" | "slideExit" | "slideExitActiveLeft-left" | "slideExitActiveLeft-right", string>; +-declare const SlideTransition: React.SFC; ++declare const SlideTransition: React.FC; + export default SlideTransition; diff --git a/ADOPTERS.md b/ADOPTERS.md index b5e19106b7..f0d6e4ed0a 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -78,7 +78,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates
Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc | | [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. | | [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 | -| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 | +| [Keyloop](https://www.keyloop.com/) | [Shawn Bruce](https://github.com/sbruce-keyloop) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 | | [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. | | [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding | | [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. | diff --git a/OWNERS.md b/OWNERS.md index caf5bc4d14..2ea263f3b4 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -145,7 +145,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling. | ------------------------------ | ------------------------- | ----------------------------------------------------- | ------------------------------ | | Adam Harvey | Cisco | [adamdmharvey](https://github.com/adamdmharvey) | `adamharvey_` | | Alex Crome | | [afscrome](https://github.com/afscrome) | `afscrome` | -| Andre Wanlin | Keyloop | [awanlin](https://github.com/awanlin) | `ahhhndre` | +| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` | | Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` | | Aramis Sennyey | Spotify | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | | Brian Fletcher | Roadie.io | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` | diff --git a/docs/backend-system/architecture/02-backends.md b/docs/backend-system/architecture/02-backends.md index 4ba76a5af3..c64024d653 100644 --- a/docs/backend-system/architecture/02-backends.md +++ b/docs/backend-system/architecture/02-backends.md @@ -23,7 +23,7 @@ import scaffolderPlugin from '@backstage/plugin-scaffolder-backend'; const backend = createBackend(); // Install desired features -backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); // Features can also be installed using an explicit reference backend.add(scaffolderPlugin()); diff --git a/docs/backend-system/building-backends/01-index.md b/docs/backend-system/building-backends/01-index.md index 7d331b4ec3..c381999429 100644 --- a/docs/backend-system/building-backends/01-index.md +++ b/docs/backend-system/building-backends/01-index.md @@ -24,9 +24,9 @@ import { createBackend } from '@backstage/backend-defaults'; // Omitted in the e const backend = createBackend(); -backend.add(import('@backstage/plugin-app-backend')); -backend.add(import('@backstage/plugin-catalog-backend')); -backend.add(import('@backstage/plugin-scaffolder-backend')); +backend.add(import('@backstage/plugin-app-backend/alpha')); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), ); @@ -126,8 +126,8 @@ You can now trim down the `src/index.ts` files to only include the plugins and m ```ts const backend = createBackend(); -backend.add(import('@backstage/plugin-app-backend')); -backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(import('@backstage/plugin-app-backend/alpha')); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), ); @@ -139,7 +139,7 @@ And `backend-b`, don't forget to clean up dependencies in `package.json` as well ```ts const backend = createBackend(); -backend.add(import('@backstage/plugin-scaffolder-backend')); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); backend.start(); ``` diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 1a380421c1..1e30d0aa9e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -177,11 +177,10 @@ custom API, so we use a helper function to transform that particular one. To make additions as mentioned above to the environment, you will start to get into the weeds of how the backend system wiring works. You'll need to have a service reference and a service factory that performs the actual creation of -your service. Please see [the services -article](../architecture/03-services.md#defining-a-service) to learn how to -create a service ref and its default factory. You can place that code directly -in the index file for now if you want, or near the actual implementation class -in question. +your service. Please see [the services article](../architecture/03-services.md) +to learn how to create a service ref and its default factory. You can place that +code directly in the index file for now if you want, or near the actual implementation +class in question. In this example, we'll assume that your added environment field is named `example`, and the created ref is named `exampleServiceRef`. @@ -233,7 +232,7 @@ be used in its new form. ```ts title="packages/backend/src/index.ts" const backend = createBackend(); /* highlight-add-next-line */ -backend.add(import('@backstage/plugin-app-backend')); +backend.add(import('@backstage/plugin-app-backend/alpha')); ``` If you need to override the app package name, which otherwise defaults to `"app"`, @@ -248,7 +247,7 @@ A basic installation of the catalog plugin looks as follows. ```ts title="packages/backend/src/index.ts" const backend = createBackend(); /* highlight-add-start */ -backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), ); @@ -296,7 +295,7 @@ const catalogModuleCustomExtensions = createBackendModule({ /* highlight-add-end */ const backend = createBackend(); -backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(import('@backstage/plugin-catalog-backend/alpha')); backend.add( import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'), ); @@ -390,7 +389,7 @@ A basic installation of the scaffolder plugin looks as follows. ```ts title="packages/backend/src/index.ts" const backend = createBackend(); /* highlight-add-next-line */ -backend.add(import('@backstage/plugin-scaffolder-backend')); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); ``` If you have other customizations made to `plugins/scaffolder.ts`, such as adding @@ -429,7 +428,7 @@ const scaffolderModuleCustomExtensions = createBackendModule({ /* highlight-add-end */ const backend = createBackend(); -backend.add(import('@backstage/plugin-scaffolder-backend')); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); /* highlight-add-next-line */ backend.add(scaffolderModuleCustomExtensions()); ``` diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index 6a70e9e2aa..29f985904f 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -548,7 +548,7 @@ title Login Sequence #### Referenced PlantUML Diagram Example -Here, the markdown file refers to another file (_.puml or _.pu) which contains the diagram description. +Here, the markdown file refers to another file (`*.puml` or `*.pu`) which contains the diagram description. ````md ```plantuml diff --git a/docs/plugins/integrating-search-into-plugins.md b/docs/plugins/integrating-search-into-plugins.md index 7fb8e40b20..28c8b410e3 100644 --- a/docs/plugins/integrating-search-into-plugins.md +++ b/docs/plugins/integrating-search-into-plugins.md @@ -22,7 +22,7 @@ Imagine you have a plugin that is responsible for storing FAQ snippets in a data The search platform provides an interface (`DocumentCollatorFactory` from package `@backstage/plugin-search-common`) that allows you to do exactly that. It works by registering each of your entries as a "document" that later represents one search result each. -> You can always look at a working example, e.g. [StackOverflowQuestionsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts), if you are unsure or want to follow best practices. +> You can always look at a working example, e.g. [StackOverflowQuestionsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts), if you are unsure or want to follow best practices. #### 1. Install collator interface dependencies diff --git a/docs/publishing.md b/docs/publishing.md index 2424bc1352..f8964278b5 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -40,7 +40,7 @@ Congratulations on the release! There should be now a post in the [`#announcemen Additional steps for the main line release - [Switch Release Mode](#switching-release-modes) to exit pre-release mode. This can be done at any time after the last Next Line Release. - - Check [`.changeset/pre.json`](https://github.com/backstage/backstage/blob/master/.changeset/pre.json) if the `mode` is set to `exit`. If you encounter `mode: "pre"` it indicates a next line release. + - Check `.changeset/pre.json` if the `mode` is set to `exit`. If you encounter `mode: "pre"` it indicates a next line release. - Check [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages) - Check for mentions of "major" & "breaking" and if they are expected in the current release - Verify the version we are shipping is correct diff --git a/docs/releases/v1.19.0-changelog.md b/docs/releases/v1.19.0-changelog.md new file mode 100644 index 0000000000..7397ccdba7 --- /dev/null +++ b/docs/releases/v1.19.0-changelog.md @@ -0,0 +1,3632 @@ +# Release v1.19.0 + +## @backstage/cli@0.23.0 + +### Minor Changes + +- 8defbd5434: Update typescript-eslint to 6.7.x, adding compatibility with TypeScript 5.2. + + This includes a major update on typescript-eslint, you can see the details in the [release notes](https://typescript-eslint.io/blog/announcing-typescript-eslint-v6/). + +- 7077dbf131: **BREAKING** The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior set `LEGACY_BACKEND_START`, which is recommended if you haven't migrated to the new backend system. + + This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. + +### Patch Changes + +- 9468a67b92: In frontend builds and tests `process.env.HAS_REACT_DOM_CLIENT` will now be defined if `react-dom/client` is present, i.e. if using React 18. This allows for conditional imports of `react-dom/client`. + +- 68158034e8: Fix for the new backend `start` command to make it work on Windows. + +- 4f16e60e6d: Request slightly smaller pages of data from GitHub + +- 21cd3b1b24: Added a template for creating `node-library` packages with `yarn new`. + +- d0f26cfa4f: Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. + +- 1ea20b0be5: Updated dependency `@typescript-eslint/eslint-plugin` to `6.7.5`. + +- 2ef6522552: Support for the `.icon.svg` extension has been deprecated and will be removed in the future. The implementation of this extension is too tied to a particular version of MUI and the SVGO, and it makes it harder to evolve the build system. We may introduce the ability to reintroduce this kind of functionality in the future through configuration for use in internal plugins, but for now we're forced to remove it. + + To migrate existing code, rename the `.icon.svg` file to `.tsx` and replace the `` element with `` from MUI and add necessary imports. For example: + + ```tsx + import React from 'react'; + import SvgIcon from '@material-ui/core/SvgIcon'; + import { IconComponent } from '@backstage/core-plugin-api'; + + export const CodeSceneIcon = (props: SvgIconProps) => ( + + + + + + ); + ``` + +- b9ec93430e: The scaffolder-module template now recommends usage of `createMockDirectory` instead of `mock-fs`. + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + +- 425203f898: Fixed recursive reloading issues of the backend, caused by unwanted watched files. + +- 3ef18f8c06: Explicitly set `exports: 'named'` for CJS builds, ensuring that they have e.g. `exports["default"] = catalogPlugin;` + +- 7187f2953e: The experimental package discovery will now always use the package name for include and exclude filtering, rather than the full module id. Entries pointing to a subpath export will now instead have an `export` field specifying the subpath that the import is from. + +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/eslint-plugin@0.1.3 + - @backstage/release-manifests@0.0.10 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.0 + +### Minor Changes + +- c9d9bfeca2: URL encode some well known unsafe characters in `RouteResolver` (and therefore `useRouteRef`) + +### Patch Changes + +- 29e4d8b76b: Fixed bug in `AppRouter` to determine the correct `signOutTargetUrl` if `app.baseUrl` contains a `basePath` +- acca17e91a: Wrap entire app in ``, enabling support for using translations outside plugins. +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- f1b349cfba: Fixed a bug in `TranslationApi` implementation where in some cases it wouldn't notify subscribers of language changes. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/core-plugin-api@1.7.0 + +### Minor Changes + +- 322bbcae24: Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/e2e-test-utils@0.1.0 + +### Minor Changes + +- f5b41b27a9: Initial release. + +## @backstage/frontend-app-api@0.2.0 + +### Minor Changes + +- 4461d87d5a: Removed support for the new `useRouteRef`. +- 9d03dfe5e3: The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. +- d7c5d80c57: The hidden `'root'` extension has been removed and has instead been made an input of the `'core'` extension. The checks for rejecting configuration of the `'root'` extension to rejects configuration of the `'core'` extension instead. +- d920b8c343: Added support for installing `ExtensionOverrides` via `createApp` options. As part of this change the `plugins` option has been renamed to `features`, and the `pluginLoader` has been renamed to `featureLoader`. + +### Patch Changes + +- 322bbcae24: Internal update for removal of experimental plugin configuration API. +- f78ac58f88: Filters for discovered packages are now also applied at runtime. This makes it possible to disable packages through the `app.experimental.packages` config at runtime. +- 68ffb9e67d: The app will now reject any extensions that attach to nonexistent inputs. +- 5072824817: Implement `toString()` and `toJSON()` for extension instances. +- 1e60a9c3a5: Fixed an issue preventing the routing system to match subroutes +- 52366db5b3: Make themes configurable through extensions, and switched default themes to use extensions instead. +- 2ecd33618a: Added the `bindRoutes` option to `createApp`. +- e5a2956dd2: Register default api implementations when creating declarative integrated apps. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 06432f900c: Updates for `at` -> `attachTo` refactor. +- 1718ec75b7: Added support for the existing routing system. +- 66d51a4827: Prevents root extension override and duplicated plugin extensions. +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/frontend-plugin-api@0.2.0 + +### Minor Changes + +- 06432f900c: Extension attachment point is now configured via `attachTo: { id, input }` instead of `at: 'id/input'`. +- 4461d87d5a: Removed support for the new `useRouteRef`. + +### Patch Changes + +- d3a37f55c0: Add support for `SidebarGroup` on the sidebar item extension. +- 2ecd33618a: Plugins can now be assigned `routes` and `externalRoutes` when created. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- c1e9ca6500: Added `createExtensionOverrides` which can be used to install a collection of extensions in an app that will replace any existing ones. +- 52366db5b3: Added `createThemeExtension` and `coreExtensionData.theme`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/types@1.1.1 + +## @techdocs/cli@1.6.0 + +### Minor Changes + +- d06b30b050: Add possibility to use a mkdocs config file with a different name than `mkdocs. with the serve command using the `--mkdocs-config-file-name\` argument + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 2b6e572051: Restructured tests. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.0 + +### Minor Changes + +- 6f142d5356: **BREAKING** `gcpIapAuthenticator.initialize()` is no longer `async` + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.0 + +### Minor Changes + +- 2d8f7e82c1: Migrated the Microsoft auth provider to new `@backstage/plugin-auth-backend-module-microsoft-provider` module package. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.0 + +### Minor Changes + +- ae34255836: Add new Pinniped auth module and authenticator to be used alongside the new Pinniped auth provider. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-node@0.4.0 + +### Minor Changes + +- 6f142d5356: **BREAKING**: The recently introduced `ProxyAuthenticator.initialize()` method is no longer `async` to match the way the OAuth equivalent is implemented. + +### Patch Changes + +- 6c2b0793bf: Fix for persisted scopes not being properly restored on sign-in. +- 8b8b1d23ae: Fixed cookie persisted scope not returned in OAuth refresh handler response. +- ae34255836: Adding optional audience parameter to OAuthState type declaration +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog@1.14.0 + +### Minor Changes + +- 28f1ab2e1a: The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: + + ```ts + import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + + const app = createApp({ + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, + }); + ``` + +- f3561a2935: include owner chip in catalog search result item + +### Patch Changes + +- 7c4a8e4d5f: Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- 0296f272b4: The \`spec.lifecycle' field in entities will now always be rendered as a string. +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- e5a2956dd2: Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-catalog-backend@1.14.0 + +### Minor Changes + +- 78af9433c8: Instrumenting some missing metrics with `OpenTelemetry` + +### Patch Changes + +- 7a2e2924c7: Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. +- 0b55f773a7: Removed some unused dependencies +- 348e8c1cdb: Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. +- b97e9790f0: Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-catalog-backend-module-aws@0.3.0 + +### Minor Changes + +- 5abc2fd4d6: AwsEksClusterProcessor supports Entity callback function and passes in region when initialize EKS cluster + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.0 + +### Minor Changes + +- c101e683d5: Added `catalogModuleGithubOrgEntityProvider` to ingest users and teams from multiple Github organizations. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend-module-github@0.4.4 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-graphql@0.4.0 + +### Minor Changes + +- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-graphql-backend@0.2.0 + +### Minor Changes + +- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-graphql@0.4.0 + - @backstage/config@1.1.1 + +## @backstage/plugin-jenkins@0.9.0 + +### Minor Changes + +- 411896faf9: Added JobRunTable Component. + Added new Route and extended Api to get buildJobs. + Actions column has a new icon button, clicking on which takes us to page where we + can see all the job runs. + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 1a05cf34f6: Extend EntityJenkinsContent to receive columns as prop +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-jenkins-common@0.1.20 + +## @backstage/plugin-jenkins-backend@0.3.0 + +### Minor Changes + +- 411896faf9: Added JobRunTable Component. + Added new Route and extended Api to get buildJobs. + Actions column has a new icon button, clicking on which takes us to page where we + can see all the job runs. + +### Patch Changes + +- 930ac236d8: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-jenkins-common@0.1.20 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-kubernetes@0.11.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- b0aca1a798: Updated dependency `xterm-addon-attach` to `^0.9.0`. + Updated dependency `xterm-addon-fit` to `^0.8.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-react@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-backend@0.13.0 + +### Minor Changes + +- ae943c3bb1: **BREAKING** Allow passing undefined `labelSelector` to `KubernetesFetcher` + + `KubernetesFetch` no longer auto-adds `labelSelector` when empty string was passed. + This is only applicable if you have custom ObjectProvider implementation, as build-in `KubernetesFanOutHandler` already does this + +### Patch Changes + +- cbb0e3c3f4: A new plugin has been introduced to house the extension points for Kubernetes backend plugin; at the moment only the `KubernetesObjectsProviderExtensionPoint` is present. The `kubernetes-backend` plugin was modified to use this new extension point. +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-node@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-kubernetes-common@0.7.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-kubernetes-node@0.1.0 + +### Minor Changes + +- cbb0e3c3f4: A new plugin has been introduced to house the extension points for Kubernetes backend plugin; at the moment only the `KubernetesObjectsProviderExtensionPoint` is present. The `kubernetes-backend` plugin was modified to use this new extension point. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-kubernetes-react@0.1.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 4262e12921: Handle mixed decimals and bigint when calculating k8s resource usage +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-newrelic-dashboard@0.3.0 + +### Minor Changes + +- d7eba6cab4: Changes in `newrelic-dashboard` plugin: + + - Make DashboardSnapshotList component public + - Settle discrepancies in the exported API + - Deprecate DashboardSnapshotComponent + +- e605ea4906: Add storybook for newrelic-dashboard plugin. + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 61d55942ae: Fix the styles for NewRelicDashboard, add more responsiveness +- 5194a51a1c: Fixed React Warning: "Each child in a list should have a unique 'key' prop" during the rendering of `EntityNewRelicDashboardCard` +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend@1.18.0 + +### Minor Changes + +- dea0aafda7: Updated `publish:gitlab` action properties to support additional Gitlab project settings: + + - general project settings provided by gitlab project create API (new `settings` property) + - branch level settings to create additional branches and make them protected (new `branches` property) + - project level environment variables settings (new `projectVariables` property) + + Marked existed properties `repoVisibility` and `topics` as deprecated, as they are covered by `settings` property. + +- f41099bb31: Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. + +### Patch Changes + +- 7dd82cc07e: Add examples for `github:issues:label` scaffolder action & improve related tests +- 733ddf7130: Add examples for `publish:Azure` scaffolder action. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-scaffolder-common@1.4.2 + +## @backstage/plugin-techdocs@1.8.0 + +### Minor Changes + +- 27740caa2d: Added experimental support for declarative integration via the `/alpha` subpath. + +### Patch Changes + +- 4918f65ab2: Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- 3605370af6: Improved `DocsTable` to display pagination controls dynamically, appearing only when needed. +- 0296f272b4: The \`spec.lifecycle' field in entities will now always be rendered as a string. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 9468a67b92: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- df449a7a31: Add kind column by default to TechDocsTable +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-techdocs-backend@1.8.0 + +### Minor Changes + +- 344cfbcfbc: Allow prepared directory clean up for custom preparers + + When using custom preparer for TechDocs, the `preparedDir` might + end up taking disk space. This requires all custom preparers to + implement a new method `shouldCleanPreparedDirectory` which indicates + whether the prepared directory should be cleaned after generation. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-techdocs-node@1.9.0 + +### Minor Changes + +- 344cfbcfbc: Allow prepared directory clean up for custom preparers + + When using custom preparer for TechDocs, the `preparedDir` might + end up taking disk space. This requires all custom preparers to + implement a new method `shouldCleanPreparedDirectory` which indicates + whether the prepared directory should be cleaned after generation. + +- d06b30b050: Add possibility to use a mkdocs config file with a different name than `mkdocs. with the serve command using the `--mkdocs-config-file-name\` argument + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/app-defaults@1.4.4 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + +## @backstage/backend-app-api@0.5.6 + +### Patch Changes + +- 74491c9602: Moved `HostDiscovery` from `@backstage/backend-common`. +- a4617c422a: Added `watch` option to configuration loaders that can be used to disable file watching by setting it to `false`. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.19.8 + +### Patch Changes + +- 74491c9602: The `HostDiscovery` export has been deprecated, import it from `@backstage/backend-app-api` instead. +- b95d66d4ea: Properly close write stream when writing temporary archive for processing zip-based `.readTree()` responses. +- b94f32271e: Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository +- 0b55f773a7: Removed some unused dependencies +- 4c39e38f1e: Added `/testUtils` entry point, with a utility for mocking resolve package paths as returned by `resolvePackagePath`. +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- a250ad775f: Removed `mock-fs` dev dependency. +- 2a40cd46a8: Adds the optional flag for useRedisSets for the Redis cache to the config. +- 1c3d6fa2b2: The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/backend-dev-utils@0.1.2 + +### Patch Changes + +- afa48341fb: Fix an issue where early IPC responses would be lost. + +## @backstage/backend-openapi-utils@0.0.5 + +### Patch Changes + +- 7c83975531: Adds new public utility types for common OpenAPI values, like request and response shapes and parameters available on an endpoint. + + **deprecated** `internal` namespace + The internal namespace will continue to be exported but now uses OpenAPI format for path parameters. You should use the new utility types. + +- Updated dependencies + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/backend-tasks@0.5.11 + +### Patch Changes + +- 5db102bfdf: Instrument `backend-tasks` with some counters and histograms for duration. + + `backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. + `backend_tasks.task.runs.duration`: Histogram with the run durations for each task. + + Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. + +- ddd76ac98d: Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.7 + +### Patch Changes + +- a250ad775f: Added `createMockDirectory()` to help out with file system mocking in tests. +- 5ddc03813e: Remove third type parameter used for `MockInstance`, in order to be compatible with older versions of `@types/jest`. +- 74491c9602: Updated to import `HostDiscovery` from `@backstage/backend-app-api`. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/catalog-client@1.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/catalog-model@1.4.3 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/cli-common@0.1.13 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + +## @backstage/cli-node@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/types@1.1.1 + +## @backstage/codemods@0.1.46 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/config@1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.5.1 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 30c553c1d2: Updated dependency `typescript-json-schema` to `^0.61.0`. +- 773ea341d2: The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. +- a4617c422a: Added `watch` option to configuration loaders that can be used to disable file watching by setting it to `false`. +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/core-components@0.13.6 + +### Patch Changes + +- 4eab5cf901: The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. +- 0b55f773a7: Removed some unused dependencies +- 8a15360bb4: Fixed overflowing messages in `WarningPanel`. +- 997a71850c: Changed SupportButton menuitems to support text wrap +- 0296f272b4: Fixed the type declaration of `DependencyGraphProps`, the `defs` prop now expects `JSX.Element`s. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 16126dbe6a: Change overlay header colors in the mobile menu to use navigation color from the theme +- d19a827ef1: MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/create-app@0.5.6 + +### Patch Changes + +- ba6a3b59c1: Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. + +- c8ec0dea4a: Create unique temp directory for each `create-app` execution. + +- e43d3eb1b7: Bumped create-app version. + +- b665f2ce65: Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. + + You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` + +- deed089a3d: Bump `cypress` to fix the end-to-end tests + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + +- 04a3f65e15: Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. + + You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` + +- 9864f263ba: Bump dev dependencies `lerna@7.3.0` on the template + +- 5eacd5d213: The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. + + The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. + + The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. + +- 8d2e640af4: Added missing `.eslintignore` file + + To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: + + ```diff + + playwright.config.ts + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.22 + +### Patch Changes + +- 080d1beb2a: Moving development `dependencies` to `devDependencies` +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 9468a67b92: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/app-defaults@1.4.4 + - @backstage/theme@0.4.3 + +## @backstage/errors@1.2.3 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/types@1.1.1 + +## @backstage/integration@1.7.1 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/integration-aws-node@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + +## @backstage/integration-react@1.1.20 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/config@1.1.1 + +## @backstage/repo-tools@0.3.5 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.1.5 + +## @backstage/test-utils@1.4.4 + +### Patch Changes + +- 322bbcae24: Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/theme@0.4.3 + +### Patch Changes + +- 5ad5344756: Added support for string `fontSize` values (e.g. `"2.5rem"`) in themes in addition to numbers. Also added an optional `fontFamily` prop for header typography variants to allow further customization. + +## @backstage/version-bridge@1.0.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. + +## @backstage/plugin-adr@0.6.8 + +### Patch Changes + +- 499e34656e: Fix icon alignment in `AdrSearchResultListItem` +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 1204e7628e: Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/theme@0.4.3 + - @backstage/plugin-adr-common@0.2.16 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-adr-backend@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-adr-common@0.2.16 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-adr-common@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-airbrake@0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/test-utils@1.4.4 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/dev-utils@1.0.22 + - @backstage/theme@0.4.3 + +## @backstage/plugin-airbrake-backend@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.41 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.34 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.3 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + +## @backstage/plugin-api-docs@0.9.12 + +### Patch Changes + +- 0117a6b47e: Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 18f1756908: added aria-label on api definition button for better a11y. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-api-docs-module-protoc-gen-doc@0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. + +## @backstage/plugin-apollo-explorer@0.1.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-app-backend@0.3.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config-loader@1.5.1 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.6 + +## @backstage/plugin-app-node@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-backend@0.19.3 + +### Patch Changes + +- 9ff7935152: Fixed bug in oidc refresh handler, if token endpoints response on refresh request does not contain a scope, the requested scope is used. +- 2d8f7e82c1: Migrated the Microsoft auth provider to new `@backstage/plugin-auth-backend-module-microsoft-provider` module package. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.3 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.3 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.3 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.3 + +### Patch Changes + +- 5d32a58b5a: Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-azure-devops@0.3.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-devops-backend@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-sites@0.1.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.49 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-badges-backend@0.3.3 + +### Patch Changes + +- 817f2acbb1: Make sure the default badge factory is used if nothing is defined +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + +## @backstage/plugin-bazaar@0.2.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + +## @backstage/plugin-bazaar-backend@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-bitbucket-cloud-common@0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + +## @backstage/plugin-bitrise@0.1.52 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-catalog-backend-module-azure@0.1.25 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-bitbucket-cloud-common@0.2.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.21 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-bitbucket-cloud-common@0.2.13 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.19 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.22 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-github@0.4.4 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- 0b55f773a7: Removed some unused dependencies +- 4f16e60e6d: Request slightly smaller pages of data from GitHub +- b4b1cbf9fa: Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` +- c101e683d5: Removed `catalogModuleGithubOrgEntityProvider`. Import from `@backstage/plugin-catalog-backend-module-github-org` instead. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.3 + +### Patch Changes + +- 4f70fdfc93: fix: use REST API to get root group memberships for GitLab SaaS users listing + + This API is the only one that shows `email` field for enterprise users and + allows to filter out bot users not using a license using the `is_using_seat` + field. + + We also added the annotation `gitlab.com/saml-external-uid` taking the value + of `group_saml_identity.extern_uid` of the `groups/:group-id/members` endpoint + response. This is useful in case you want to create a `SignInResolver` that + references the user with the id of your identity provider (e.g. OneLogin). + + ref: + + + + +- 890e3b5ad4: Make sure to include the error message when ingestion fails + +- 0b55f773a7: Removed some unused dependencies + +- 6ae7f12abb: Make sure the archived projects are skipped with the Gitlab API + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.10 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.21 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.13 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.11 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-catalog-common@1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-catalog-graph@0.2.37 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The `app.title` configuration is now properly required to be a string. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-node@1.4.7 + +### Patch Changes + +- 7a2e2924c7: Added docs to `processingResult` +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-catalog-react@1.8.5 + +### Patch Changes + +- a402e1dfb9: Fixed an issue causing `EntityPage` to show an error for entities containing special characters +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The `spec.type` field in entities will now always be rendered as a string. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-cicd-statistics@0.1.27 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-cicd-statistics@0.1.27 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-circleci@0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-cloudbuild@0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-code-climate@0.1.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-code-coverage@0.2.18 + +### Patch Changes + +- 88b0b32547: Fixed the coverage history statistics to compare newest with oldest record +- 0296f272b4: The warning for missing code coverage will now render the entity as a reference. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- a468544fa9: Updated layout to improve contrasts and consistency with other plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-code-coverage-backend@0.2.20 + +### Patch Changes + +- 4aa27aa200: Added option to set body size limit +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + +## @backstage/plugin-codescene@0.1.18 + +### Patch Changes + +- 9c9a9100b0: Internal refactor to avoid using the deprecated `.icon.svg` extension. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-config-schema@0.1.46 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- ba4820883c: Updated dependency `@types/pluralize` to `^0.0.31`. +- 959aa2a09f: The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.5 + +## @backstage/plugin-devtools-backend@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.5 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-devtools-common@0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-dynatrace@7.0.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-entity-feedback@0.2.8 + +### Patch Changes + +- 48c8b93e98: Added tooltip to like dislike buttons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/plugin-catalog-common@1.0.17 + +## @backstage/plugin-events-backend@0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-azure@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-gerrit@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-github@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-module-gitlab@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-backend-test-utils@0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.15 + +## @backstage/plugin-events-node@0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + +## @backstage/plugin-explore@0.4.11 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0f10c53a05: Create an experimental `ExploreSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-explore-react@0.0.32 + - @backstage/theme@0.4.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-explore-backend@0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-explore-react@0.0.32 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.9 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-fossa@0.2.57 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-gcalendar@0.3.19 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-gcp-projects@0.3.42 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-git-release-manager@0.3.38 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-github-actions@0.6.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-github-deployments@0.1.56 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-github-issues@0.2.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 7bd0a8ab3c: Filters out entities that belonged to a different github instance other than the one configured by the plugin +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-github-pull-requests-board@0.1.19 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-gitops-profiles@0.3.41 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-gocd@0.1.31 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-graphiql@0.2.55 + +### Patch Changes + +- 9c9a9100b0: Internal refactor to avoid using the deprecated `.icon.svg` extension. +- 06432f900c: Updated `/alpha` exports to use new `attachTo` option. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-graphql-voyager@0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-home@0.5.9 + +### Patch Changes + +- f997f771da: Adds Top/Recently Visited components to homepage +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-home-react@0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + +## @backstage/plugin-ilert@0.2.14 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9c9a9100b0: Internal refactor to avoid using the deprecated `.icon.svg` extension. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-jenkins-common@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-kafka@0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-kafka-backend@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-kubernetes-cluster@0.0.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-react@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-lighthouse@0.4.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-common@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + +## @backstage/plugin-linguist@0.1.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-newrelic@0.3.41 + +### Patch Changes + +- ce50a15506: Fixed sorting and searching in the NewRelic table. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-nomad@0.1.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-nomad-backend@0.1.8 + +### Patch Changes + +- 6822918c50: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-octopus-deploy@0.2.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-opencost@0.2.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 777b9a16a4: Fix for broken image reference. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-org@0.6.15 + +### Patch Changes + +- dc5b6b971b: Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. + This allows the already existing recursive method to work properly when children of entity have children themselves. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-org-react@0.1.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + +## @backstage/plugin-pagerduty@0.6.6 + +### Patch Changes + +- b9ce306814: Minor fix to avoid usage of deprecated prop +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + +## @backstage/plugin-periskop@0.1.23 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-periskop-backend@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-permission-common@0.7.9 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.7.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-permission-react@0.4.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-playlist@0.1.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 65498193e8: Updated Playlist read me with additional screenshots +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-playlist-common@0.1.11 + +## @backstage/plugin-playlist-backend@0.3.10 + +### Patch Changes + +- 9e46f5ff49: Added support to the playlist plugin for the new backend +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-playlist-common@0.1.11 + +## @backstage/plugin-playlist-common@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-proxy-backend@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-rollbar@0.4.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-rollbar-backend@0.1.51 + +### Patch Changes + +- 407f4284be: ensure rollbar token is hidden +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.15.1 + +### Patch Changes + +- b337d78c3b: fixed issue related template editor fails with multiple templates per file. +- ff2ab02690: Make entity picker more reliable with only one available entity +- 83e4a42ccd: Display log visibility button on the template panel +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 4c70fe497d: `RepoUrlPickerRepoName` now correctly handles value changes in allowed repos. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.23 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-scaffolder-node@0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.2 + +## @backstage/plugin-scaffolder-react@1.5.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.2 + +## @backstage/plugin-search@1.4.1 + +### Patch Changes + +- e5a2956dd2: Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: Minor internal code cleanup. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend@1.4.6 + +### Patch Changes + +- 16be6f9473: Set the default length limit to search query to 100. To override it, define `search.maxTermLength` in the config file. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-module-catalog@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.9 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-module-explore@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-module-pg@0.5.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-module-techdocs@0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-backend-node@1.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-search-common@1.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/plugin-search-react@1.7.1 + +### Patch Changes + +- 06432f900c: Updated `/alpha` exports to use new `attachTo` option. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The filter options passed to `SearchResultGroupLayout` are now always explicitly rendered as strings by default. +- 703a4ffc5b: Create `createSearchResultListItem` alpha version that only supports declarative integration. +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-sentry@0.5.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-shortcuts@0.3.15 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-sonarqube-react@0.1.9 + +## @backstage/plugin-sonarqube-backend@0.2.8 + +### Patch Changes + +- a5d592d0ad: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-sonarqube-react@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-stack-overflow@0.1.21 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-stack-overflow-backend@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + +## @backstage/plugin-stackstorm@0.1.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-tech-insights@0.3.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 21f409d776: Export `ScorecardInfo` and `ScorecardsList` components to be able to use manually queried check results directly. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.20 + +### Patch Changes + +- cc7dddfa7f: Increase the maximum allowed length of an entity filter for tech insights fact schemas. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/config@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.9 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- c09d2fa1d6: Added experimental support for the declarative integration. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.22 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog@1.14.0 + - @backstage/test-utils@1.4.4 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + +## @backstage/plugin-techdocs-react@1.1.12 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + +## @backstage/plugin-todo@0.2.28 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-todo-backend@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + +## @backstage/plugin-user-settings@0.7.11 + +### Patch Changes + +- 18c8dee6f5: Added experimental support for declarative integration via the `/alpha` subpath. +- d1b637d005: Fixed a bug where the theme icons would not be colored according to their active state. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.20 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## @backstage/plugin-vault-backend@0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-xcmetrics@0.2.44 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + +## example-app@0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/plugin-pagerduty@0.6.6 + - @backstage/plugin-org@0.6.15 + - @backstage/plugin-code-coverage@0.2.18 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-home@0.5.9 + - @backstage/plugin-newrelic@0.3.41 + - @backstage/plugin-user-settings@0.7.11 + - @backstage/plugin-scaffolder@1.15.1 + - @backstage/core-components@0.13.6 + - @backstage/plugin-entity-feedback@0.2.8 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-tech-radar@0.6.9 + - @backstage/plugin-adr@0.6.8 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/plugin-search@1.4.1 + - @backstage/plugin-jenkins@0.9.0 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-api-docs@0.9.12 + - @backstage/plugin-kubernetes@0.11.0 + - @backstage/plugin-airbrake@0.3.25 + - @backstage/plugin-apache-airflow@0.2.16 + - @backstage/plugin-azure-devops@0.3.7 + - @backstage/plugin-azure-sites@0.1.14 + - @backstage/plugin-badges@0.2.49 + - @backstage/plugin-catalog-graph@0.2.37 + - @backstage/plugin-catalog-import@0.10.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4 + - @backstage/plugin-circleci@0.3.25 + - @backstage/plugin-cloudbuild@0.3.25 + - @backstage/plugin-cost-insights@0.12.14 + - @backstage/plugin-devtools@0.1.5 + - @backstage/plugin-dynatrace@7.0.5 + - @backstage/plugin-explore@0.4.11 + - @backstage/plugin-gcalendar@0.3.19 + - @backstage/plugin-gcp-projects@0.3.42 + - @backstage/plugin-github-actions@0.6.6 + - @backstage/plugin-gocd@0.1.31 + - @backstage/plugin-kafka@0.3.25 + - @backstage/plugin-kubernetes-cluster@0.0.1 + - @backstage/plugin-lighthouse@0.4.10 + - @backstage/plugin-linguist@0.1.10 + - @backstage/plugin-microsoft-calendar@0.1.8 + - @backstage/plugin-newrelic-dashboard@0.3.0 + - @backstage/plugin-nomad@0.1.6 + - @backstage/plugin-octopus-deploy@0.2.7 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-playlist@0.1.17 + - @backstage/plugin-puppetdb@0.1.8 + - @backstage/plugin-rollbar@0.4.25 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/plugin-sentry@0.5.10 + - @backstage/plugin-shortcuts@0.3.15 + - @backstage/plugin-stack-overflow@0.1.21 + - @backstage/plugin-stackstorm@0.1.7 + - @backstage/plugin-tech-insights@0.3.17 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/plugin-todo@0.2.28 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.7 + +## example-app-next@0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/plugin-pagerduty@0.6.6 + - @backstage/plugin-org@0.6.15 + - @backstage/plugin-code-coverage@0.2.18 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-home@0.5.9 + - @backstage/plugin-newrelic@0.3.41 + - @backstage/plugin-user-settings@0.7.11 + - @backstage/plugin-scaffolder@1.15.1 + - @backstage/core-components@0.13.6 + - @backstage/plugin-entity-feedback@0.2.8 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-tech-radar@0.6.9 + - @backstage/plugin-adr@0.6.8 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/plugin-search@1.4.1 + - @backstage/plugin-jenkins@0.9.0 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-api-docs@0.9.12 + - @backstage/plugin-kubernetes@0.11.0 + - @backstage/plugin-airbrake@0.3.25 + - @backstage/plugin-apache-airflow@0.2.16 + - @backstage/plugin-azure-devops@0.3.7 + - @backstage/plugin-azure-sites@0.1.14 + - @backstage/plugin-badges@0.2.49 + - @backstage/plugin-catalog-graph@0.2.37 + - @backstage/plugin-catalog-import@0.10.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4 + - @backstage/plugin-circleci@0.3.25 + - @backstage/plugin-cloudbuild@0.3.25 + - @backstage/plugin-cost-insights@0.12.14 + - @backstage/plugin-devtools@0.1.5 + - @backstage/plugin-dynatrace@7.0.5 + - @backstage/plugin-explore@0.4.11 + - @backstage/plugin-gcalendar@0.3.19 + - @backstage/plugin-gcp-projects@0.3.42 + - @backstage/plugin-github-actions@0.6.6 + - @backstage/plugin-gocd@0.1.31 + - @backstage/plugin-kafka@0.3.25 + - @backstage/plugin-lighthouse@0.4.10 + - @backstage/plugin-linguist@0.1.10 + - @backstage/plugin-microsoft-calendar@0.1.8 + - @backstage/plugin-newrelic-dashboard@0.3.0 + - @backstage/plugin-octopus-deploy@0.2.7 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-playlist@0.1.17 + - @backstage/plugin-puppetdb@0.1.8 + - @backstage/plugin-rollbar@0.4.25 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/plugin-sentry@0.5.10 + - @backstage/plugin-shortcuts@0.3.15 + - @backstage/plugin-stack-overflow@0.1.21 + - @backstage/plugin-stackstorm@0.1.7 + - @backstage/plugin-tech-insights@0.3.17 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/plugin-todo@0.2.28 + - @backstage/theme@0.4.3 + - app-next-example-plugin@0.0.2 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.7 + +## app-next-example-plugin@0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-components@0.13.6 + +## example-backend@0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8 + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-scaffolder-backend@1.18.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.9 + - @backstage/integration@1.7.1 + - @backstage/plugin-playlist-backend@0.3.10 + - @backstage/plugin-techdocs-backend@1.8.0 + - @backstage/plugin-auth-backend@0.19.3 + - @backstage/plugin-rollbar-backend@0.1.51 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/plugin-graphql-backend@0.2.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-badges-backend@0.3.3 + - @backstage/plugin-tech-insights-backend@0.5.20 + - @backstage/plugin-kubernetes-backend@0.13.0 + - @backstage/plugin-jenkins-backend@0.3.0 + - @backstage/plugin-code-coverage-backend@0.2.20 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.23 + - @backstage/plugin-search-backend@1.4.6 + - example-app@0.2.88 + - @backstage/plugin-lighthouse-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/plugin-adr-backend@0.4.3 + - @backstage/plugin-app-backend@0.3.54 + - @backstage/plugin-azure-devops-backend@0.4.3 + - @backstage/plugin-azure-sites-backend@0.1.16 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-devtools-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.2.3 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-explore-backend@0.0.16 + - @backstage/plugin-kafka-backend@0.3.3 + - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-proxy-backend@0.4.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7 + - @backstage/plugin-search-backend-module-pg@0.5.15 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38 + - @backstage/plugin-todo-backend@0.3.4 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## example-backend-next@0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8 + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-sonarqube-backend@0.2.8 + - @backstage/plugin-scaffolder-backend@1.18.0 + - @backstage/plugin-playlist-backend@0.3.10 + - @backstage/plugin-techdocs-backend@1.8.0 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/plugin-badges-backend@0.3.3 + - @backstage/plugin-kubernetes-backend@0.13.0 + - @backstage/plugin-jenkins-backend@0.3.0 + - @backstage/plugin-search-backend@1.4.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-lighthouse-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/backend-defaults@0.2.6 + - @backstage/plugin-adr-backend@0.4.3 + - @backstage/plugin-app-backend@0.3.54 + - @backstage/plugin-azure-devops-backend@0.4.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-devtools-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.2.3 + - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-proxy-backend@0.4.3 + - @backstage/plugin-todo-backend@0.3.4 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + - @backstage/plugin-permission-common@0.7.9 + +## @backstage/backend-plugin-manager@0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + +## e2e-test@0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + +## techdocs-cli-embedded-app@0.2.87 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/test-utils@1.4.4 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + +## @internal/plugin-todo-list@1.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + +## @internal/plugin-todo-list-backend@1.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + +## @internal/plugin-todo-list-common@1.0.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.9 diff --git a/docs/releases/v1.19.0.md b/docs/releases/v1.19.0.md new file mode 100644 index 0000000000..49a31f32b6 --- /dev/null +++ b/docs/releases/v1.19.0.md @@ -0,0 +1,86 @@ +--- +id: v1.19.0 +title: v1.19.0 +description: Backstage Release v1.19.0 +--- + +These are the release notes for the v1.19.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.js v18 + v20 + +The supported versions of Node.js are now v18 and v20. Be sure to update the `engine` field in your root `package.json` accordingly and update your Dockerfile base images, for example to `node:18-bookworm-slim`. + +### New default `start` command for backends + +Backend packages now use the new `package start` implementation by default. This new version uses module loaders rather than a Webpack build for transpilation. The largest difference from the old version is that the backend process is now restarted on change, rather than using Webpack hot module reloads. When using SQLite the database state is serialized and stored in the parent process across restart, which requires a [migration to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). If you have yet to migrate to the new system it is recommended that you set the `LEGACY_BACKEND_START` environment variable when starting the backend to keep the old behavior. + +### **BREAKING**: Allow passing undefined `labelSelector` to `KubernetesFetcher` + +`KubernetesFetch` no longer auto-adds `labelSelector` when an empty string is passed. +This is only applicable if you have a custom ObjectProvider implementation, as build-in `KubernetesFanOutHandler` already does this. + +Contributed by [@szubster](https://github.com/szubster) in [#20541](https://github.com/backstage/backstage/pull/20541) + +### **DEPRECATION**: Catalog GraphQL Backend Package + +This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. + +### **DEPRECATION**: `.icon.svg` Extension Support + +Support for the `.icon.svg` extension has been deprecated and will be removed in a future release. Please migrate existing usage to either inline the SVG elements in a `` component from MUI, or switch to a regular `.svg` asset import. + +### Insightful Homepage + +You can now create an Insightful homepage to show your users their recent and top visited activity in Backstage. Add [this](https://github.com/backstage/backstage/tree/master/plugins/home#page-visit-homepage-component-homepagetopvisited--homepagerecentlyvisited) plugin to track your users’ recent navigation history in your Backstage database and display it in the Backstage Homepage using the customizable Recent and Top visits components (`` and ``)and the extensible Visits API interface. This feature is released with an example that extends the Visits API with LocalStorage as an alternative storage solution for user visit activity. + +### New plugin: Kubernetes Clusters + +This plugin lets you view Kubernetes clusters as an admin. + +### New feature: New Pinniped Auth Provider Module + +This module provides a Pinniped auth provider implementation for the auth backend. + +Contributed by [@RubenV-dev](https://github.com/RubenV-dev) in [#19846](https://github.com/backstage/backstage/pull/19846) + +## More Movement Toward the New Backend System + +Since the last release, a lot of contributions have been made toward migrating features to support [the new backend system](https://backstage.io/docs/backend-system/). + +The following backend plugins were migrated: + +- jenkins +- nomad +- sonarqube +- playlist + +The Kubernetes backend broadened its backend system feature set, with a new extension point. For the catalog backend, some new modules were added, including GitHub org and Microsoft/Azure. + +If you would like to help out with these efforts, check out [this issue](https://github.com/backstage/backstage/issues/18301)! + +## Security Fixes + +Some improvements were made in the configuration schemas, ensuring that no secret fields could be read outside of a backend context. + +The `lerna` package in newly scaffolded Backstage repositories is now of version >7 which has 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/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.19.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://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/releases/v1.9.0-changelog.md b/docs/releases/v1.9.0-changelog.md index df14c3d34d..07451f6d2c 100644 --- a/docs/releases/v1.9.0-changelog.md +++ b/docs/releases/v1.9.0-changelog.md @@ -1299,7 +1299,7 @@ - d3fea4ae0a: Internal fixes to avoid implicit usage of globals - 3280711113: Updated dependency `msw` to `^0.49.0`. - 9516b0c355: Added support for sending virtual pageviews on `search` events in order to enable - Site Search functionality in GA. For more information consult [README](/plugins/analytics-module-ga/README.md#enabling-site-search) + Site Search functionality in GA. For more information consult [README](https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md#enabling-site-search) - Updated dependencies - @backstage/core-plugin-api@1.2.0 - @backstage/core-components@0.12.1 diff --git a/docs/releases/v1.9.0-next.2-changelog.md b/docs/releases/v1.9.0-next.2-changelog.md index a410da5263..2c6d495641 100644 --- a/docs/releases/v1.9.0-next.2-changelog.md +++ b/docs/releases/v1.9.0-next.2-changelog.md @@ -525,7 +525,7 @@ ### Patch Changes - 9516b0c355: Added support for sending virtual pageviews on `search` events in order to enable - Site Search functionality in GA. For more information consult [README](/plugins/analytics-module-ga/README.md#enabling-site-search) + Site Search functionality in GA. For more information consult [README](https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md#enabling-site-search) - Updated dependencies - @backstage/core-plugin-api@1.2.0-next.2 - @backstage/core-components@0.12.1-next.2 diff --git a/microsite/data/plugins/tips.yaml b/microsite/data/plugins/tips.yaml new file mode 100644 index 0000000000..e58ad0fb46 --- /dev/null +++ b/microsite/data/plugins/tips.yaml @@ -0,0 +1,10 @@ +--- +title: Tips +author: dweber019 +authorUrl: https://github.com/dweber019 +category: Discovery +description: The tips plugin will show the end user some helpful information for entities. +documentation: https://github.com/dweber019/backstage-plugin-tips +iconUrl: https://raw.githubusercontent.com/dweber019/backstage-plugin-tips/main/plugins/tips/docs/pluginIcon.png +npmPackageName: '@dweber019/backstage-plugin-tips' +addedDate: '2023-10-08' diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js index 83a5d3ac3d..f4dd76b8e3 100644 --- a/microsite/docusaurus.config.js +++ b/microsite/docusaurus.config.js @@ -178,7 +178,7 @@ module.exports = { position: 'left', }, { - to: 'docs/releases/v1.18.0', + to: 'docs/releases/v1.19.0', label: 'Releases', position: 'left', }, diff --git a/microsite/sidebars.json b/microsite/sidebars.json index bc394982ca..8d8cb39eaa 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.19.0", "releases/v1.18.0", "releases/v1.17.0", "releases/v1.16.0", diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 835727014c..8147655315 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -1614,8 +1614,8 @@ __metadata: linkType: hard "@babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/traverse@npm:7.23.0" + version: 7.23.2 + resolution: "@babel/traverse@npm:7.23.2" dependencies: "@babel/code-frame": ^7.22.13 "@babel/generator": ^7.23.0 @@ -1627,7 +1627,7 @@ __metadata: "@babel/types": ^7.23.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: 0b17fae53269e1af2cd3edba00892bc2975ad5df9eea7b84815dab07dfec2928c451066d51bc65b4be61d8499e77db7e547ce69ef2a7b0eca3f96269cb43a0b0 + checksum: 26a1eea0dde41ab99dde8b9773a013a0dc50324e5110a049f5d634e721ff08afffd54940b3974a20308d7952085ac769689369e9127dea655f868c0f6e1ab35d languageName: node linkType: hard diff --git a/package.json b/package.json index b50e087aa7..6a21034cae 100644 --- a/package.json +++ b/package.json @@ -47,12 +47,14 @@ ] }, "resolutions": { - "@types/react": "^17", - "@types/react-dom": "^17", + "@types/react": "^18", + "@types/react-dom": "^18", "jest-haste-map@^29.4.3": "patch:jest-haste-map@npm%3A29.4.3#./.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch", - "mock-fs@^5.2.0": "patch:mock-fs@npm%3A5.2.0#./.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch" + "mock-fs@^5.2.0": "patch:mock-fs@npm%3A5.2.0#./.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch", + "@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", + "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch" }, - "version": "1.19.0-next.2", + "version": "1.19.0", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3" diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index ce6bdb23fa..d212580484 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/app-defaults +## 1.4.4 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + ## 1.4.4-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 7695d128e7..9ab12f7cc5 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.4.4-next.2", + "version": "1.4.4", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -42,15 +42,15 @@ "@material-ui/icons": "^4.9.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@types/react": "^16.13.1 || ^17.0.0" }, "files": [ diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index 10874da64a..3402944211 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,13 @@ # app-next-example-plugin +## 0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-components@0.13.6 + ## 0.0.2-next.2 ### Patch Changes diff --git a/packages/app-next-example-plugin/api-report.md b/packages/app-next-example-plugin/api-report.md index 83449a102f..c89a7b599b 100644 --- a/packages/app-next-example-plugin/api-report.md +++ b/packages/app-next-example-plugin/api-report.md @@ -3,13 +3,11 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { default as React_2 } from 'react'; // @public (undocumented) -const examplePlugin: BackstagePlugin; +const examplePlugin: BackstagePlugin<{}, {}>; export default examplePlugin; // @public (undocumented) diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 6304dcd028..865c6e0800 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,7 +1,7 @@ { "name": "app-next-example-plugin", "description": "Backstage internal example plugin", - "version": "0.0.2-next.2", + "version": "0.0.2", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -39,8 +39,8 @@ "@material-ui/icons": "^4.9.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 3195255f36..0a80d6d902 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,82 @@ # example-app-next +## 0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/plugin-pagerduty@0.6.6 + - @backstage/plugin-org@0.6.15 + - @backstage/plugin-code-coverage@0.2.18 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-home@0.5.9 + - @backstage/plugin-newrelic@0.3.41 + - @backstage/plugin-user-settings@0.7.11 + - @backstage/plugin-scaffolder@1.15.1 + - @backstage/core-components@0.13.6 + - @backstage/plugin-entity-feedback@0.2.8 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-tech-radar@0.6.9 + - @backstage/plugin-adr@0.6.8 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/plugin-search@1.4.1 + - @backstage/plugin-jenkins@0.9.0 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-api-docs@0.9.12 + - @backstage/plugin-kubernetes@0.11.0 + - @backstage/plugin-airbrake@0.3.25 + - @backstage/plugin-apache-airflow@0.2.16 + - @backstage/plugin-azure-devops@0.3.7 + - @backstage/plugin-azure-sites@0.1.14 + - @backstage/plugin-badges@0.2.49 + - @backstage/plugin-catalog-graph@0.2.37 + - @backstage/plugin-catalog-import@0.10.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4 + - @backstage/plugin-circleci@0.3.25 + - @backstage/plugin-cloudbuild@0.3.25 + - @backstage/plugin-cost-insights@0.12.14 + - @backstage/plugin-devtools@0.1.5 + - @backstage/plugin-dynatrace@7.0.5 + - @backstage/plugin-explore@0.4.11 + - @backstage/plugin-gcalendar@0.3.19 + - @backstage/plugin-gcp-projects@0.3.42 + - @backstage/plugin-github-actions@0.6.6 + - @backstage/plugin-gocd@0.1.31 + - @backstage/plugin-kafka@0.3.25 + - @backstage/plugin-lighthouse@0.4.10 + - @backstage/plugin-linguist@0.1.10 + - @backstage/plugin-microsoft-calendar@0.1.8 + - @backstage/plugin-newrelic-dashboard@0.3.0 + - @backstage/plugin-octopus-deploy@0.2.7 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-playlist@0.1.17 + - @backstage/plugin-puppetdb@0.1.8 + - @backstage/plugin-rollbar@0.4.25 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/plugin-sentry@0.5.10 + - @backstage/plugin-shortcuts@0.3.15 + - @backstage/plugin-stack-overflow@0.1.21 + - @backstage/plugin-stackstorm@0.1.7 + - @backstage/plugin-tech-insights@0.3.17 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/plugin-todo@0.2.28 + - @backstage/theme@0.4.3 + - app-next-example-plugin@0.0.2 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.7 + ## 0.0.2-next.2 ### Patch Changes diff --git a/packages/app-next/app-config.yaml b/packages/app-next/app-config.yaml index a97c52f40f..0c75e1c96c 100644 --- a/packages/app-next/app-config.yaml +++ b/packages/app-next/app-config.yaml @@ -1,10 +1,20 @@ app: experimental: packages: 'all' # ✨ + routes: + bindings: + plugin.pages.externalRoutes.pageX: plugin.pages.routes.pageX + plugin.catalog.externalRoutes.viewTechDoc: plugin.techdocs.routes.docRoot extensions: - apis.plugin.graphiql.browse.gitlab: true + # Entity page cards + - 'entity.cards.about' + + # Entity page content + - 'entity.content.techdocs' + # scmAuthExtension: >- # createScmAuthExtension({ # id: 'apis.scmAuth.addons.ghe', diff --git a/packages/app-next/package.json b/packages/app-next/package.json index b1d158fb9f..5437c66272 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.2-next.2", + "version": "0.0.2", "private": true, "backstage": { "role": "frontend" @@ -12,6 +12,7 @@ "@backstage/cli": "workspace:^", "@backstage/config": "workspace:^", "@backstage/core-app-api": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-app-api": "workspace:^", @@ -67,7 +68,6 @@ "@backstage/plugin-search-react": "workspace:^", "@backstage/plugin-sentry": "workspace:^", "@backstage/plugin-shortcuts": "workspace:^", - "@backstage/plugin-stack-overflow": "workspace:^", "@backstage/plugin-stackstorm": "workspace:^", "@backstage/plugin-tech-insights": "workspace:^", "@backstage/plugin-tech-radar": "workspace:^", @@ -89,8 +89,8 @@ "app-next-example-plugin": "workspace:^", "history": "^5.0.0", "lodash": "^4.17.21", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-use": "^17.2.4", @@ -100,7 +100,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/jquery": "^3.3.34", "@types/react": "*", diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 4d72cca14f..1275722da4 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -20,12 +20,28 @@ import { pagesPlugin } from './examples/pagesPlugin'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; +import homePlugin, { + titleExtensionDataRef, +} from '@backstage/plugin-home/alpha'; + import { + coreExtensionData, + createExtension, + createApiExtension, createExtensionOverrides, - createPageExtension, } from '@backstage/frontend-plugin-api'; -import { entityRouteRef } from '@backstage/plugin-catalog-react'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; +import { homePage } from './HomePage'; +import { collectLegacyRoutes } from '@backstage/core-compat-api'; +import { FlatRoutes } from '@backstage/core-app-api'; +import { Route } from 'react-router'; +import { CatalogImportPage } from '@backstage/plugin-catalog-import'; +import { createApiFactory, configApiRef } from '@backstage/core-plugin-api'; +import { + ScmAuth, + ScmIntegrationsApi, + scmIntegrationsApiRef, +} from '@backstage/integration-react'; /* @@ -56,13 +72,36 @@ TODO: /* app.tsx */ -const entityPageExtension = createPageExtension({ - id: 'catalog:entity', - defaultPath: '/catalog/:namespace/:kind/:name', - routeRef: entityRouteRef, - loader: async () =>

Just a temporary mocked entity page
, +const homePageExtension = createExtension({ + id: 'myhomepage', + attachTo: { id: 'home', input: 'props' }, + output: { + children: coreExtensionData.reactElement, + title: titleExtensionDataRef, + }, + factory({ bind }) { + bind({ children: homePage, title: 'just a title' }); + }, }); +const scmAuthExtension = createApiExtension({ + factory: ScmAuth.createDefaultApiFactory(), +}); + +const scmIntegrationApi = createApiExtension({ + factory: createApiFactory({ + api: scmIntegrationsApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), + }), +}); + +const collectedLegacyPlugins = collectLegacyRoutes( + + } /> + , +); + const app = createApp({ features: [ graphiqlPlugin, @@ -70,13 +109,16 @@ const app = createApp({ techRadarPlugin, techdocsPlugin, userSettingsPlugin, + homePlugin, + ...collectedLegacyPlugins, createExtensionOverrides({ - extensions: [entityPageExtension], + extensions: [homePageExtension, scmAuthExtension, scmIntegrationApi], }), ], - bindRoutes({ bind }) { - bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX }); - }, + /* Handled through config instead */ + // bindRoutes({ bind }) { + // bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX }); + // }, }); // const legacyApp = createLegacyApp({ plugins: [legacyGraphiqlPlugin] }); diff --git a/packages/app-next/src/HomePage.tsx b/packages/app-next/src/HomePage.tsx new file mode 100644 index 0000000000..cb31beb34a --- /dev/null +++ b/packages/app-next/src/HomePage.tsx @@ -0,0 +1,119 @@ +/* + * 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 { + ClockConfig, + CustomHomepageGrid, + HeaderWorldClock, + HomePageCompanyLogo, + HomePageRandomJoke, + HomePageStarredEntities, + HomePageToolkit, + HomePageTopVisited, + HomePageRecentlyVisited, + WelcomeTitle, +} from '@backstage/plugin-home'; +import { Content, Header, Page } from '@backstage/core-components'; +import { HomePageCalendar } from '@backstage/plugin-gcalendar'; +import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar'; +import React from 'react'; +import HomeIcon from '@material-ui/icons/Home'; +import { HomePagePagerDutyCard } from '@backstage/plugin-pagerduty'; + +const clockConfigs: ClockConfig[] = [ + { + label: 'NYC', + timeZone: 'America/New_York', + }, + { + label: 'UTC', + timeZone: 'UTC', + }, + { + label: 'STO', + timeZone: 'Europe/Stockholm', + }, + { + label: 'TYO', + timeZone: 'Asia/Tokyo', + }, +]; + +const timeFormat: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + hour12: false, +}; + +const defaultConfig = [ + { + component: 'CompanyLogo', + x: 0, + y: 0, + width: 12, + height: 1, + movable: false, + resizable: false, + deletable: false, + }, + { + component: 'WelcomeTitle', + x: 0, + y: 1, + width: 12, + height: 1, + }, + { + component: 'HomePageSearchBar', + x: 0, + y: 2, + width: 12, + height: 2, + }, +]; + +export const homePage = ( + +
} pageTitleOverride="Home"> + +
+ + + + + + + + + + , + }, + ]} + /> + + + + +
+); diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index ef6b55ff4c..1e9409a5e4 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -19,18 +19,16 @@ import { Link } from '@backstage/core-components'; import { createPageExtension, createPlugin, -} from '@backstage/frontend-plugin-api'; -import { - useRouteRef, createRouteRef, createExternalRouteRef, -} from '@backstage/core-plugin-api'; + useRouteRef, +} from '@backstage/frontend-plugin-api'; import { Route, Routes } from 'react-router-dom'; -const indexRouteRef = createRouteRef({ id: 'index' }); -const page1RouteRef = createRouteRef({ id: 'page1' }); -export const externalPageXRouteRef = createExternalRouteRef({ id: 'pageX' }); -export const pageXRouteRef = createRouteRef({ id: 'pageX' }); +const indexRouteRef = createRouteRef(); +const page1RouteRef = createRouteRef(); +export const externalPageXRouteRef = createExternalRouteRef(); +export const pageXRouteRef = createRouteRef(); // const page2RouteRef = createSubRouteRef({ // id: 'page2', // parent: page1RouteRef, @@ -50,6 +48,9 @@ const IndexPage = createPageExtension({
Page 1
+
+ Home +
GraphiQL
diff --git a/packages/app-next/src/index.tsx b/packages/app-next/src/index.tsx index 3c354b06d0..37a2574484 100644 --- a/packages/app-next/src/index.tsx +++ b/packages/app-next/src/index.tsx @@ -15,7 +15,7 @@ */ import '@backstage/cli/asset-types'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import app from './App'; -ReactDOM.render(app, document.getElementById('root')); +ReactDOM.createRoot(document.getElementById('root')!).render(app); diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index dc7635f51a..f339cf74da 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,82 @@ # example-app +## 0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/plugin-pagerduty@0.6.6 + - @backstage/plugin-org@0.6.15 + - @backstage/plugin-code-coverage@0.2.18 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-home@0.5.9 + - @backstage/plugin-newrelic@0.3.41 + - @backstage/plugin-user-settings@0.7.11 + - @backstage/plugin-scaffolder@1.15.1 + - @backstage/core-components@0.13.6 + - @backstage/plugin-entity-feedback@0.2.8 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-tech-radar@0.6.9 + - @backstage/plugin-adr@0.6.8 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/plugin-search@1.4.1 + - @backstage/plugin-jenkins@0.9.0 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-api-docs@0.9.12 + - @backstage/plugin-kubernetes@0.11.0 + - @backstage/plugin-airbrake@0.3.25 + - @backstage/plugin-apache-airflow@0.2.16 + - @backstage/plugin-azure-devops@0.3.7 + - @backstage/plugin-azure-sites@0.1.14 + - @backstage/plugin-badges@0.2.49 + - @backstage/plugin-catalog-graph@0.2.37 + - @backstage/plugin-catalog-import@0.10.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4 + - @backstage/plugin-circleci@0.3.25 + - @backstage/plugin-cloudbuild@0.3.25 + - @backstage/plugin-cost-insights@0.12.14 + - @backstage/plugin-devtools@0.1.5 + - @backstage/plugin-dynatrace@7.0.5 + - @backstage/plugin-explore@0.4.11 + - @backstage/plugin-gcalendar@0.3.19 + - @backstage/plugin-gcp-projects@0.3.42 + - @backstage/plugin-github-actions@0.6.6 + - @backstage/plugin-gocd@0.1.31 + - @backstage/plugin-kafka@0.3.25 + - @backstage/plugin-kubernetes-cluster@0.0.1 + - @backstage/plugin-lighthouse@0.4.10 + - @backstage/plugin-linguist@0.1.10 + - @backstage/plugin-microsoft-calendar@0.1.8 + - @backstage/plugin-newrelic-dashboard@0.3.0 + - @backstage/plugin-nomad@0.1.6 + - @backstage/plugin-octopus-deploy@0.2.7 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-playlist@0.1.17 + - @backstage/plugin-puppetdb@0.1.8 + - @backstage/plugin-rollbar@0.4.25 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/plugin-sentry@0.5.10 + - @backstage/plugin-shortcuts@0.3.15 + - @backstage/plugin-stack-overflow@0.1.21 + - @backstage/plugin-stackstorm@0.1.7 + - @backstage/plugin-tech-insights@0.3.17 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/plugin-todo@0.2.28 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.7 + ## 0.2.88-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index ce344d1aa9..9c6b578cd8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.88-next.2", + "version": "0.2.88", "private": true, "backstage": { "role": "frontend" @@ -93,12 +93,16 @@ "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", "@roadiehq/backstage-plugin-travis-ci": "^2.0.5", + "@vitejs/plugin-react": "^4.0.4", "history": "^5.0.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-use": "^17.2.4", + "vite": "^4.4.9", + "vite-plugin-html": "^3.2.0", + "vite-plugin-node-polyfills": "^0.14.1", "zen-observable": "^0.10.0" }, "devDependencies": { @@ -106,7 +110,7 @@ "@playwright/test": "^1.32.3", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/jquery": "^3.3.34", "@types/react": "*", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index f2b7d66b21..cc3787a8bc 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -64,7 +64,7 @@ import { GcpProjectsPage } from '@backstage/plugin-gcp-projects'; import { HomepageCompositionRoot, VisitListener } from '@backstage/plugin-home'; import { LighthousePage } from '@backstage/plugin-lighthouse'; import { NewRelicPage } from '@backstage/plugin-newrelic'; -import { NextScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; +import { LegacyScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder'; import { ScaffolderFieldExtensions, @@ -236,11 +236,11 @@ const routes = ( - + - + - + - + diff --git a/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx b/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx index b15d12979a..e236e01d79 100644 --- a/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx +++ b/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx @@ -17,10 +17,6 @@ import React from 'react'; import type { FieldValidation } from '@rjsf/utils'; import { scaffolderPlugin } from '@backstage/plugin-scaffolder'; import { TextField } from '@material-ui/core'; -import { - NextFieldExtensionComponentProps, - createNextScaffolderFieldExtension, -} from '@backstage/plugin-scaffolder-react/alpha'; import { createScaffolderFieldExtension, FieldExtensionComponentProps, @@ -67,7 +63,7 @@ export const LowerCaseValuePickerFieldExtension = scaffolderPlugin.provide( ); const MockDelayComponent = ( - props: NextFieldExtensionComponentProps<{ test?: string }>, + props: FieldExtensionComponentProps<{ test?: string }>, ) => { const { onChange, formData, rawErrors = [] } = props; return ( @@ -83,7 +79,7 @@ const MockDelayComponent = ( }; export const DelayingComponentFieldExtension = scaffolderPlugin.provide( - createNextScaffolderFieldExtension({ + createScaffolderFieldExtension({ name: 'DelayingComponent', component: MockDelayComponent, validation: async ( diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index b15bc4c102..e5ca03fe64 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -16,7 +16,7 @@ import '@backstage/cli/asset-types'; import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import App from './App'; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index dc81b18678..efc72cefc8 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/backend-app-api +## 0.5.6 + +### Patch Changes + +- 74491c9602: Moved `HostDiscovery` from `@backstage/backend-common`. +- a4617c422a: Added `watch` option to configuration loaders that can be used to disable file watching by setting it to `false`. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.5.6-next.2 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index c83a4acfd7..48a3b7a05b 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.5.6-next.2", + "version": "0.5.6", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts index 2b916908de..d523481cf7 100644 --- a/packages/backend-app-api/src/wiring/BackstageBackend.ts +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -57,7 +57,26 @@ function isPromise(value: unknown | Promise): value is Promise { } function unwrapFeature( - feature: BackendFeature | (() => BackendFeature), + feature: + | BackendFeature + | (() => BackendFeature) + | { default: BackendFeature | (() => BackendFeature) }, ): BackendFeature { - return typeof feature === 'function' ? feature() : feature; + if (typeof feature === 'function') { + return feature(); + } + if ('$$type' in feature) { + return feature; + } + // This is a workaround where default exports get transpiled to `exports['default'] = ...` + // in CommonJS modules, which in turn results in a double `{ default: { default: ... } }` nesting + // when importing using a dynamic import. + // TODO: This is a broader issue than just this piece of code, and should move away from CommonJS. + if ('default' in feature) { + const defaultFeature = feature.default; + return typeof defaultFeature === 'function' + ? defaultFeature() + : defaultFeature; + } + return feature; } diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 5a84733f86..50216d5139 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/backend-common +## 0.19.8 + +### Patch Changes + +- 74491c9602: The `HostDiscovery` export has been deprecated, import it from `@backstage/backend-app-api` instead. +- b95d66d4ea: Properly close write stream when writing temporary archive for processing zip-based `.readTree()` responses. +- b94f32271e: Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository +- 0b55f773a7: Removed some unused dependencies +- 4c39e38f1e: Added `/testUtils` entry point, with a utility for mocking resolve package paths as returned by `resolvePackagePath`. +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- a250ad775f: Removed `mock-fs` dev dependency. +- 2a40cd46a8: Adds the optional flag for useRedisSets for the Redis cache to the config. +- 1c3d6fa2b2: The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/backend-dev-utils@0.1.2 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + ## 0.19.8-next.2 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 9ca46d9473..11facfa7ce 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.19.8-next.2", + "version": "0.19.8", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index c4e9ef1026..6c9089fd06 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-defaults +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + ## 0.2.6-next.2 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 9b901f0e74..c843bbc412 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.6-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-dev-utils/CHANGELOG.md b/packages/backend-dev-utils/CHANGELOG.md index 3710cf3bd5..f1d1887b78 100644 --- a/packages/backend-dev-utils/CHANGELOG.md +++ b/packages/backend-dev-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/backend-dev-utils +## 0.1.2 + +### Patch Changes + +- afa48341fb: Fix an issue where early IPC responses would be lost. + ## 0.1.2-next.0 ### Patch Changes diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json index 8d461b46cf..b6156e622c 100644 --- a/packages/backend-dev-utils/package.json +++ b/packages/backend-dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dev-utils", - "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/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index b09af35602..171d82887c 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,44 @@ # example-backend-next +## 0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8 + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-sonarqube-backend@0.2.8 + - @backstage/plugin-scaffolder-backend@1.18.0 + - @backstage/plugin-playlist-backend@0.3.10 + - @backstage/plugin-techdocs-backend@1.8.0 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/plugin-badges-backend@0.3.3 + - @backstage/plugin-kubernetes-backend@0.13.0 + - @backstage/plugin-jenkins-backend@0.3.0 + - @backstage/plugin-search-backend@1.4.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-lighthouse-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/backend-defaults@0.2.6 + - @backstage/plugin-adr-backend@0.4.3 + - @backstage/plugin-app-backend@0.3.54 + - @backstage/plugin-azure-devops-backend@0.4.3 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-devtools-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.2.3 + - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.3 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-proxy-backend@0.4.3 + - @backstage/plugin-todo-backend@0.3.4 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + - @backstage/plugin-permission-common@0.7.9 + ## 0.0.16-next.2 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index f057b87523..69aa81a9cb 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.16-next.2", + "version": "0.0.16", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 9061bfe90b..097b0aa089 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-openapi-utils +## 0.0.5 + +### Patch Changes + +- 7c83975531: Adds new public utility types for common OpenAPI values, like request and response shapes and parameters available on an endpoint. + + **deprecated** `internal` namespace + The internal namespace will continue to be exported but now uses OpenAPI format for path parameters. You should use the new utility types. + +- Updated dependencies + - @backstage/errors@1.2.3 + ## 0.0.5-next.0 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 54428236af..04dc3f19f2 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-openapi-utils", "description": "OpenAPI typescript support.", - "version": "0.0.5-next.0", + "version": "0.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 4e656538c8..63600bed9f 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-plugin-api +## 0.6.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.6.6-next.2 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index c733d394c3..2706b1bdaf 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.6.6-next.2", + "version": "0.6.6", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/CHANGELOG.md b/packages/backend-plugin-manager/CHANGELOG.md index 3603dd0dc8..526bc6c802 100644 --- a/packages/backend-plugin-manager/CHANGELOG.md +++ b/packages/backend-plugin-manager/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/backend-plugin-manager +## 0.0.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 0.0.2-next.2 ### Patch Changes diff --git a/packages/backend-plugin-manager/package.json b/packages/backend-plugin-manager/package.json index 5653513b80..20446196cf 100644 --- a/packages/backend-plugin-manager/package.json +++ b/packages/backend-plugin-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-manager", "description": "Backstage plugin management backend", - "version": "0.0.2-next.2", + "version": "0.0.2", "private": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 2dfa563592..2a209521f1 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/backend-tasks +## 0.5.11 + +### Patch Changes + +- 5db102bfdf: Instrument `backend-tasks` with some counters and histograms for duration. + + `backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. + `backend_tasks.task.runs.duration`: Histogram with the run durations for each task. + + Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. + +- ddd76ac98d: Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.5.11-next.2 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index a1fe6497b2..c386654a24 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.11-next.2", + "version": "0.5.11", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index c3b92ebf4f..8cb13b24c5 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/backend-test-utils +## 0.2.7 + +### Patch Changes + +- a250ad775f: Added `createMockDirectory()` to help out with file system mocking in tests. +- 5ddc03813e: Remove third type parameter used for `MockInstance`, in order to be compatible with older versions of `@types/jest`. +- 74491c9602: Updated to import `HostDiscovery` from `@backstage/backend-app-api`. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-app-api@0.5.6 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.7-next.2 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index edcb5b7414..1094de8ced 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.2.7-next.2", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 088f05cfd1..9eb282bb1c 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,64 @@ # example-backend +## 0.2.88 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-nomad-backend@0.1.8 + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-scaffolder-backend@1.18.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.9 + - @backstage/integration@1.7.1 + - @backstage/plugin-playlist-backend@0.3.10 + - @backstage/plugin-techdocs-backend@1.8.0 + - @backstage/plugin-auth-backend@0.19.3 + - @backstage/plugin-rollbar-backend@0.1.51 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/plugin-graphql-backend@0.2.0 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-badges-backend@0.3.3 + - @backstage/plugin-tech-insights-backend@0.5.20 + - @backstage/plugin-kubernetes-backend@0.13.0 + - @backstage/plugin-jenkins-backend@0.3.0 + - @backstage/plugin-code-coverage-backend@0.2.20 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.23 + - @backstage/plugin-search-backend@1.4.6 + - example-app@0.2.88 + - @backstage/plugin-lighthouse-backend@0.3.3 + - @backstage/plugin-linguist-backend@0.5.3 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-search-backend-module-explore@0.1.10 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/plugin-adr-backend@0.4.3 + - @backstage/plugin-app-backend@0.3.54 + - @backstage/plugin-azure-devops-backend@0.4.3 + - @backstage/plugin-azure-sites-backend@0.1.16 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-devtools-backend@0.2.3 + - @backstage/plugin-entity-feedback-backend@0.2.3 + - @backstage/plugin-events-backend@0.2.15 + - @backstage/plugin-explore-backend@0.0.16 + - @backstage/plugin-kafka-backend@0.3.3 + - @backstage/plugin-permission-backend@0.5.29 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-proxy-backend@0.4.3 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.7 + - @backstage/plugin-search-backend-module-pg@0.5.15 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.38 + - @backstage/plugin-todo-backend@0.3.4 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.3 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 0.2.88-next.2 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index cd0191f7fa..76ef8dfb2d 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.88-next.2", + "version": "0.2.88", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 71593b5a33..b3c1aeb56f 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/catalog-client +## 1.4.5 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 1.4.5-next.0 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 2be748fbce..28cbe0879a 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "1.4.5-next.0", + "version": "1.4.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index a6b3715d28..6f374cdbc5 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-model +## 1.4.3 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 1.4.3-next.0 ### Patch Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 58097decec..746ef803ff 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-model", "description": "Types and validators that help describe the model of a Backstage Catalog", - "version": "1.4.3-next.0", + "version": "1.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index 30b9670251..70e98da8dd 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli-common +## 0.1.13 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + ## 0.1.13-next.0 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 8aed6881e2..b8bd27cef9 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-common", "description": "Common functionality used by cli, backend, and create-app", - "version": "0.1.13-next.0", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index 2d896f3e7b..d5dcb6e976 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/cli-node +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/types@1.1.1 + ## 0.1.5-next.1 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 1190d134f5..1d1158c818 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-node", "description": "Node.js library for Backstage CLIs", - "version": "0.1.5-next.1", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index a3a6b005c0..65d0b752e7 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/cli +## 0.23.0 + +### Minor Changes + +- 8defbd5434: Update typescript-eslint to 6.7.x, adding compatibility with TypeScript 5.2. + + This includes a major update on typescript-eslint, you can see the details in the [release notes](https://typescript-eslint.io/blog/announcing-typescript-eslint-v6/). + +- 7077dbf131: **BREAKING** The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior set `LEGACY_BACKEND_START`, which is recommended if you haven't migrated to the new backend system. + + This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. + +### Patch Changes + +- 9468a67b92: In frontend builds and tests `process.env.HAS_REACT_DOM_CLIENT` will now be defined if `react-dom/client` is present, i.e. if using React 18. This allows for conditional imports of `react-dom/client`. +- 68158034e8: Fix for the new backend `start` command to make it work on Windows. +- 4f16e60e6d: Request slightly smaller pages of data from GitHub +- 21cd3b1b24: Added a template for creating `node-library` packages with `yarn new`. +- d0f26cfa4f: Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. +- 1ea20b0be5: Updated dependency `@typescript-eslint/eslint-plugin` to `6.7.5`. +- 2ef6522552: Support for the `.icon.svg` extension has been deprecated and will be removed in the future. The implementation of this extension is too tied to a particular version of MUI and the SVGO, and it makes it harder to evolve the build system. We may introduce the ability to reintroduce this kind of functionality in the future through configuration for use in internal plugins, but for now we're forced to remove it. + + To migrate existing code, rename the `.icon.svg` file to `.tsx` and replace the `` element with `` from MUI and add necessary imports. For example: + + ```tsx + import React from 'react'; + import SvgIcon from '@material-ui/core/SvgIcon'; + import { IconComponent } from '@backstage/core-plugin-api'; + + export const CodeSceneIcon = (props: SvgIconProps) => ( + + + + + + ); + ``` + +- b9ec93430e: The scaffolder-module template now recommends usage of `createMockDirectory` instead of `mock-fs`. +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 425203f898: Fixed recursive reloading issues of the backend, caused by unwanted watched files. +- 3ef18f8c06: Explicitly set `exports: 'named'` for CJS builds, ensuring that they have e.g. `exports["default"] = catalogPlugin;` +- 7187f2953e: The experimental package discovery will now always use the package name for include and exclude filtering, rather than the full module id. Entries pointing to a subpath export will now instead have an `export` field specifying the subpath that the import is from. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.1.5 + - @backstage/config@1.1.1 + - @backstage/eslint-plugin@0.1.3 + - @backstage/release-manifests@0.0.10 + - @backstage/types@1.1.1 + ## 0.23.0-next.2 ### Minor Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 1a5af11de3..689de4b20e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.23.0-next.2", + "version": "0.23.0", "publishConfig": { "access": "public" }, @@ -40,8 +40,6 @@ "@backstage/integration": "workspace:^", "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", - "@esbuild-kit/cjs-loader": "^2.4.1", - "@esbuild-kit/esm-loader": "^2.5.5", "@manypkg/get-packages": "^1.1.3", "@octokit/graphql": "^5.0.0", "@octokit/graphql-schema": "^13.7.0", @@ -131,6 +129,7 @@ "swc-loader": "^0.2.3", "tar": "^6.1.12", "terser-webpack-plugin": "^5.1.3", + "tsx": "^3.14.0", "util": "^0.12.3", "webpack": "^5.70.0", "webpack-dev-server": "^4.7.3", @@ -153,6 +152,7 @@ "@backstage/theme": "workspace:^", "@types/cross-spawn": "^6.0.2", "@types/diff": "^5.0.0", + "@types/ejs": "^3.1.3", "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", "@types/http-proxy": "^1.17.4", @@ -174,11 +174,27 @@ "type-fest": "^2.19.0" }, "peerDependencies": { - "@microsoft/api-extractor": "^7.21.2" + "@microsoft/api-extractor": "^7.21.2", + "@vitejs/plugin-react": "^4.0.4", + "vite": "^4.4.9", + "vite-plugin-html": "^3.2.0", + "vite-plugin-node-polyfills": "^0.14.1" }, "peerDependenciesMeta": { "@microsoft/api-extractor": { "optional": true + }, + "@vitejs/plugin-react": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-plugin-html": { + "optional": true + }, + "vite-plugin-node-polyfills": { + "optional": true } }, "files": [ diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 534ffe8c58..542cc83ce9 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -39,6 +39,7 @@ import { runPlain } from '../run'; import { transforms } from './transforms'; import { version } from '../../lib/version'; import yn from 'yn'; +import { hasReactDomClient } from './hasReactDomClient'; const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; @@ -81,15 +82,6 @@ async function readBuildInfo() { }; } -function hasReactDomClient() { - try { - require.resolve('react-dom/client'); - return true; - } catch { - return false; - } -} - export async function createConfig( paths: BundlingPaths, options: BundlingOptions, diff --git a/packages/cli/src/lib/bundler/hasReactDomClient.ts b/packages/cli/src/lib/bundler/hasReactDomClient.ts new file mode 100644 index 0000000000..e7ef7bbac9 --- /dev/null +++ b/packages/cli/src/lib/bundler/hasReactDomClient.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export function hasReactDomClient() { + try { + require.resolve('react-dom/client'); + return true; + } catch { + return false; + } +} diff --git a/packages/cli/src/lib/bundler/packageDetection.ts b/packages/cli/src/lib/bundler/packageDetection.ts index 10686f7c86..3aa0955c06 100644 --- a/packages/cli/src/lib/bundler/packageDetection.ts +++ b/packages/cli/src/lib/bundler/packageDetection.ts @@ -15,7 +15,7 @@ */ import { BackstagePackageJson } from '@backstage/cli-node'; -import { Config } from '@backstage/config'; +import { Config, ConfigReader } from '@backstage/config'; import chokidar from 'chokidar'; import fs from 'fs-extra'; import { join as joinPath, resolve as resolvePath } from 'path'; @@ -45,9 +45,19 @@ function readPackageDetectionConfig( return {}; } + if (typeof packages !== 'object' || Array.isArray(packages)) { + throw new Error( + "Invalid config at 'app.experimental.packages', expected object", + ); + } + const packagesConfig = new ConfigReader( + packages, + 'app.experimental.packages', + ); + return { - include: config.getOptionalStringArray('app.experimental.packages.include'), - exclude: config.getOptionalStringArray('app.experimental.packages.exclude'), + include: packagesConfig.getOptionalStringArray('include'), + exclude: packagesConfig.getOptionalStringArray('exclude'), }; } @@ -59,8 +69,15 @@ async function detectPackages( resolvePath(targetPath, 'package.json'), ); - return Object.keys(pkg.dependencies ?? {}) - .flatMap(depName => { + return Object.keys(pkg.dependencies ?? {}).flatMap(depName => { + if (exclude?.includes(depName)) { + return []; + } + if (include && !include.includes(depName)) { + return []; + } + + try { const depPackageJson: BackstagePackageJson = require(require.resolve( `${depName}/package.json`, { paths: [targetPath] }, @@ -73,26 +90,30 @@ async function detectPackages( // Include alpha entry point if available. If there's no default export it will be ignored const exp = depPackageJson.exports; if (exp && typeof exp === 'object' && './alpha' in exp) { - return [depName, `${depName}/alpha`]; + return [ + { name: depName, import: depName }, + { name: depName, export: './alpha', import: `${depName}/alpha` }, + ]; } - return [depName]; + return [{ name: depName, import: depName }]; } - return []; - }) - .filter(name => { - if (exclude?.includes(name)) { - return false; - } - if (include && !include.includes(name)) { - return false; - } - return true; - }); + } catch { + /* ignore packages that don't make package.json available */ + } + return []; + }); } -async function writeDetectedPackagesModule(packageNames: string[]) { - const requirePackageScript = packageNames - ?.map(pkg => `{ name: '${pkg}', default: require('${pkg}').default }`) +async function writeDetectedPackagesModule( + pkgs: { name: string; export?: string; import: string }[], +) { + const requirePackageScript = pkgs + ?.map( + pkg => + `{ name: ${JSON.stringify(pkg.name)}, export: ${JSON.stringify( + pkg.export, + )}, default: require('${pkg.import}').default }`, + ) .join(','); await fs.writeFile( diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 78f6bb7823..bd70b2b074 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -34,6 +34,7 @@ import { createConfig, resolveBaseUrl } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths } from './paths'; import { ServeOptions } from './types'; +import { hasReactDomClient } from './hasReactDomClient'; export async function serveBundle(options: ServeOptions) { const paths = resolveBundlingPaths(options); @@ -77,7 +78,9 @@ export async function serveBundle(options: ServeOptions) { const { name } = await fs.readJson(libPaths.resolveTarget('package.json')); - let server: WebpackDevServer | undefined = undefined; + let webpackServer: WebpackDevServer | undefined = undefined; + let viteServer: import('vite').ViteDevServer | undefined = undefined; + let latestFrontendAppConfigs: AppConfig[] = []; const cliConfig = await loadCliConfig({ @@ -86,7 +89,9 @@ export async function serveBundle(options: ServeOptions) { withFilteredKeys: true, watch(appConfigs) { latestFrontendAppConfigs = appConfigs; - server?.invalidate(); + + webpackServer?.invalidate(); + viteServer?.restart(); }, }); latestFrontendAppConfigs = cliConfig.frontendAppConfigs; @@ -123,7 +128,8 @@ export async function serveBundle(options: ServeOptions) { config: fullConfig, targetPath: paths.targetPath, watch() { - server?.invalidate(); + webpackServer?.invalidate(); + viteServer?.restart(); }, }); @@ -139,64 +145,111 @@ export async function serveBundle(options: ServeOptions) { additionalEntryPoints: detectedModulesEntryPoint, }); - const compiler = webpack(config); - - server = new WebpackDevServer( - { - hot: !process.env.CI, - devMiddleware: { - publicPath: config.output?.publicPath as string, - stats: 'errors-warnings', + if (process.env.EXPERIMENTAL_VITE) { + const { default: vite } = await import('vite'); + const { default: viteReact } = await import('@vitejs/plugin-react'); + const { nodePolyfills: viteNodePolyfills } = await import( + 'vite-plugin-node-polyfills' + ); + const { createHtmlPlugin: viteHtml } = await import('vite-plugin-html'); + viteServer = await vite.createServer({ + define: { + global: 'window', + 'process.argv': JSON.stringify(process.argv), + 'process.env.APP_CONFIG': JSON.stringify(cliConfig.frontendAppConfigs), + // This allows for conditional imports of react-dom/client, since there's no way + // to check for presence of it in source code without module resolution errors. + 'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(hasReactDomClient()), }, - static: paths.targetPublic - ? { - publicPath: config.output?.publicPath as string, - directory: paths.targetPublic, - } - : undefined, - historyApiFallback: { - // Paths with dots should still use the history fallback. - // See https://github.com/facebookincubator/create-react-app/issues/387. - disableDotRule: true, - - // The index needs to be rewritten relative to the new public path, including subroutes. - index: `${config.output?.publicPath}index.html`, + plugins: [ + viteReact(), + viteNodePolyfills(), + viteHtml({ + entry: paths.targetEntry, + // todo(blam): we should look at contributing to thPe plugin here + // to support absolute paths, but works in the interim at least. + template: 'public/index.html', + inject: { + data: { + config: frontendConfig, + publicPath: config.output?.publicPath, + }, + }, + }), + ], + server: { + host, + port, }, - https: - url.protocol === 'https:' - ? { - cert: fullConfig.getString('app.https.certificate.cert'), - key: fullConfig.getString('app.https.certificate.key'), - } - : false, - host, - port, - proxy: targetPkg.proxy, - // When the dev server is behind a proxy, the host and public hostname differ - allowedHosts: [url.hostname], - client: { - webSocketURL: 'auto://0.0.0.0:0/ws', - }, - } as any, - compiler as any, - ); - - await new Promise((resolve, reject) => { - server?.startCallback((err?: Error) => { - if (err) { - reject(err); - return; - } - - openBrowser(url.href); - resolve(); + publicDir: paths.targetPublic, + root: paths.targetPath, }); + } else { + const compiler = webpack(config); + + webpackServer = new WebpackDevServer( + { + hot: !process.env.CI, + devMiddleware: { + publicPath: config.output?.publicPath as string, + stats: 'errors-warnings', + }, + static: paths.targetPublic + ? { + publicPath: config.output?.publicPath as string, + directory: paths.targetPublic, + } + : undefined, + historyApiFallback: { + // Paths with dots should still use the history fallback. + // See https://github.com/facebookincubator/create-react-app/issues/387. + disableDotRule: true, + + // The index needs to be rewritten relative to the new public path, including subroutes. + index: `${config.output?.publicPath}index.html`, + }, + https: + url.protocol === 'https:' + ? { + cert: fullConfig.getString('app.https.certificate.cert'), + key: fullConfig.getString('app.https.certificate.key'), + } + : false, + host, + port, + proxy: targetPkg.proxy, + // When the dev server is behind a proxy, the host and public hostname differ + allowedHosts: [url.hostname], + client: { + webSocketURL: 'auto://0.0.0.0:0/ws', + }, + }, + compiler, + ); + } + + await viteServer?.listen(); + await new Promise(async (resolve, reject) => { + if (webpackServer) { + webpackServer.startCallback((err?: Error) => { + if (err) { + reject(err); + return; + } + resolve(); + }); + } else { + resolve(); + } }); + openBrowser(url.href); + const waitForExit = async () => { for (const signal of ['SIGINT', 'SIGTERM'] as const) { process.on(signal, () => { - server?.close(); + webpackServer?.close(); + viteServer?.close(); // exit instead of resolve. The process is shutting down and resolving a promise here logs an error process.exit(); }); diff --git a/packages/cli/src/lib/experimental/startBackendExperimental.ts b/packages/cli/src/lib/experimental/startBackendExperimental.ts index 578fd1c747..af6e33a1e4 100644 --- a/packages/cli/src/lib/experimental/startBackendExperimental.ts +++ b/packages/cli/src/lib/experimental/startBackendExperimental.ts @@ -27,11 +27,14 @@ import { isAbsolute as isAbsolutePath } from 'path'; import { paths } from '../paths'; import spawn from 'cross-spawn'; +const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number); +const supportsModuleLoaderRegister = nodeMajor >= 20 && nodeMinor >= 6; + const loaderArgs = [ '--require', - require.resolve('@esbuild-kit/cjs-loader'), - '--loader', - pathToFileURL(require.resolve('@esbuild-kit/esm-loader')).toString(), // Windows prefers a URL here + require.resolve('tsx/preflight'), + supportsModuleLoaderRegister ? '--import' : '--loader', + pathToFileURL(require.resolve('tsx')).toString(), // Windows prefers a URL here ]; export async function startBackendExperimental(options: BackendServeOptions) { @@ -95,7 +98,7 @@ export async function startBackendExperimental(options: BackendServeOptions) { process.execPath, [...loaderArgs, ...optionArgs, options.entry, ...userArgs], { - stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + stdio: ['ignore', 'inherit', 'inherit', 'ipc'], env: { ...process.env, BACKSTAGE_CLI_CHANNEL: '1', @@ -124,9 +127,8 @@ export async function startBackendExperimental(options: BackendServeOptions) { restart(); - watcher = watch([paths.targetDir], { + watcher = watch([], { cwd: process.cwd(), - ignored: ['**/.*/**', '**/node_modules/**'], ignoreInitial: true, ignorePermissionErrors: true, }).on('all', restart); diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 7db642945f..133da12a64 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/codemods +## 0.1.46 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13 + ## 0.1.46-next.0 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 34f4b5d748..d469ad47ea 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.46-next.0", + "version": "0.1.46", "publishConfig": { "access": "public", "main": "dist/index.cjs.js" diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 8e25cf28fa..b0d59d8a8b 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/config-loader +## 1.5.1 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 30c553c1d2: Updated dependency `typescript-json-schema` to `^0.61.0`. +- 773ea341d2: The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. +- a4617c422a: Added `watch` option to configuration loaders that can be used to disable file watching by setting it to `false`. +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.5.1-next.1 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 3ddd84fdb5..fa2ad992c6 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "1.5.1-next.1", + "version": "1.5.1", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/packages/config-loader/src/sources/ConfigSources.test.ts b/packages/config-loader/src/sources/ConfigSources.test.ts index 43feb3ca27..f095bbec42 100644 --- a/packages/config-loader/src/sources/ConfigSources.test.ts +++ b/packages/config-loader/src/sources/ConfigSources.test.ts @@ -95,6 +95,14 @@ describe('ConfigSources', () => { ), ).toEqual([{ name: 'FileConfigSource', path: '/config.yaml' }]); + expect( + mergeSources( + ConfigSources.defaultForTargets({ + targets: [{ type: 'path', target: 'config.yaml' }], + }), + ), + ).toEqual([{ name: 'FileConfigSource', path: resolvePath('config.yaml') }]); + const subFunc = async () => undefined; expect( mergeSources( @@ -172,8 +180,8 @@ describe('ConfigSources', () => { }), ), ).toEqual([ - { name: 'FileConfigSource', path: 'a.yaml' }, - { name: 'FileConfigSource', path: 'b.yaml' }, + { name: 'FileConfigSource', path: resolvePath('a.yaml') }, + { name: 'FileConfigSource', path: resolvePath('b.yaml') }, { name: 'EnvConfigSource', env: { HOME: '/' } }, ]); }); diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index 43123f87ea..03fc6d83d6 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -161,7 +161,7 @@ export class ConfigSources { } return FileConfigSource.create({ watch: options.watch, - path: arg.target, + path: resolvePath(arg.target), substitutionFunc: options.substitutionFunc, }); }); diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index 8f0f5202f4..1ba8b45805 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/config +## 1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 1.1.1-next.0 ### Patch Changes diff --git a/packages/config/package.json b/packages/config/package.json index 538429e569..d7127b8c05 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "1.1.1-next.0", + "version": "1.1.1", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 35bbee7183..bce1da4c9d 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/core-app-api +## 1.11.0 + +### Minor Changes + +- c9d9bfeca2: URL encode some well known unsafe characters in `RouteResolver` (and therefore `useRouteRef`) + +### Patch Changes + +- 29e4d8b76b: Fixed bug in `AppRouter` to determine the correct `signOutTargetUrl` if `app.baseUrl` contains a `basePath` +- acca17e91a: Wrap entire app in ``, enabling support for using translations outside plugins. +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- f1b349cfba: Fixed a bug in `TranslationApi` implementation where in some cases it wouldn't notify subscribers of language changes. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.11.0-next.2 ### Minor Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index b566ff6fe6..e6792a3402 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.11.0-next.2", + "version": "1.11.0", "publishConfig": { "access": "public" }, @@ -57,8 +57,8 @@ "zod": "^3.21.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -66,7 +66,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.0.0", "@types/zen-observable": "^0.8.0", diff --git a/packages/core-app-api/src/apis/system/ApiProvider.test.tsx b/packages/core-app-api/src/apis/system/ApiProvider.test.tsx index a6118f0f68..6460e12900 100644 --- a/packages/core-app-api/src/apis/system/ApiProvider.test.tsx +++ b/packages/core-app-api/src/apis/system/ApiProvider.test.tsx @@ -118,6 +118,10 @@ describe('ApiProvider', () => { }).toThrow(/^API context is not available/); }).error, ).toEqual([ + expect.objectContaining({ + detail: new Error('API context is not available'), + type: 'unhandled exception', + }), expect.objectContaining({ detail: new Error('API context is not available'), type: 'unhandled exception', @@ -134,6 +138,10 @@ describe('ApiProvider', () => { }).toThrow(/^API context is not available/); }).error, ).toEqual([ + expect.objectContaining({ + detail: new Error('API context is not available'), + type: 'unhandled exception', + }), expect.objectContaining({ detail: new Error('API context is not available'), type: 'unhandled exception', @@ -156,6 +164,10 @@ describe('ApiProvider', () => { }).toThrow('No implementation available for apiRef{x}'); }).error, ).toEqual([ + expect.objectContaining({ + detail: new Error('No implementation available for apiRef{x}'), + type: 'unhandled exception', + }), expect.objectContaining({ detail: new Error('No implementation available for apiRef{x}'), type: 'unhandled exception', @@ -176,6 +188,10 @@ describe('ApiProvider', () => { }).toThrow('No implementation available for apiRef{x}'); }).error, ).toEqual([ + expect.objectContaining({ + detail: new Error('No implementation available for apiRef{x}'), + type: 'unhandled exception', + }), expect.objectContaining({ detail: new Error('No implementation available for apiRef{x}'), type: 'unhandled exception', diff --git a/packages/core-app-api/src/app/AppContext.test.tsx b/packages/core-app-api/src/app/AppContext.test.tsx index ee7b90533f..a011b5966b 100644 --- a/packages/core-app-api/src/app/AppContext.test.tsx +++ b/packages/core-app-api/src/app/AppContext.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useVersionedContext } from '@backstage/version-bridge'; import { AppContext as AppContextV1 } from './types'; import { AppContextProvider } from './AppContext'; diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 3d0c47c4d5..fe8d2fa91a 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -639,26 +639,24 @@ describe('Integration Test', () => { const Provider = app.getProvider(); const Router = app.getRouter(); const { error: errorLogs } = withLogCollector(() => { - expect(() => - render( - - - - }> - } /> - - - - , - ), - ).toThrow( - 'Parameter :thing is duplicated in path test/:thing/some/:thing', + render( + + + + }> + } /> + + + + , ); }); expect(errorLogs).toEqual([ - expect.stringContaining( - 'The above error occurred in the component', - ), + expect.objectContaining({ + message: expect.stringContaining( + 'Parameter :thing is duplicated in path test/:thing/some/:thing', + ), + }), ]); }); @@ -676,24 +674,22 @@ describe('Integration Test', () => { const Provider = app.getProvider(); const Router = app.getRouter(); const { error: errorLogs } = withLogCollector(() => { - expect(() => - render( - - - - } /> - - - , - ), - ).toThrow( - /^External route 'extRouteRef1' of the 'blob' plugin must be bound to a target route/, + render( + + + + } /> + + + , ); }); expect(errorLogs).toEqual([ - expect.stringContaining( - 'The above error occurred in the component', - ), + expect.objectContaining({ + message: expect.stringMatching( + /^External route 'extRouteRef1' of the 'blob' plugin must be bound to a target route/, + ), + }), ]); }); diff --git a/packages/core-app-api/src/app/AppRouter.tsx b/packages/core-app-api/src/app/AppRouter.tsx index 9d07be1ffd..7481f6662a 100644 --- a/packages/core-app-api/src/app/AppRouter.tsx +++ b/packages/core-app-api/src/app/AppRouter.tsx @@ -16,6 +16,7 @@ import React, { useContext, ReactNode, ComponentType, useState } from 'react'; import { + attachComponentData, ConfigApi, configApiRef, IdentityApi, @@ -186,3 +187,5 @@ export function AppRouter(props: AppRouterProps) { ); } + +attachComponentData(AppRouter, 'core.type', 'AppRouter'); diff --git a/packages/core-app-api/src/routing/FlatRoutes.beta.test.tsx b/packages/core-app-api/src/routing/FlatRoutes.beta.test.tsx index 30be04d2d4..8d4d10c52a 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.beta.test.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.beta.test.tsx @@ -56,7 +56,7 @@ function makeRouteRenderer(node: ReactNode) { ); if (rendered) { rendered.unmount(); - rendered.rerender(content); + rendered = render(content); } else { rendered = render(content); } diff --git a/packages/core-app-api/src/routing/FlatRoutes.compat.test.tsx b/packages/core-app-api/src/routing/FlatRoutes.compat.test.tsx index 5d2ca15672..c32b306387 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.compat.test.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.compat.test.tsx @@ -83,7 +83,7 @@ describe.each(['beta', 'stable'])('FlatRoutes %s', rrVersion => { ); if (rendered) { rendered.unmount(); - rendered.rerender(content); + rendered = render(content); } else { rendered = render(content); } diff --git a/packages/core-app-api/src/routing/FlatRoutes.stable.test.tsx b/packages/core-app-api/src/routing/FlatRoutes.stable.test.tsx index 93297edc4c..ece6c22ff2 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.stable.test.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.stable.test.tsx @@ -56,7 +56,7 @@ function makeRouteRenderer(node: ReactNode) { ); if (rendered) { rendered.unmount(); - rendered.rerender(content); + rendered = render(content); } else { rendered = render(content); } diff --git a/packages/core-app-api/src/routing/FlatRoutes.tsx b/packages/core-app-api/src/routing/FlatRoutes.tsx index abb7fe9432..46c2270d0d 100644 --- a/packages/core-app-api/src/routing/FlatRoutes.tsx +++ b/packages/core-app-api/src/routing/FlatRoutes.tsx @@ -16,7 +16,11 @@ import React, { ReactNode, useMemo } from 'react'; import { useRoutes } from 'react-router-dom'; -import { useApp, useElementFilter } from '@backstage/core-plugin-api'; +import { + attachComponentData, + useApp, + useElementFilter, +} from '@backstage/core-plugin-api'; import { isReactRouterBeta } from '../app/isReactRouterBeta'; let warned = false; @@ -115,3 +119,5 @@ export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => { return useRoutes(withNotFound); }; + +attachComponentData(FlatRoutes, 'core.type', 'FlatRoutes'); diff --git a/packages/core-app-api/src/routing/RoutingProvider.beta.test.tsx b/packages/core-app-api/src/routing/RoutingProvider.beta.test.tsx index 0f7a5cd3ad..ca089d0014 100644 --- a/packages/core-app-api/src/routing/RoutingProvider.beta.test.tsx +++ b/packages/core-app-api/src/routing/RoutingProvider.beta.test.tsx @@ -17,7 +17,7 @@ import React, { PropsWithChildren, ReactElement } from 'react'; import { MemoryRouter, Routes } from 'react-router-dom'; import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useVersionedContext } from '@backstage/version-bridge'; import { childDiscoverer, @@ -353,9 +353,7 @@ describe('v1 consumer', () => { initialProps: { routeRef: routeRef1 as AnyRouteRef, }, - wrapper: ({ - children, - }: React.PropsWithChildren<{ routeRef: AnyRouteRef }>) => ( + wrapper: ({ children }) => ( , string>([ diff --git a/packages/core-app-api/src/routing/RoutingProvider.stable.test.tsx b/packages/core-app-api/src/routing/RoutingProvider.stable.test.tsx index 495fc20b15..df0ce32e2b 100644 --- a/packages/core-app-api/src/routing/RoutingProvider.stable.test.tsx +++ b/packages/core-app-api/src/routing/RoutingProvider.stable.test.tsx @@ -17,7 +17,7 @@ import React, { PropsWithChildren, ReactElement } from 'react'; import { MemoryRouter, Routes, Route, useOutlet } from 'react-router-dom'; import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useVersionedContext } from '@backstage/version-bridge'; import { childDiscoverer, @@ -385,9 +385,7 @@ describe('v1 consumer', () => { initialProps: { routeRef: routeRef1 as AnyRouteRef, }, - wrapper: ({ - children, - }: React.PropsWithChildren<{ routeRef: AnyRouteRef }>) => ( + wrapper: ({ children }) => ( , string>([ diff --git a/packages/core-compat-api/.eslintrc.js b/packages/core-compat-api/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/core-compat-api/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/core-compat-api/README.md b/packages/core-compat-api/README.md new file mode 100644 index 0000000000..5faa299f03 --- /dev/null +++ b/packages/core-compat-api/README.md @@ -0,0 +1,12 @@ +# @backstage/core-compat-api + +_This package was created through the Backstage CLI_. + +## Installation + +Install the package via Yarn: + +```sh +cd # if within a monorepo +yarn add @backstage/core-compat-api +``` diff --git a/packages/core-compat-api/api-report.md b/packages/core-compat-api/api-report.md new file mode 100644 index 0000000000..3dd2eb6b22 --- /dev/null +++ b/packages/core-compat-api/api-report.md @@ -0,0 +1,23 @@ +## API Report File for "@backstage/core-compat-api" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; +import { default as React_2 } from 'react'; + +// @public (undocumented) +export function collectLegacyRoutes( + flatRoutesElement: JSX.Element, +): BackstagePlugin[]; + +// @public (undocumented) +export function convertLegacyApp( + rootElement: React_2.JSX.Element, +): (ExtensionOverrides | BackstagePlugin)[]; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/core-compat-api/catalog-info.yaml b/packages/core-compat-api/catalog-info.yaml new file mode 100644 index 0000000000..f20f0543a0 --- /dev/null +++ b/packages/core-compat-api/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-core-compat-api + title: '@backstage/core-compat-api' +spec: + lifecycle: experimental + type: backstage-web-library + owner: maintainers diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json new file mode 100644 index 0000000000..d27049c2a4 --- /dev/null +++ b/packages/core-compat-api/package.json @@ -0,0 +1,45 @@ +{ + "name": "@backstage/core-compat-api", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": true, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library" + }, + "sideEffects": false, + "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" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/plugin-puppetdb": "workspace:^", + "@backstage/plugin-stackstorm": "workspace:^", + "@oriflame/backstage-plugin-score-card": "^0.7.0", + "@testing-library/jest-dom": "^6.0.0" + }, + "files": [ + "dist" + ], + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "dependencies": { + "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^" + } +} diff --git a/packages/core-compat-api/src/collectLegacyRoutes.test.tsx b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx new file mode 100644 index 0000000000..85fed83e8c --- /dev/null +++ b/packages/core-compat-api/src/collectLegacyRoutes.test.tsx @@ -0,0 +1,104 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FlatRoutes } from '@backstage/core-app-api'; +import { PuppetDbPage } from '@backstage/plugin-puppetdb'; +import { StackstormPage } from '@backstage/plugin-stackstorm'; +import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card'; +import React from 'react'; +import { Route } from 'react-router-dom'; + +import { collectLegacyRoutes } from './collectLegacyRoutes'; + +describe('collectLegacyRoutes', () => { + it('should collect legacy routes', () => { + const collected = collectLegacyRoutes( + + } /> + } /> + } /> + } /> + , + ); + + expect( + collected.map(p => ({ + id: p.id, + extensions: p.extensions.map(e => ({ + id: e.id, + attachTo: e.attachTo, + disabled: e.disabled, + defaultConfig: e.configSchema?.parse({}), + })), + })), + ).toEqual([ + { + id: 'score-card', + extensions: [ + { + id: 'plugin.score-card.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'score-board' }, + }, + { + id: 'apis.plugin.scoringdata.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + { + id: 'stackstorm', + extensions: [ + { + id: 'plugin.stackstorm.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'stackstorm' }, + }, + { + id: 'apis.plugin.stackstorm.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + { + id: 'puppetDb', + extensions: [ + { + id: 'plugin.puppetDb.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'puppetdb' }, + }, + { + id: 'plugin.puppetDb.page2', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'puppetdb' }, + }, + { + id: 'apis.plugin.puppetdb.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + ]); + }); +}); diff --git a/packages/core-compat-api/src/collectLegacyRoutes.tsx b/packages/core-compat-api/src/collectLegacyRoutes.tsx new file mode 100644 index 0000000000..8178de2876 --- /dev/null +++ b/packages/core-compat-api/src/collectLegacyRoutes.tsx @@ -0,0 +1,142 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { ReactNode } from 'react'; +import { + Extension, + createApiExtension, + createPageExtension, + createPlugin, + BackstagePlugin, +} from '@backstage/frontend-plugin-api'; +import { Route, Routes } from 'react-router-dom'; +import { + BackstagePlugin as LegacyBackstagePlugin, + RouteRef, + getComponentData, +} from '@backstage/core-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; + +/* + +# Legacy interoperability + +Use-cases (prioritized): + 1. Slowly migrate over an existing app to DI, piece by piece + 2. Use a legacy plugin in a new DI app + 3. Use DI in an existing legacy app + +Starting point: use-case #1 + +Potential solutions: + 1. Codemods (we're not considering this for now) + 2. Legacy apps are migrated bottom-up, i.e. keep legacy root, replace pages with DI + 3. Legacy apps are migrated top-down i.e. switch out base to DI, legacy adapter allows for usage of existing app structure + +Chosen path: #3 + +Existing tasks: + - Adopters can migrate their existing app gradually (~4) + - Example-app uses legacy base with DI adapters + - Create an API that lets you inject DI into existing apps - working assumption is that this is enough + - Adopters can use legacy plugins in DI through adapters (~8) + - App-next uses DI base with legacy adapters + - Create a legacy adapter that is able to take an existing extension tree + +*/ + +/** @public */ +export function collectLegacyRoutes( + flatRoutesElement: JSX.Element, +): BackstagePlugin[] { + const createdPluginIds = new Map< + LegacyBackstagePlugin, + Extension[] + >(); + + React.Children.forEach( + flatRoutesElement.props.children, + (route: ReactNode) => { + if (!React.isValidElement(route)) { + return; + } + + // TODO(freben): Handle feature flag and permissions framework wrapper elements + if (route.type !== Route) { + return; + } + + const routeElement = route.props.element; + + // TODO: to support deeper extension component, e.g. hidden within , use https://github.com/backstage/backstage/blob/518a34646b79ec2028cc0ed6bc67d4366c51c4d6/packages/core-app-api/src/routing/collectors.tsx#L69 + const plugin = getComponentData( + routeElement, + 'core.plugin', + ); + if (!plugin) { + return; + } + + const routeRef = getComponentData( + routeElement, + 'core.mountPoint', + ); + + const pluginId = plugin.getId(); + + const detectedExtensions = + createdPluginIds.get(plugin) ?? new Array>(); + createdPluginIds.set(plugin, detectedExtensions); + + const path: string = route.props.path; + + detectedExtensions.push( + createPageExtension({ + id: `plugin.${pluginId}.page${ + detectedExtensions.length ? detectedExtensions.length + 1 : '' + }`, + defaultPath: path[0] === '/' ? path.slice(1) : path, + routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined, + + loader: async () => + route.props.children ? ( + + + + + + ) : ( + routeElement + ), + }), + ); + }, + ); + + return Array.from(createdPluginIds).map(([plugin, extensions]) => + createPlugin({ + id: plugin.getId(), + extensions: [ + ...extensions, + ...Array.from(plugin.getApis()).map(factory => + createApiExtension({ + factory, + }), + ), + ], + }), + ); +} diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx new file mode 100644 index 0000000000..0f1f6145c9 --- /dev/null +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AppRouter, FlatRoutes } from '@backstage/core-app-api'; +import { PuppetDbPage } from '@backstage/plugin-puppetdb'; +import { StackstormPage } from '@backstage/plugin-stackstorm'; +import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card'; +import React, { ReactNode } from 'react'; +import { Route } from 'react-router-dom'; +import { convertLegacyApp } from './convertLegacyApp'; + +const Root = ({ children }: { children: ReactNode }) => <>{children}; + +describe('convertLegacyApp', () => { + it('should find and extract root and routes', () => { + const collected = convertLegacyApp( + <> +
+ + +
+ + + } /> + } /> + } /> + } /> + + + + , + ); + + expect( + collected.map((p: any /* TODO */) => ({ + id: p.id, + extensions: p.extensions.map((e: any) => ({ + id: e.id, + attachTo: e.attachTo, + disabled: e.disabled, + defaultConfig: e.configSchema?.parse({}), + })), + })), + ).toEqual([ + { + id: 'score-card', + extensions: [ + { + id: 'plugin.score-card.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'score-board' }, + }, + { + id: 'apis.plugin.scoringdata.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + { + id: 'stackstorm', + extensions: [ + { + id: 'plugin.stackstorm.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'stackstorm' }, + }, + { + id: 'apis.plugin.stackstorm.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + { + id: 'puppetDb', + extensions: [ + { + id: 'plugin.puppetDb.page', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'puppetdb' }, + }, + { + id: 'plugin.puppetDb.page2', + attachTo: { id: 'core.routes', input: 'routes' }, + disabled: false, + defaultConfig: { path: 'puppetdb' }, + }, + { + id: 'apis.plugin.puppetdb.service', + attachTo: { id: 'core', input: 'apis' }, + disabled: false, + }, + ], + }, + { + id: undefined, + extensions: [ + { + id: 'core.layout', + attachTo: { id: 'core', input: 'root' }, + disabled: false, + }, + { + id: 'core.nav', + attachTo: { id: 'core.layout', input: 'nav' }, + disabled: true, + }, + ], + }, + ]); + }); +}); diff --git a/packages/core-compat-api/src/convertLegacyApp.ts b/packages/core-compat-api/src/convertLegacyApp.ts new file mode 100644 index 0000000000..59cb136c65 --- /dev/null +++ b/packages/core-compat-api/src/convertLegacyApp.ts @@ -0,0 +1,139 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { + Children, + Fragment, + ReactElement, + ReactNode, + isValidElement, +} from 'react'; +import { + BackstagePlugin, + ExtensionOverrides, + coreExtensionData, + createExtension, + createExtensionInput, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; +import { getComponentData } from '@backstage/core-plugin-api'; +import { collectLegacyRoutes } from './collectLegacyRoutes'; + +function selectChildren( + rootNode: ReactNode, + selector?: (element: ReactElement<{ children?: ReactNode }>) => boolean, + strictError?: string, +): Array> { + return Children.toArray(rootNode).flatMap(node => { + if (!isValidElement<{ children?: ReactNode }>(node)) { + return []; + } + + if (node.type === Fragment) { + return selectChildren(node.props.children, selector, strictError); + } + + if (selector === undefined || selector(node)) { + return [node]; + } + + if (strictError) { + throw new Error(strictError); + } + + return selectChildren(node.props.children, selector, strictError); + }); +} + +/** @public */ +export function convertLegacyApp( + rootElement: React.JSX.Element, +): (ExtensionOverrides | BackstagePlugin)[] { + const appRouterEls = selectChildren( + rootElement, + el => getComponentData(el, 'core.type') === 'AppRouter', + ); + if (appRouterEls.length !== 1) { + throw new Error( + "Failed to convert legacy app, AppRouter element could not been found. Make sure it's at the top level of the App element tree", + ); + } + + const rootEls = selectChildren( + appRouterEls[0].props.children, + el => + Boolean(el.props.children) && + selectChildren( + el.props.children, + innerEl => getComponentData(innerEl, 'core.type') === 'FlatRoutes', + ).length === 1, + ); + if (rootEls.length !== 1) { + throw new Error( + "Failed to convert legacy app, Root element containing FlatRoutes could not been found. Make sure it's within the AppRouter element of the App element tree", + ); + } + const [rootEl] = rootEls; + + const routesEls = selectChildren( + rootEls[0].props.children, + el => getComponentData(el, 'core.type') === 'FlatRoutes', + ); + if (routesEls.length !== 1) { + throw new Error( + 'Unexpectedly failed to find FlatRoutes in app element tree', + ); + } + const [routesEl] = routesEls; + + const CoreLayoutOverride = createExtension({ + id: 'core.layout', + attachTo: { id: 'core', input: 'root' }, + inputs: { + content: createExtensionInput( + { + element: coreExtensionData.reactElement, + }, + { singleton: true }, + ), + }, + output: { + element: coreExtensionData.reactElement, + }, + factory({ bind, inputs }) { + // Clone the root element, this replaces the FlatRoutes declared in the app with out content input + bind({ + element: React.cloneElement(rootEl, undefined, inputs.content.element), + }); + }, + }); + const CoreNavOverride = createExtension({ + id: 'core.nav', + attachTo: { id: 'core.layout', input: 'nav' }, + output: {}, + factory() {}, + disabled: true, + }); + + const collectedRoutes = collectLegacyRoutes(routesEl); + + return [ + ...collectedRoutes, + createExtensionOverrides({ + extensions: [CoreLayoutOverride, CoreNavOverride], + }), + ]; +} diff --git a/packages/core-compat-api/src/index.ts b/packages/core-compat-api/src/index.ts new file mode 100644 index 0000000000..e5f61119a3 --- /dev/null +++ b/packages/core-compat-api/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { collectLegacyRoutes } from './collectLegacyRoutes'; +export { convertLegacyApp } from './convertLegacyApp'; diff --git a/packages/core-compat-api/src/setupTests.ts b/packages/core-compat-api/src/setupTests.ts new file mode 100644 index 0000000000..865308e634 --- /dev/null +++ b/packages/core-compat-api/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index b6a2f05cd1..3ee6eae062 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/core-components +## 0.13.6 + +### Patch Changes + +- 4eab5cf901: The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. +- 0b55f773a7: Removed some unused dependencies +- 8a15360bb4: Fixed overflowing messages in `WarningPanel`. +- 997a71850c: Changed SupportButton menuitems to support text wrap +- 0296f272b4: Fixed the type declaration of `DependencyGraphProps`, the `defs` prop now expects `JSX.Element`s. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 16126dbe6a: Change overlay header colors in the mobile menu to use navigation color from the theme +- d19a827ef1: MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.13.6-next.2 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 3bbaa8ee6a..842a52df43 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.13.6-next.2", + "version": "0.13.6", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -78,8 +78,8 @@ "zod": "^3.21.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -88,8 +88,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/ansi-regex": "^5.0.0", "@types/classnames": "^2.2.9", diff --git a/packages/core-components/src/components/AutoLogout/disconnectedUsers.test.ts b/packages/core-components/src/components/AutoLogout/disconnectedUsers.test.ts index 87d6369eda..3d097dcc7f 100644 --- a/packages/core-components/src/components/AutoLogout/disconnectedUsers.test.ts +++ b/packages/core-components/src/components/AutoLogout/disconnectedUsers.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; import { diff --git a/packages/core-components/src/components/Avatar/util.test.ts b/packages/core-components/src/components/Avatar/util.test.ts index 6581df8b9a..98d0bd2550 100644 --- a/packages/core-components/src/components/Avatar/util.test.ts +++ b/packages/core-components/src/components/Avatar/util.test.ts @@ -17,25 +17,29 @@ import { extractInitials, stringToColor } from './utils'; describe('stringToColor', () => { - it('extract color', async () => { + it('extract color', () => { expect(stringToColor('Jenny Doe')).toEqual('#7809fa'); }); }); describe('extractInitials', () => { - it('extract initials', async () => { + it('extract initials', () => { expect(extractInitials('Jenny Doe')).toEqual('JD'); }); - it('extract unicode initials', async () => { + it('extract unicode initials', () => { expect(extractInitials('Petr Čech')).toEqual('PČ'); }); - it('extract single letter for short name', async () => { + it('extract single letter for short name', () => { expect(extractInitials('Doe')).toEqual('D'); }); - it('limit the initials to two letters', async () => { - expect(extractInitials('John Jonathan Doe')).toEqual('JJ'); + it('limit the initials to two letters', () => { + expect(extractInitials('John Jonathan Doe')).toEqual('JD'); + }); + + it('removes spaces from beginning or the end', () => { + expect(extractInitials(' John Jonathan Doe ')).toEqual('JD'); }); }); diff --git a/packages/core-components/src/components/Avatar/utils.ts b/packages/core-components/src/components/Avatar/utils.ts index 79627d5996..65e2be6afa 100644 --- a/packages/core-components/src/components/Avatar/utils.ts +++ b/packages/core-components/src/components/Avatar/utils.ts @@ -27,9 +27,11 @@ export function stringToColor(str: string) { return color; } -export function extractInitials(value: string) { - return value - .match(/(? 1 ? names[names.length - 1] : ''; + return firstName && lastName + ? `${firstName.charAt(0)}${lastName.charAt(0)}` + : firstName.charAt(0); } diff --git a/packages/core-components/src/components/Link/Link.test.tsx b/packages/core-components/src/components/Link/Link.test.tsx index f88d830479..42668b54c9 100644 --- a/packages/core-components/src/components/Link/Link.test.tsx +++ b/packages/core-components/src/components/Link/Link.test.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ -import React from 'react'; -import { fireEvent, waitFor, screen } from '@testing-library/react'; +import React, { ComponentType } from 'react'; +import { fireEvent, waitFor, screen, renderHook } from '@testing-library/react'; import { MockAnalyticsApi, TestApiProvider, @@ -24,7 +24,6 @@ import { import { analyticsApiRef, configApiRef } from '@backstage/core-plugin-api'; import { isExternalUri, Link, useResolvedPath } from './Link'; import { Route, Routes } from 'react-router-dom'; -import { renderHook, WrapperComponent } from '@testing-library/react-hooks'; import { ConfigReader } from '@backstage/config'; describe('', () => { @@ -128,7 +127,7 @@ describe('', () => { }); describe('useResolvedPath', () => { - const wrapper: WrapperComponent> = ({ + const wrapper: ComponentType> = ({ children, }) => { const configApi = new ConfigReader({ diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx index a64f22765b..1b54f552a5 100644 --- a/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx +++ b/packages/core-components/src/components/LogViewer/useLogViewerSearch.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { applySearchFilter, useLogViewerSearch } from './useLogViewerSearch'; import { AnsiLine } from './AnsiProcessor'; diff --git a/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx b/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx index a828818ed5..6c6f7da71b 100644 --- a/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx +++ b/packages/core-components/src/components/LogViewer/useLogViewerSelection.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { TestApiProvider, MockErrorApi } from '@backstage/test-utils'; import { errorApiRef } from '@backstage/core-plugin-api'; import { AnsiLine } from './AnsiProcessor'; diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx index 2a0b0eae28..2c727efe1b 100644 --- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx +++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx @@ -27,8 +27,8 @@ import { SubRoute } from './types'; export function useSelectedSubRoute(subRoutes: SubRoute[]): { index: number; - route: SubRoute; - element: JSX.Element; + route?: SubRoute; + element?: JSX.Element; } { const params = useParams(); @@ -44,7 +44,7 @@ export function useSelectedSubRoute(subRoutes: SubRoute[]): { b.path.replace(/\/\*$/, '').localeCompare(a.path.replace(/\/\*$/, '')), ); - const element = useRoutes(sortedRoutes) ?? subRoutes[0].children; + const element = useRoutes(sortedRoutes) ?? subRoutes[0]?.children; // TODO(Rugvip): Once we only support v6 stable we can always prefix // This avoids having a double / prefix for react-router v6 beta, which in turn breaks @@ -98,7 +98,7 @@ export function RoutedTabs(props: { routes: SubRoute[] }) { onChange={onTabChange} /> - + {element} diff --git a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx index f5a059d615..c7109686d5 100644 --- a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -48,6 +48,11 @@ describe('TabbedLayout', () => { }); expect(error).toEqual([ + expect.objectContaining({ + detail: new Error( + 'Child of TabbedLayout must be an TabbedLayout.Route', + ), + }), expect.objectContaining({ detail: new Error( 'Child of TabbedLayout must be an TabbedLayout.Route', diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx index 6a16224a02..8bfb228f53 100644 --- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx +++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx @@ -67,6 +67,9 @@ describe('', () => { }); expect(error).toEqual([ + expect.objectContaining({ + detail: new Error('Bomb'), + }), expect.objectContaining({ detail: new Error('Bomb'), }), @@ -75,6 +78,6 @@ describe('', () => { ), expect.stringMatching(/^ErrorBoundary/), ]); - expect(error.length).toEqual(3); + expect(error.length).toEqual(4); }); }); diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx index ce5c572eef..f656696f8a 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.test.tsx @@ -19,6 +19,7 @@ import Badge from '@material-ui/core/Badge'; import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; import { HeaderTabs } from './HeaderTabs'; +import userEvent from '@testing-library/user-event'; const mockTabs = [ { id: 'overview', label: 'Overview' }, @@ -41,7 +42,7 @@ describe('', () => { 'false', ); - rendered.getByText('Docs').click(); + await userEvent.click(rendered.getByText('Docs')); expect(rendered.getByText('Docs').parentElement).toHaveAttribute( 'aria-selected', diff --git a/packages/core-components/src/layout/Sidebar/Items.test.tsx b/packages/core-components/src/layout/Sidebar/Items.test.tsx index 9479180180..6c959bfd0d 100644 --- a/packages/core-components/src/layout/Sidebar/Items.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.test.tsx @@ -26,7 +26,7 @@ import HomeIcon from '@material-ui/icons/Home'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; import { Sidebar } from './Bar'; import { SidebarItem, SidebarSearchField, SidebarExpandButton } from './Items'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { makeStyles } from '@material-ui/core/styles'; import { analyticsApiRef } from '@backstage/core-plugin-api'; diff --git a/packages/core-components/src/layout/Sidebar/SidebarOpenStateContext.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarOpenStateContext.test.tsx index f1900f025c..8cc6f7858c 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarOpenStateContext.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarOpenStateContext.test.tsx @@ -16,7 +16,7 @@ import React, { ReactNode, useContext } from 'react'; import { renderWithEffects } from '@backstage/test-utils'; import { waitFor } from '@testing-library/react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { LegacySidebarContext, SidebarOpenStateProvider, diff --git a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx index 8bd1597725..8f6660707d 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx @@ -16,7 +16,7 @@ import React, { ReactNode, useContext } from 'react'; import { renderWithEffects } from '@backstage/test-utils'; import { waitFor } from '@testing-library/react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { LegacySidebarPinStateContext, SidebarPinStateProvider, diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 3c1516c646..e35fd4d6a3 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/core-plugin-api +## 1.7.0 + +### Minor Changes + +- 322bbcae24: Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 1.7.0-next.1 ### Patch Changes diff --git a/packages/core-plugin-api/alpha-api-report.md b/packages/core-plugin-api/alpha-api-report.md index ba3583142f..0284d691a9 100644 --- a/packages/core-plugin-api/alpha-api-report.md +++ b/packages/core-plugin-api/alpha-api-report.md @@ -3,8 +3,12 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyRouteRefParams } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { Observable } from '@backstage/types'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { SubRouteRef } from '@backstage/core-plugin-api'; import { TranslationMessages as TranslationMessages_2 } from '@backstage/core-plugin-api/alpha'; import { TranslationRef as TranslationRef_2 } from '@backstage/core-plugin-api/alpha'; @@ -25,6 +29,24 @@ export type AppLanguageApi = { // @alpha (undocumented) export const appLanguageApiRef: ApiRef; +// @public +export function convertLegacyRouteRef( + ref: RouteRef, +): NewRouteRef; + +// @public +export function convertLegacyRouteRef( + ref: SubRouteRef, +): NewSubRouteRef; + +// @public +export function convertLegacyRouteRef< + TParams extends AnyRouteRefParams, + TOptional extends boolean, +>( + ref: ExternalRouteRef, +): NewExternalRouteRef; + // @alpha export function createTranslationMessages< TId extends string, diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 7873b23f13..789fc2bfdc 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -95,8 +95,11 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef; }; +// @public @deprecated (undocumented) +export type AnyParams = AnyRouteRefParams; + // @public -export type AnyParams = +export type AnyRouteRefParams = | { [param in string]: string; } @@ -523,7 +526,7 @@ export type IdentityApi = { // @public export const identityApiRef: ApiRef; -// @public +// @public @deprecated export type MakeSubRouteRef< Params extends { [param in string]: string; @@ -533,7 +536,7 @@ export type MakeSubRouteRef< ? SubRouteRef>> : never; -// @public +// @public @deprecated export type MergeParams< P1 extends { [param in string]: string; @@ -606,30 +609,30 @@ export type OpenIdConnectApi = { getIdToken(options?: AuthRequestOptions): Promise; }; -// @public +// @public @deprecated export type OptionalParams< Params extends { [param in string]: string; }, > = Params[keyof Params] extends never ? undefined : Params; -// @public +// @public @deprecated export type ParamKeys = keyof Params extends never ? [] : (keyof Params)[]; -// @public +// @public @deprecated export type ParamNames = S extends `${infer Part}/${infer Rest}` ? ParamPart | ParamNames : ParamPart; -// @public +// @public @deprecated export type ParamPart = S extends `:${infer Param}` ? Param : never; -// @public +// @public @deprecated export type PathParams = { [name in ParamNames]: string; }; diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 81f77e7dcf..42f3b8b4d4 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "1.7.0-next.1", + "version": "1.7.0", "publishConfig": { "access": "public" }, @@ -54,8 +54,8 @@ "i18next": "^22.4.15" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -64,8 +64,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0" }, "files": [ diff --git a/packages/core-plugin-api/src/alpha.ts b/packages/core-plugin-api/src/alpha.ts index ebcbcf34c0..540b4ed22a 100644 --- a/packages/core-plugin-api/src/alpha.ts +++ b/packages/core-plugin-api/src/alpha.ts @@ -16,3 +16,4 @@ export * from './translation'; export * from './apis/alpha'; +export { convertLegacyRouteRef } from './routing/convertLegacyRouteRef'; diff --git a/packages/core-plugin-api/src/analytics/AnalyticsContext.test.tsx b/packages/core-plugin-api/src/analytics/AnalyticsContext.test.tsx index 88e8afa6ef..c29ec5b3ca 100644 --- a/packages/core-plugin-api/src/analytics/AnalyticsContext.test.tsx +++ b/packages/core-plugin-api/src/analytics/AnalyticsContext.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { AnalyticsContext, useAnalyticsContext } from './AnalyticsContext'; const AnalyticsSpy = () => { diff --git a/packages/core-plugin-api/src/analytics/useAnalytics.test.tsx b/packages/core-plugin-api/src/analytics/useAnalytics.test.tsx index 22021026af..037e585430 100644 --- a/packages/core-plugin-api/src/analytics/useAnalytics.test.tsx +++ b/packages/core-plugin-api/src/analytics/useAnalytics.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useAnalytics } from './useAnalytics'; import { useApi } from '../apis'; diff --git a/packages/core-plugin-api/src/apis/system/useApi.test.tsx b/packages/core-plugin-api/src/apis/system/useApi.test.tsx index 6f473d8f59..4b9d80fb62 100644 --- a/packages/core-plugin-api/src/apis/system/useApi.test.tsx +++ b/packages/core-plugin-api/src/apis/system/useApi.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createVersionedContextForTesting } from '@backstage/version-bridge'; import { createApiRef } from './ApiRef'; import { useApi } from './useApi'; diff --git a/packages/core-plugin-api/src/app/useApp.test.tsx b/packages/core-plugin-api/src/app/useApp.test.tsx index f2e330e847..34c956138e 100644 --- a/packages/core-plugin-api/src/app/useApp.test.tsx +++ b/packages/core-plugin-api/src/app/useApp.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createVersionedContextForTesting } from '@backstage/version-bridge'; import { useApp } from './useApp'; diff --git a/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx b/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx index 9a3760d019..8597274e35 100644 --- a/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx +++ b/packages/core-plugin-api/src/extensions/useElementFilter.test.tsx @@ -15,7 +15,7 @@ */ import React, { ReactNode } from 'react'; import { useElementFilter } from './useElementFilter'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { attachComponentData } from './componentData'; import { featureFlagsApiRef } from '../apis'; import { LocalStorageFeatureFlags } from '@backstage/core-app-api'; @@ -316,23 +316,23 @@ describe('useElementFilter', () => { ); - const { result } = renderHook( - props => - useElementFilter(props.tree, elements => - elements - .selectByComponentData({ - key: WRAPPING_COMPONENT_KEY, - withStrictError: 'Could not find component', - }) - .findComponentData({ key: INNER_COMPONENT_KEY }), - ), - { - initialProps: { tree }, - wrapper: Wrapper, - }, - ); - - expect(result.error?.message).toEqual('Could not find component'); + expect(() => + renderHook( + props => + useElementFilter(props.tree, elements => + elements + .selectByComponentData({ + key: WRAPPING_COMPONENT_KEY, + withStrictError: 'Could not find component', + }) + .findComponentData({ key: INNER_COMPONENT_KEY }), + ), + { + initialProps: { tree }, + wrapper: Wrapper, + }, + ), + ).toThrow('Could not find component'); }); it('should support fragments and text node iteration', () => { diff --git a/packages/core-plugin-api/src/routing/SubRouteRef.ts b/packages/core-plugin-api/src/routing/SubRouteRef.ts index 14a614c2ba..b08368d74e 100644 --- a/packages/core-plugin-api/src/routing/SubRouteRef.ts +++ b/packages/core-plugin-api/src/routing/SubRouteRef.ts @@ -51,6 +51,7 @@ export class SubRouteRefImpl /** * Used in {@link PathParams} type declaration. * @public + * @deprecated this type is deprecated and will be removed in the future */ export type ParamPart = S extends `:${infer Param}` ? Param @@ -59,6 +60,7 @@ export type ParamPart = S extends `:${infer Param}` /** * Used in {@link PathParams} type declaration. * @public + * @deprecated this type is deprecated and will be removed in the future */ export type ParamNames = S extends `${infer Part}/${infer Rest}` @@ -68,12 +70,14 @@ export type ParamNames = * This utility type helps us infer a Param object type from a string path * For example, `/foo/:bar/:baz` inferred to `{ bar: string, baz: string }` * @public + * @deprecated this type is deprecated and will be removed in the future */ export type PathParams = { [name in ParamNames]: string }; /** * Merges a param object type with an optional params type into a params object. * @public + * @deprecated this type is deprecated and will be removed in the future */ export type MergeParams< P1 extends { [param in string]: string }, @@ -85,6 +89,7 @@ export type MergeParams< * The parameters types are merged together while ensuring that there is no overlap between the two. * * @public + * @deprecated this type is deprecated and will be removed in the future */ export type MakeSubRouteRef< Params extends { [param in string]: string }, diff --git a/packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts b/packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts new file mode 100644 index 0000000000..940a4174a9 --- /dev/null +++ b/packages/core-plugin-api/src/routing/convertLegacyRouteRef.ts @@ -0,0 +1,188 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { routeRefType } from './types'; +import { + RouteRef as LegacyRouteRef, + SubRouteRef as LegacySubRouteRef, + ExternalRouteRef as LegacyExternalRouteRef, + AnyRouteRefParams, +} from '@backstage/core-plugin-api'; + +// Relative imports to avoid dependency, at least for now + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { + RouteRef, + SubRouteRef, + ExternalRouteRef, + createRouteRef, + createSubRouteRef, + createExternalRouteRef, +} from '../../../frontend-plugin-api/src/routing'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalRouteRef } from '../../../frontend-plugin-api/src/routing/RouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalSubRouteRef } from '../../../frontend-plugin-api/src/routing/SubRouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExternalRouteRef } from '../../../frontend-plugin-api/src/routing/ExternalRouteRef'; + +// TODO(Rugvip): Once this is moved to a compat package these aliases can be removed and imported from frontend- instead + +/** @ignore */ +type NewRouteRef = + RouteRef; + +/** @ignore */ +type NewSubRouteRef = + SubRouteRef; + +/** @ignore */ +type NewExternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, + TOptional extends boolean = boolean, +> = ExternalRouteRef; + +/** + * A temporary helper to convert a legacy route ref to the new system. + * + * @public + * @remarks + * + * In the future the legacy createRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef( + ref: LegacyRouteRef, +): NewRouteRef; + +/** + * A temporary helper to convert a legacy sub route ref to the new system. + * + * @public + * @remarks + * + * In the future the legacy createSubRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef( + ref: LegacySubRouteRef, +): NewSubRouteRef; + +/** + * A temporary helper to convert a legacy external route ref to the new system. + * + * @public + * @remarks + * + * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems. + */ +export function convertLegacyRouteRef< + TParams extends AnyRouteRefParams, + TOptional extends boolean, +>( + ref: LegacyExternalRouteRef, +): NewExternalRouteRef; + +export function convertLegacyRouteRef( + ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef, +): NewRouteRef | NewSubRouteRef | NewExternalRouteRef { + // Ref has already been converted + if ('$$type' in ref) { + return ref as unknown as NewRouteRef | NewSubRouteRef | NewExternalRouteRef; + } + + const type = (ref as unknown as { [routeRefType]: unknown })[routeRefType]; + + if (type === 'absolute') { + const legacyRef = ref as LegacyRouteRef; + const newRef = toInternalRouteRef( + createRouteRef<{ [key in string]: string }>({ + params: legacyRef.params as string[], + }), + ); + return Object.assign(legacyRef, { + $$type: '@backstage/RouteRef' as const, + version: 'v1', + T: newRef.T, + getParams() { + return newRef.getParams(); + }, + getDescription() { + return newRef.getDescription(); + }, + setId(id: string) { + newRef.setId(id); + }, + toString() { + return newRef.toString(); + }, + }); + } + if (type === 'sub') { + const legacyRef = ref as LegacySubRouteRef; + const newRef = toInternalSubRouteRef( + createSubRouteRef({ + path: legacyRef.path, + parent: convertLegacyRouteRef(legacyRef.parent), + }), + ); + return Object.assign(legacyRef, { + $$type: '@backstage/SubRouteRef' as const, + version: 'v1', + T: newRef.T, + getParams() { + return newRef.getParams(); + }, + getParent() { + return newRef.getParent(); + }, + getDescription() { + return newRef.getDescription(); + }, + toString() { + return newRef.toString(); + }, + }); + } + if (type === 'external') { + const legacyRef = ref as LegacyExternalRouteRef; + const newRef = toInternalExternalRouteRef( + createExternalRouteRef<{ [key in string]: string }>({ + params: legacyRef.params as string[], + optional: legacyRef.optional, + }), + ); + return Object.assign(legacyRef, { + $$type: '@backstage/ExternalRouteRef' as const, + version: 'v1', + T: newRef.T, + optional: newRef.optional, + getParams() { + return newRef.getParams(); + }, + getDescription() { + return newRef.getDescription(); + }, + setId(id: string) { + newRef.setId(id); + }, + toString() { + return newRef.toString(); + }, + }); + } + + throw new Error(`Failed to convert legacy route ref, unknown type '${type}'`); +} diff --git a/packages/core-plugin-api/src/routing/index.ts b/packages/core-plugin-api/src/routing/index.ts index 01d69cd4b0..4f8b12ec73 100644 --- a/packages/core-plugin-api/src/routing/index.ts +++ b/packages/core-plugin-api/src/routing/index.ts @@ -16,6 +16,7 @@ export type { AnyParams, + AnyRouteRefParams, RouteRef, SubRouteRef, ExternalRouteRef, diff --git a/packages/core-plugin-api/src/routing/types.ts b/packages/core-plugin-api/src/routing/types.ts index 80653518bb..32f26f19c1 100644 --- a/packages/core-plugin-api/src/routing/types.ts +++ b/packages/core-plugin-api/src/routing/types.ts @@ -21,12 +21,19 @@ import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; * * @public */ -export type AnyParams = { [param in string]: string } | undefined; +export type AnyRouteRefParams = { [param in string]: string } | undefined; + +/** + * @deprecated use {@link AnyRouteRefParams} instead + * @public + */ +export type AnyParams = AnyRouteRefParams; /** * Type describing the key type of a route parameter mapping. * * @public + * @deprecated this type is deprecated and will be removed in the future */ export type ParamKeys = keyof Params extends never ? [] @@ -36,6 +43,7 @@ export type ParamKeys = keyof Params extends never * Optional route params. * * @public + * @deprecated this type is deprecated and will be removed in the future */ export type OptionalParams = Params[keyof Params] extends never ? undefined : Params; @@ -81,8 +89,10 @@ export const routeRefType: unique symbol = getOrCreateGlobalSingleton( * @public */ export type RouteRef = { + /** @deprecated access to this property will be removed in the future */ $$routeRefType: 'absolute'; // See routeRefType above + /** @deprecated access to this property will be removed in the future */ params: ParamKeys; }; @@ -96,12 +106,15 @@ export type RouteRef = { * @public */ export type SubRouteRef = { + /** @deprecated access to this property will be removed in the future */ $$routeRefType: 'sub'; // See routeRefType above + /** @deprecated access to this property will be removed in the future */ parent: RouteRef; path: string; + /** @deprecated access to this property will be removed in the future */ params: ParamKeys; }; @@ -118,8 +131,10 @@ export type ExternalRouteRef< Params extends AnyParams = any, Optional extends boolean = any, > = { + /** @deprecated access to this property will be removed in the future */ $$routeRefType: 'external'; // See routeRefType above + /** @deprecated access to this property will be removed in the future */ params: ParamKeys; optional?: Optional; diff --git a/packages/core-plugin-api/src/routing/useRouteRef.test.tsx b/packages/core-plugin-api/src/routing/useRouteRef.test.tsx index 7a03a1cdc4..b302fa6441 100644 --- a/packages/core-plugin-api/src/routing/useRouteRef.test.tsx +++ b/packages/core-plugin-api/src/routing/useRouteRef.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { MemoryRouter, Router } from 'react-router-dom'; import { createVersionedContextForTesting } from '@backstage/version-bridge'; diff --git a/packages/core-plugin-api/src/translation/useTranslationRef.test.tsx b/packages/core-plugin-api/src/translation/useTranslationRef.test.tsx index 19f0516906..a7493152de 100644 --- a/packages/core-plugin-api/src/translation/useTranslationRef.test.tsx +++ b/packages/core-plugin-api/src/translation/useTranslationRef.test.tsx @@ -20,7 +20,7 @@ import { TestApiProvider, withLogCollector, } from '@backstage/test-utils'; -import { renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import { createTranslationRef, TranslationRef } from './TranslationRef'; import { useTranslationRef } from './useTranslationRef'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -91,19 +91,15 @@ describe('useTranslationRef', () => { ], }); - const { result, waitForNextUpdate } = renderHook( - () => useTranslationRef(plainRef), - { - wrapper: makeWrapper(translationApi), - }, - ); + const { result } = renderHook(() => useTranslationRef(plainRef), { + wrapper: makeWrapper(translationApi), + }); - await waitForNextUpdate(); - - const { t } = result.current; - - expect(t('key1')).toBe('en1'); - expect(t('key2')).toBe('en2'); + await waitFor(() => { + const { t } = result.current; + expect(t('key1')).toBe('en1'); + expect(t('key2')).toBe('en2'); + }); }); it('should switch between languages', async () => { @@ -123,26 +119,25 @@ describe('useTranslationRef', () => { ], }); - const { result, waitForNextUpdate } = renderHook( - () => useTranslationRef(plainRef), - { - wrapper: makeWrapper(translationApi), - }, - ); + const { result } = renderHook(() => useTranslationRef(plainRef), { + wrapper: makeWrapper(translationApi), + }); - const { t } = result.current; + await waitFor(() => { + const { t } = result.current; - expect(t('key1')).toBe('default1'); - expect(t('key2')).toBe('default2'); + expect(t('key1')).toBe('default1'); + expect(t('key2')).toBe('default2'); + }); languageApi.setLanguage('de'); - await waitForNextUpdate(); + await waitFor(() => { + const { t: t2 } = result.current; - const { t: t2 } = result.current; - - expect(t2('key1')).toBe('de1'); - expect(t2('key2')).toBe('de2'); + expect(t2('key1')).toBe('de1'); + expect(t2('key2')).toBe('de2'); + }); }); it('should load default resource', async () => { @@ -165,19 +160,16 @@ describe('useTranslationRef', () => { languageApi, }); - const { result, waitForNextUpdate } = renderHook( - () => useTranslationRef(resourceRef), - { - wrapper: makeWrapper(translationApi), - }, - ); + const { result } = renderHook(() => useTranslationRef(resourceRef), { + wrapper: makeWrapper(translationApi), + }); - await waitForNextUpdate(); + await waitFor(() => { + const { t } = result.current; - const { t } = result.current; - - expect(t('key1')).toBe('de1'); - expect(t('key2')).toBe('de2'); + expect(t('key1')).toBe('de1'); + expect(t('key2')).toBe('de2'); + }); }); it('should log once and then ignore loading errors', async () => { @@ -212,7 +204,7 @@ describe('useTranslationRef', () => { }); const { error } = await withLogCollector(['error'], async () => { - await rendered2.waitForNextUpdate(); + await act(rendered2.rerender); }); const msg = diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 2ad4280db0..25728675d6 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/create-app +## 0.5.6 + +### Patch Changes + +- ba6a3b59c1: Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. +- c8ec0dea4a: Create unique temp directory for each `create-app` execution. +- e43d3eb1b7: Bumped create-app version. +- b665f2ce65: Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. + + You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` + +- deed089a3d: Bump `cypress` to fix the end-to-end tests +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 04a3f65e15: Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. + + You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` + +- 9864f263ba: Bump dev dependencies `lerna@7.3.0` on the template +- 5eacd5d213: The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. + + The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. + + The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. + +- 8d2e640af4: Added missing `.eslintignore` file + + To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: + + ```diff + + playwright.config.ts + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.13 + ## 0.5.6-next.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 467ceb1cfe..597908c894 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.5.6-next.2", + "version": "0.5.6", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index 09cede933d..af6b0c9c70 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -129,7 +129,7 @@ export default async (opts: OptionValues): Promise => { ); Task.log(); Task.section('All set! Now you might want to'); - if (!opts.skipInstall) { + if (opts.skipInstall) { Task.log( ` Install the dependencies: ${chalk.cyan( `cd ${opts.path ?? answers.name} && yarn install`, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 3869ee9281..3bb6f8e324 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/dev-utils +## 1.0.22 + +### Patch Changes + +- 080d1beb2a: Moving development `dependencies` to `devDependencies` +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 9468a67b92: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/app-defaults@1.4.4 + - @backstage/theme@0.4.3 + ## 1.0.22-next.2 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index bbb55d9b14..d860d67070 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.22-next.2", + "version": "1.0.22", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "zen-observable": "^0.10.0" }, diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index 335308ff5e..ccb1cca2e8 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -49,14 +49,13 @@ import { createRoutesFromChildren, Route } from 'react-router-dom'; import { SidebarThemeSwitcher } from './SidebarThemeSwitcher'; import 'react-dom'; -let ReactDOM: - | typeof import('react-dom') - // TODO: replace with import('react-dom/client') when repo is migrated to 18 - | { createRoot(el: HTMLElement): { render(el: JSX.Element): void } }; +let ReactDOMPromise: Promise< + typeof import('react-dom') | typeof import('react-dom/client') +>; if (process.env.HAS_REACT_DOM_CLIENT) { - ReactDOM = require('react-dom/client'); + ReactDOMPromise = import('react-dom/client'); } else { - ReactDOM = require('react-dom'); + ReactDOMPromise = import('react-dom'); } export function isReactRouterBeta(): boolean { @@ -245,11 +244,15 @@ export class DevAppBuilder { window.location.pathname = this.defaultPage; } - if ('createRoot' in ReactDOM) { - ReactDOM.createRoot(document.getElementById('root')!).render(); - } else { - ReactDOM.render(, document.getElementById('root')); - } + ReactDOMPromise.then(ReactDOM => { + if ('createRoot' in ReactDOM) { + ReactDOM.createRoot(document.getElementById('root')!).render( + , + ); + } else { + ReactDOM.render(, document.getElementById('root')); + } + }); } } diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md index de15b39751..914644a9f6 100644 --- a/packages/e2e-test-utils/CHANGELOG.md +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/e2e-test-utils +## 0.1.0 + +### Minor Changes + +- f5b41b27a9: Initial release. + ## 0.1.0-next.0 ### Minor Changes diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index fcbae56796..3448497395 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/e2e-test-utils", "description": "Shared end-to-end test utilities Backstage", - "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/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 846f7e62a4..37d8b1d24a 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.8 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + ## 0.2.8-next.2 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 9d5654098d..f6e90e116e 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.8-next.2", + "version": "0.2.8", "private": true, "backstage": { "role": "cli" diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index 2568ca095e..92655a25d8 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/errors +## 1.2.3 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/types@1.1.1 + ## 1.2.3-next.0 ### Patch Changes diff --git a/packages/errors/package.json b/packages/errors/package.json index c064765aca..7dc17a10a2 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.2.3-next.0", + "version": "1.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 12983fdcd6..96bf43f73c 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/frontend-app-api +## 0.2.0 + +### Minor Changes + +- 4461d87d5a: Removed support for the new `useRouteRef`. +- 9d03dfe5e3: The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. +- d7c5d80c57: The hidden `'root'` extension has been removed and has instead been made an input of the `'core'` extension. The checks for rejecting configuration of the `'root'` extension to rejects configuration of the `'core'` extension instead. +- d920b8c343: Added support for installing `ExtensionOverrides` via `createApp` options. As part of this change the `plugins` option has been renamed to `features`, and the `pluginLoader` has been renamed to `featureLoader`. + +### Patch Changes + +- 322bbcae24: Internal update for removal of experimental plugin configuration API. +- f78ac58f88: Filters for discovered packages are now also applied at runtime. This makes it possible to disable packages through the `app.experimental.packages` config at runtime. +- 68ffb9e67d: The app will now reject any extensions that attach to nonexistent inputs. +- 5072824817: Implement `toString()` and `toJSON()` for extension instances. +- 1e60a9c3a5: Fixed an issue preventing the routing system to match subroutes +- 52366db5b3: Make themes configurable through extensions, and switched default themes to use extensions instead. +- 2ecd33618a: Added the `bindRoutes` option to `createApp`. +- e5a2956dd2: Register default api implementations when creating declarative integrated apps. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 06432f900c: Updates for `at` -> `attachTo` refactor. +- 1718ec75b7: Added support for the existing routing system. +- 66d51a4827: Prevents root extension override and duplicated plugin extensions. +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-graphiql@0.2.55 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.0-next.2 ### Minor Changes diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 74c34be5f4..11c9ac03c5 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -3,13 +3,28 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AppRouteBinder } from '@backstage/core-app-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Config } from '@backstage/config'; import { ConfigApi } from '@backstage/core-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; +import { RouteRef } from '@backstage/frontend-plugin-api'; +import { SubRouteRef } from '@backstage/frontend-plugin-api'; + +// @public +export type AppRouteBinder = < + TExternalRoutes extends { + [name: string]: ExternalRouteRef; + }, +>( + externalRoutes: TExternalRoutes, + targetRoutes: PartialKeys< + TargetRouteMap, + KeysWithType> + >, +) => void; // @public (undocumented) export function createApp(options: { diff --git a/packages/frontend-app-api/config.d.ts b/packages/frontend-app-api/config.d.ts index 81c24d1185..28355f5376 100644 --- a/packages/frontend-app-api/config.d.ts +++ b/packages/frontend-app-api/config.d.ts @@ -16,20 +16,35 @@ export interface Config { app?: { + experimental?: { + /** + * @visibility frontend + * @deepVisibility frontend + */ + packages?: 'all' | { include?: string[]; exclude?: string[] }; + }; + + routes?: { + /** + * @deepVisibility frontend + */ + bindings?: { [externalRouteRefId: string]: string }; + }; + /** * @deepVisibility frontend */ - extensions?: + extensions?: Array< | string | { [extensionId: string]: | boolean - | string | { - at?: string; - extension?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; config?: unknown; }; - }; + } + >; }; } diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 7a1c5aa79f..d4a595707a 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.2.0-next.2", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,7 +26,7 @@ "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3" + "@testing-library/react": "^14.0.0" }, "configSchema": "config.d.ts", "files": [ @@ -49,7 +49,7 @@ "lodash": "^4.17.21" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" } } diff --git a/packages/frontend-app-api/src/extensions/Core.tsx b/packages/frontend-app-api/src/extensions/Core.tsx index 6efe3984dc..f48aa2ea6b 100644 --- a/packages/frontend-app-api/src/extensions/Core.tsx +++ b/packages/frontend-app-api/src/extensions/Core.tsx @@ -22,7 +22,7 @@ import { export const Core = createExtension({ id: 'core', - attachTo: { id: 'root', input: 'default' }, + attachTo: { id: 'root', input: 'default' }, // ignored inputs: { apis: createExtensionInput({ api: coreExtensionData.apiFactory, diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 3406c1d637..cd12ca129a 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -20,8 +20,8 @@ import { coreExtensionData, createExtensionInput, NavTarget, + useRouteRef, } from '@backstage/frontend-plugin-api'; -import { useRouteRef } from '@backstage/core-plugin-api'; import { makeStyles } from '@material-ui/core'; import { Sidebar, @@ -66,7 +66,7 @@ const SidebarLogo = () => { const SidebarNavItem = (props: NavTarget) => { const { icon: Icon, title, routeRef } = props; - const to = useRouteRef(routeRef)({}); + const to = useRouteRef(routeRef)(); // TODO: Support opening modal, for example, the search one return ; }; diff --git a/packages/frontend-app-api/src/graph/createAppGraph.test.ts b/packages/frontend-app-api/src/graph/createAppGraph.test.ts new file mode 100644 index 0000000000..2c9f062199 --- /dev/null +++ b/packages/frontend-app-api/src/graph/createAppGraph.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createExtension, + createExtensionOverrides, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { MockConfigApi } from '@backstage/test-utils'; +import { createAppGraph } from './createAppGraph'; + +const extBase = { + id: 'test', + attachTo: { id: 'core', input: 'root' }, + output: {}, + factory() {}, +}; + +describe('createAppGraph', () => { + it('throws an error when a core extension is parametrized', () => { + const config = new MockConfigApi({ + app: { + extensions: [ + { + core: {}, + }, + ], + }, + }); + const features = [ + createPlugin({ + id: 'plugin', + extensions: [], + }), + ]; + expect(() => + createAppGraph({ features, config, builtinExtensions: [] }), + ).toThrow("Configuration of the 'core' extension is forbidden"); + }); + + it('throws an error when a core extension is overridden', () => { + const config = new MockConfigApi({}); + const features = [ + createPlugin({ + id: 'plugin', + extensions: [ + createExtension({ + id: 'core', + attachTo: { id: 'core.routes', input: 'route' }, + inputs: {}, + output: {}, + factory() {}, + }), + ], + }), + ]; + expect(() => + createAppGraph({ features, config, builtinExtensions: [] }), + ).toThrow( + "It is forbidden to override the following extension(s): 'core', which is done by the following plugin(s): 'plugin'", + ); + }); + + it('throws an error when duplicated extensions are detected', () => { + const config = new MockConfigApi({}); + + const ExtensionA = createExtension({ ...extBase, id: 'A' }); + + const ExtensionB = createExtension({ ...extBase, id: 'B' }); + + const PluginA = createPlugin({ + id: 'A', + extensions: [ExtensionA, ExtensionA], + }); + + const PluginB = createPlugin({ + id: 'B', + extensions: [ExtensionA, ExtensionB, ExtensionB], + }); + + const features = [PluginA, PluginB]; + + expect(() => + createAppGraph({ features, config, builtinExtensions: [] }), + ).toThrow( + "The following extensions are duplicated: The extension 'A' was provided 2 time(s) by the plugin 'A' and 1 time(s) by the plugin 'B', The extension 'B' was provided 2 time(s) by the plugin 'B'", + ); + }); + + it('throws an error when duplicated extension overrides are detected', () => { + expect(() => + createAppGraph({ + features: [ + createExtensionOverrides({ + extensions: [ + createExtension({ ...extBase, id: 'a' }), + createExtension({ ...extBase, id: 'a' }), + createExtension({ ...extBase, id: 'b' }), + ], + }), + createExtensionOverrides({ + extensions: [createExtension({ ...extBase, id: 'b' })], + }), + ], + config: new MockConfigApi({}), + builtinExtensions: [], + }), + ).toThrow('The following extensions had duplicate overrides: a, b'); + }); +}); diff --git a/packages/frontend-app-api/src/graph/createAppGraph.ts b/packages/frontend-app-api/src/graph/createAppGraph.ts new file mode 100644 index 0000000000..ace8595f53 --- /dev/null +++ b/packages/frontend-app-api/src/graph/createAppGraph.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + BackstagePlugin, + Extension, + ExtensionOverrides, +} from '@backstage/frontend-plugin-api'; +import { readAppExtensionsConfig } from './readAppExtensionsConfig'; +import { resolveAppGraph } from './resolveAppGraph'; +import { resolveAppNodeSpecs } from './resolveAppNodeSpecs'; +import { AppGraph } from './types'; +import { Config } from '@backstage/config'; +import { instantiateAppNodeTree } from './instantiateAppNodeTree'; + +/** @internal */ +export interface CreateAppGraphOptions { + features: (BackstagePlugin | ExtensionOverrides)[]; + builtinExtensions: Extension[]; + config: Config; +} + +/** @internal */ +export function createAppGraph(options: CreateAppGraphOptions): AppGraph { + const appGraph = resolveAppGraph( + 'core', + resolveAppNodeSpecs({ + features: options.features, + builtinExtensions: options.builtinExtensions, + parameters: readAppExtensionsConfig(options.config), + forbidden: new Set(['core']), + }), + ); + instantiateAppNodeTree(appGraph.root); + return appGraph; +} diff --git a/packages/frontend-app-api/src/graph/index.ts b/packages/frontend-app-api/src/graph/index.ts new file mode 100644 index 0000000000..4a3b54dffb --- /dev/null +++ b/packages/frontend-app-api/src/graph/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { + AppNode, + AppNodeEdges, + AppNodeInstance, + AppNodeSpec, +} from './types'; +export { createAppGraph } from './createAppGraph'; diff --git a/packages/frontend-app-api/src/graph/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/graph/instantiateAppNodeTree.test.ts new file mode 100644 index 0000000000..21f364dda2 --- /dev/null +++ b/packages/frontend-app-api/src/graph/instantiateAppNodeTree.test.ts @@ -0,0 +1,554 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Extension, + createExtension, + createExtensionDataRef, + createExtensionInput, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { + createAppNodeInstance, + instantiateAppNodeTree, +} from './instantiateAppNodeTree'; +import { AppNodeInstance, AppNodeSpec } from './types'; +import { resolveAppGraph } from './resolveAppGraph'; + +const testDataRef = createExtensionDataRef('test'); +const otherDataRef = createExtensionDataRef('other'); +const inputMirrorDataRef = createExtensionDataRef('mirror'); + +const simpleExtension = createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + other: otherDataRef.optional(), + }, + configSchema: createSchemaFromZod(z => + z.object({ + output: z.string().default('test'), + other: z.number().optional(), + }), + ), + factory({ bind, config }) { + bind({ test: config.output, other: config.other }); + }, +}); + +function makeSpec( + extension: Extension, + config?: TConfig, +): AppNodeSpec { + return { + id: extension.id, + attachTo: extension.attachTo, + disabled: extension.disabled, + extension, + config, + source: undefined, + }; +} + +function makeInstanceWithId( + extension: Extension, + config?: TConfig, +): { id: string; instance: AppNodeInstance } { + return { + id: extension.id, + instance: createAppNodeInstance({ + spec: makeSpec(extension, config), + attachments: new Map(), + }), + }; +} + +describe('instantiateAppNodeTree', () => { + it('should instantiate a single node', () => { + const graph = resolveAppGraph('root-node', [ + { ...makeSpec(simpleExtension), id: 'root-node' }, + ]); + expect(graph.root.instance).not.toBeDefined(); + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).toBeDefined(); + expect(graph.root.instance?.getData(testDataRef)).toBe('test'); + + // Multiple calls should have no effect + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).toBeDefined(); + }); + + it('should not instantiate disabled nodes', () => { + const graph = resolveAppGraph('root-node', [ + { ...makeSpec(simpleExtension), id: 'root-node', disabled: true }, + ]); + expect(graph.root.instance).not.toBeDefined(); + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).not.toBeDefined(); + }); + + it('should instantiate a node with attachments', () => { + const graph = resolveAppGraph('root-node', [ + { + ...makeSpec( + createExtension({ + id: 'root-node', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + test: createExtensionInput({ test: testDataRef }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ bind, inputs }) { + bind({ inputMirror: inputs }); + }, + }), + ), + }, + { + ...makeSpec(simpleExtension), + id: 'child-node', + attachTo: { id: 'root-node', input: 'test' }, + }, + ]); + + const childNode = graph.nodes.get('child-node'); + expect(childNode).toBeDefined(); + + expect(graph.root.instance).not.toBeDefined(); + expect(childNode?.instance).not.toBeDefined(); + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).toBeDefined(); + expect(childNode?.instance).toBeDefined(); + expect(graph.root.instance?.getData(inputMirrorDataRef)).toEqual({ + test: [{ test: 'test' }], + }); + + // Multiple calls should have no effect + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).toBeDefined(); + expect(childNode?.instance).toBeDefined(); + }); + + it('should not instantiate disabled attachments', () => { + const graph = resolveAppGraph('root-node', [ + { + ...makeSpec( + createExtension({ + id: 'root-node', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + test: createExtensionInput({ test: testDataRef }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ bind, inputs }) { + bind({ inputMirror: inputs }); + }, + }), + ), + }, + { + ...makeSpec(simpleExtension), + id: 'child-node', + attachTo: { id: 'root-node', input: 'test' }, + disabled: true, + }, + ]); + + const childNode = graph.nodes.get('child-node'); + expect(childNode).toBeDefined(); + + expect(graph.root.instance).not.toBeDefined(); + expect(childNode?.instance).not.toBeDefined(); + instantiateAppNodeTree(graph.root); + expect(graph.root.instance).toBeDefined(); + expect(childNode?.instance).not.toBeDefined(); + expect(graph.root.instance?.getData(inputMirrorDataRef)).toEqual({ + test: [], + }); + }); +}); + +describe('createAppNodeInstance', () => { + it('should create a simple extension instance', () => { + const attachments = new Map(); + const instance = createAppNodeInstance({ + spec: makeSpec(simpleExtension), + attachments, + }); + + expect(Array.from(instance.getDataRefs())).toEqual([ + testDataRef, + otherDataRef.optional(), + ]); + expect(instance.getData(testDataRef)).toEqual('test'); + }); + + it('should create an extension with different kind of inputs', () => { + const attachments = new Map([ + [ + 'optionalSingletonPresent', + [ + makeInstanceWithId(simpleExtension, { + output: 'optionalSingletonPresent', + }), + ], + ], + [ + 'singleton', + [ + makeInstanceWithId(simpleExtension, { + output: 'singleton', + other: 2, + }), + ], + ], + [ + 'many', + [ + makeInstanceWithId(simpleExtension, { output: 'many1' }), + makeInstanceWithId(simpleExtension, { output: 'many2', other: 3 }), + ], + ], + ]); + const instance = createAppNodeInstance({ + attachments, + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + optionalSingletonPresent: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + optionalSingletonMissing: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true, optional: true }, + ), + singleton: createExtensionInput( + { + test: testDataRef, + other: otherDataRef.optional(), + }, + { singleton: true }, + ), + many: createExtensionInput({ + test: testDataRef, + other: otherDataRef.optional(), + }), + }, + output: { + inputMirror: inputMirrorDataRef, + }, + factory({ bind, inputs }) { + bind({ inputMirror: inputs }); + }, + }), + ), + }); + + expect(Array.from(instance.getDataRefs())).toEqual([inputMirrorDataRef]); + expect(instance.getData(inputMirrorDataRef)).toEqual({ + optionalSingletonPresent: { test: 'optionalSingletonPresent' }, + singleton: { test: 'singleton', other: 2 }, + many: [{ test: 'many1' }, { test: 'many2', other: 3 }], + }); + }); + + it('should refuse to create an extension with invalid config', () => { + expect(() => + createAppNodeInstance({ + spec: { + ...makeSpec(simpleExtension), + config: { other: 'not-a-number' }, + }, + attachments: new Map(), + }), + ).toThrow( + "Invalid configuration for extension 'core.test'; caused by Error: Expected number, received string at 'other'", + ); + }); + + it('should forward extension factory errors', () => { + expect(() => + createAppNodeInstance({ + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory() { + const error = new Error('NOPE'); + error.name = 'NopeError'; + throw error; + }, + }), + ), + attachments: new Map(), + }), + ).toThrow( + "Failed to instantiate extension 'core.test'; caused by NopeError: NOPE", + ); + }); + + it('should refuse to create an instance with duplicate output', () => { + expect(() => + createAppNodeInstance({ + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test1: testDataRef, + test2: testDataRef, + }, + factory({ bind }) { + bind({ test1: 'test', test2: 'test2' }); + }, + }), + ), + attachments: new Map(), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', duplicate extension data 'test' received via output 'test2'", + ); + }); + + it('should refuse to create an instance with disconnected output data', () => { + expect(() => + createAppNodeInstance({ + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: { + test: testDataRef, + }, + factory({ bind }) { + bind({ nonexistent: 'test' } as any); + }, + }), + ), + attachments: new Map(), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', unknown output provided via 'nonexistent'", + ); + }); + + it('should refuse to create an instance with missing required input', () => { + expect(() => + createAppNodeInstance({ + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory() {}, + }), + ), + attachments: new Map(), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', input 'singleton' is required but was not received", + ); + }); + + it('should refuse to create an instance with undeclared inputs', () => { + expect(() => + createAppNodeInstance({ + attachments: new Map([ + [ + 'declared', + [ + makeInstanceWithId(simpleExtension, { + output: 'many1', + }), + ], + ], + [ + 'undeclared', + [ + makeInstanceWithId(simpleExtension, { + output: 'many1', + }), + ], + ], + ]), + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + declared: createExtensionInput({ + test: testDataRef, + }), + }, + output: {}, + factory() {}, + }), + ), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', received undeclared input 'undeclared' from extension 'core.test'", + ); + }); + + it('should refuse to create an instance with multiple undeclared inputs', () => { + expect(() => + createAppNodeInstance({ + attachments: new Map([ + [ + 'undeclared1', + [makeInstanceWithId(simpleExtension, { output: 'many1' })], + ], + [ + 'undeclared2', + [ + makeInstanceWithId(simpleExtension, { output: 'many1' }), + makeInstanceWithId(simpleExtension, { output: 'many1' }), + ], + ], + ]), + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + output: {}, + factory() {}, + }), + ), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', received undeclared inputs 'undeclared1' from extension 'core.test' and 'undeclared2' from extensions 'core.test', 'core.test'", + ); + }); + + it('should refuse to create an instance with multiple inputs for required singleton', () => { + expect(() => + createAppNodeInstance({ + attachments: new Map([ + [ + 'singleton', + [ + makeInstanceWithId(simpleExtension, { output: 'many1' }), + makeInstanceWithId(simpleExtension, { output: 'many2' }), + ], + ], + ]), + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory() {}, + }), + ), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', expected exactly one 'singleton' input but received multiple: 'core.test', 'core.test'", + ); + }); + + it('should refuse to create an instance with multiple inputs for optional singleton', () => { + expect(() => + createAppNodeInstance({ + attachments: new Map([ + [ + 'singleton', + [ + makeInstanceWithId(simpleExtension, { output: 'many1' }), + makeInstanceWithId(simpleExtension, { output: 'many2' }), + ], + ], + ]), + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + test: testDataRef, + }, + { singleton: true, optional: true }, + ), + }, + output: {}, + factory() {}, + }), + ), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', expected at most one 'singleton' input but received multiple: 'core.test', 'core.test'", + ); + }); + + it('should refuse to create an instance with multiple inputs that did not provide required data', () => { + expect(() => + createAppNodeInstance({ + attachments: new Map([ + ['singleton', [makeInstanceWithId(simpleExtension, undefined)]], + ]), + spec: makeSpec( + createExtension({ + id: 'core.test', + attachTo: { id: 'ignored', input: 'ignored' }, + inputs: { + singleton: createExtensionInput( + { + other: otherDataRef, + }, + { singleton: true }, + ), + }, + output: {}, + factory() {}, + }), + ), + }), + ).toThrow( + "Failed to instantiate extension 'core.test', input 'singleton' did not receive required extension data 'other' from extension 'core.test'", + ); + }); +}); diff --git a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts b/packages/frontend-app-api/src/graph/instantiateAppNodeTree.ts similarity index 51% rename from packages/frontend-app-api/src/wiring/createExtensionInstance.ts rename to packages/frontend-app-api/src/graph/instantiateAppNodeTree.ts index 5a325dc0a0..ba0c85692e 100644 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts +++ b/packages/frontend-app-api/src/graph/instantiateAppNodeTree.ts @@ -17,36 +17,22 @@ import { AnyExtensionDataMap, AnyExtensionInputMap, - BackstagePlugin, - Extension, ExtensionDataRef, } from '@backstage/frontend-plugin-api'; import mapValues from 'lodash/mapValues'; +import { AppNode, AppNodeInstance, AppNodeSpec } from './types'; -/** @internal */ -export interface ExtensionInstance { - readonly $$type: '@backstage/ExtensionInstance'; - - readonly id: string; - /** - * Get concrete value for the given extension data reference. Returns undefined if no value is available. - */ - getData(ref: ExtensionDataRef): T | undefined; - /** - * Maps input names to the actual instances given to them. - */ - readonly attachments: Map; - - readonly source?: BackstagePlugin; -} +type Mutable = { + -readonly [P in keyof T]: T[P]; +}; function resolveInputData( dataMap: AnyExtensionDataMap, - attachment: ExtensionInstance, + attachment: { id: string; instance: AppNodeInstance }, inputName: string, ) { return mapValues(dataMap, ref => { - const value = attachment.getData(ref); + const value = attachment.instance.getData(ref); if (value === undefined && !ref.config.optional) { throw new Error( `input '${inputName}' did not receive required extension data '${ref.id}' from extension '${attachment.id}'`, @@ -58,11 +44,12 @@ function resolveInputData( function resolveInputs( inputMap: AnyExtensionInputMap, - attachments: Map, + attachments: ReadonlyMap, ) { const undeclaredAttachments = Array.from(attachments.entries()).filter( ([inputName]) => inputMap[inputName] === undefined, ); + // TODO: Make this a warning rather than an error if (undeclaredAttachments.length > 0) { throw new Error( `received undeclared input${ @@ -79,113 +66,49 @@ function resolveInputs( } return mapValues(inputMap, (input, inputName) => { - const attachedInstances = attachments.get(inputName) ?? []; + const attachedNodes = attachments.get(inputName) ?? []; + if (input.config.singleton) { - if (attachedInstances.length > 1) { + if (attachedNodes.length > 1) { + const attachedNodeIds = attachedNodes.map(e => e.id); throw Error( `expected ${ input.config.optional ? 'at most' : 'exactly' - } one '${inputName}' input but received multiple: '${attachedInstances - .map(e => e.id) - .join("', '")}'`, + } one '${inputName}' input but received multiple: '${attachedNodeIds.join( + "', '", + )}'`, ); - } else if (attachedInstances.length === 0) { + } else if (attachedNodes.length === 0) { if (input.config.optional) { return undefined; } throw Error(`input '${inputName}' is required but was not received`); } - return resolveInputData( - input.extensionData, - attachedInstances[0], - inputName, - ); + return resolveInputData(input.extensionData, attachedNodes[0], inputName); } - return attachedInstances.map(attachment => + return attachedNodes.map(attachment => resolveInputData(input.extensionData, attachment, inputName), ); }); } -function indent(str: string) { - return str.replace(/^/gm, ' '); -} - -class ExtensionInstanceImpl implements ExtensionInstance { - readonly $$type = '@backstage/ExtensionInstance'; - - readonly id: string; - readonly #extensionData: Map; - readonly attachments: Map; - readonly source?: BackstagePlugin; - - constructor( - id: string, - extensionData: Map, - attachments: Map, - source: BackstagePlugin | undefined, - ) { - this.id = id; - this.#extensionData = extensionData; - this.attachments = attachments; - this.source = source; - } - - getData(ref: ExtensionDataRef): T | undefined { - return this.#extensionData.get(ref.id) as T | undefined; - } - - toJSON() { - return { - id: this.id, - output: - this.#extensionData.size > 0 - ? [...this.#extensionData.keys()] - : undefined, - attachments: - this.attachments.size > 0 - ? Object.fromEntries(this.attachments) - : undefined, - }; - } - - toString() { - const out = - this.#extensionData.size > 0 - ? ` out=[${[...this.#extensionData.keys()].join(', ')}]` - : ''; - - if (this.attachments.size === 0) { - return `<${this.id}${out} />`; - } - - return [ - `<${this.id}${out}>`, - ...[...this.attachments.entries()].map(([k, v]) => - indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\n')), - ), - ``, - ].join('\n'); - } -} - /** @internal */ -export function createExtensionInstance(options: { - extension: Extension; - config: unknown; - source?: BackstagePlugin; - attachments: Map; -}): ExtensionInstance { - const { extension, config, source, attachments } = options; +export function createAppNodeInstance(options: { + spec: AppNodeSpec; + attachments: ReadonlyMap; +}): AppNodeInstance { + const { spec, attachments } = options; + const { id, extension, config, source } = spec; const extensionData = new Map(); + const extensionDataRefs = new Set>(); let parsedConfig: unknown; try { parsedConfig = extension.configSchema?.parse(config ?? {}); } catch (e) { throw new Error( - `Invalid configuration for extension '${extension.id}'; caused by ${e}`, + `Invalid configuration for extension '${id}'; caused by ${e}`, ); } @@ -205,22 +128,65 @@ export function createExtensionInstance(options: { ); } extensionData.set(ref.id, output); + extensionDataRefs.add(ref); } }, inputs: resolveInputs(extension.inputs, attachments), }); } catch (e) { throw new Error( - `Failed to instantiate extension '${extension.id}'${ + `Failed to instantiate extension '${id}'${ e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}` }`, ); } - return new ExtensionInstanceImpl( - options.extension.id, - extensionData, - attachments, - source, - ); + return { + getDataRefs() { + return extensionDataRefs.values(); + }, + getData(ref: ExtensionDataRef): T | undefined { + return extensionData.get(ref.id) as T | undefined; + }, + }; +} + +/** + * Starting at the provided node, instantiate all reachable nodes in the graph that have not been disabled. + * @internal + */ +export function instantiateAppNodeTree(rootNode: AppNode): void { + function createInstance(node: AppNode): AppNodeInstance | undefined { + if (node.instance) { + return node.instance; + } + if (node.spec.disabled) { + return undefined; + } + + const instantiatedAttachments = new Map< + string, + { id: string; instance: AppNodeInstance }[] + >(); + + for (const [input, children] of node.edges.attachments) { + const instantiatedChildren = children.flatMap(child => { + const childInstance = createInstance(child); + if (!childInstance) { + return []; + } + return [{ id: child.spec.id, instance: childInstance }]; + }); + instantiatedAttachments.set(input, instantiatedChildren); + } + + (node as Mutable).instance = createAppNodeInstance({ + spec: node.spec, + attachments: instantiatedAttachments, + }); + + return node.instance; + } + + createInstance(rootNode); } diff --git a/packages/frontend-app-api/src/wiring/parameters.test.ts b/packages/frontend-app-api/src/graph/readAppExtensionsConfig.test.ts similarity index 59% rename from packages/frontend-app-api/src/wiring/parameters.test.ts rename to packages/frontend-app-api/src/graph/readAppExtensionsConfig.test.ts index 4ee420f667..91f6992f29 100644 --- a/packages/frontend-app-api/src/wiring/parameters.test.ts +++ b/packages/frontend-app-api/src/graph/readAppExtensionsConfig.test.ts @@ -15,204 +15,16 @@ */ import { ConfigReader } from '@backstage/config'; -import { - createExtensionOverrides, - createPlugin, - Extension, -} from '@backstage/frontend-plugin-api'; import { JsonValue } from '@backstage/types'; import { expandShorthandExtensionParameters, - mergeExtensionParameters, - readAppExtensionParameters, -} from './parameters'; + readAppExtensionsConfig, +} from './readAppExtensionsConfig'; -function makeExt( - id: string, - status: 'disabled' | 'enabled' = 'enabled', - attachId: string = 'root', -) { - return { - id, - attachTo: { id: attachId, input: 'default' }, - disabled: status === 'disabled', - } as Extension; -} - -describe('mergeExtensionParameters', () => { - it('should filter out disabled extension instances', () => { - expect( - mergeExtensionParameters({ - features: [], - builtinExtensions: [makeExt('a', 'disabled')], - parameters: [], - }), - ).toEqual([]); - }); - - it('should pass through extension instances', () => { - const a = makeExt('a'); - const b = makeExt('b'); - expect( - mergeExtensionParameters({ - features: [], - builtinExtensions: [a, b], - parameters: [], - }), - ).toEqual([ - { extension: a, attachTo: { id: 'root', input: 'default' } }, - { extension: b, attachTo: { id: 'root', input: 'default' } }, - ]); - }); - - it('should override attachment points', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const pluginA = createPlugin({ id: 'test', extensions: [a] }); - expect( - mergeExtensionParameters({ - features: [pluginA], - builtinExtensions: [b], - parameters: [ - { - id: 'b', - attachTo: { id: 'derp', input: 'default' }, - }, - ], - }), - ).toEqual([ - { - extension: a, - attachTo: { id: 'root', input: 'default' }, - source: pluginA, - }, - { extension: b, attachTo: { id: 'derp', input: 'default' } }, - ]); - }); - - it('should fully override configuration and duplicate', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); - expect( - mergeExtensionParameters({ - features: [plugin], - builtinExtensions: [], - parameters: [ - { - id: 'a', - config: { foo: { bar: 1 } }, - }, - { - id: 'b', - config: { foo: { bar: 2 } }, - }, - { - id: 'b', - config: { foo: { qux: 3 } }, - }, - ], - }), - ).toEqual([ - { - extension: a, - attachTo: { id: 'root', input: 'default' }, - source: plugin, - config: { foo: { bar: 1 } }, - }, - { - extension: b, - attachTo: { id: 'root', input: 'default' }, - source: plugin, - config: { foo: { qux: 3 } }, - }, - ]); - }); - - it('should place enabled instances in the order that they were enabled', () => { - const a = makeExt('a', 'disabled'); - const b = makeExt('b', 'disabled'); - expect( - mergeExtensionParameters({ - features: [createPlugin({ id: 'empty', extensions: [] })], - builtinExtensions: [a, b], - parameters: [ - { - id: 'b', - disabled: false, - }, - { - id: 'a', - disabled: false, - }, - ], - }), - ).toEqual([ - { extension: b, attachTo: { id: 'root', input: 'default' } }, - { extension: a, attachTo: { id: 'root', input: 'default' } }, - ]); - }); - - it('should apply extension overrides', () => { - const a = makeExt('a'); - const b = makeExt('b'); - const plugin = createPlugin({ id: 'test', extensions: [a, b] }); - const aOverride = makeExt('a', 'enabled', 'other'); - const bOverride = makeExt('b', 'disabled', 'other'); - const cOverride = makeExt('c'); - - const result = mergeExtensionParameters({ - features: [ - plugin, - createExtensionOverrides({ - extensions: [aOverride, bOverride, cOverride], - }), - ], - builtinExtensions: [], - parameters: [], - }); - - expect(result.length).toBe(2); - expect(result[0].extension).toBe(aOverride); - expect(result[0].attachTo).toEqual({ id: 'other', input: 'default' }); - expect(result[0].config).toEqual(undefined); - expect(result[0].source).toBe(plugin); - - expect(result[1]).toEqual({ - extension: cOverride, - attachTo: { id: 'root', input: 'default' }, - config: undefined, - source: undefined, - }); - }); - - it('should use order from configuration when rather than overrides', () => { - const a = makeExt('a', 'disabled'); - const b = makeExt('b', 'disabled'); - const c = makeExt('c', 'disabled'); - const aOverride = makeExt('c', 'disabled'); - const bOverride = makeExt('b', 'disabled'); - const cOverride = makeExt('a', 'disabled'); - - const result = mergeExtensionParameters({ - features: [ - createPlugin({ id: 'test', extensions: [a, b, c] }), - createExtensionOverrides({ - extensions: [cOverride, bOverride, aOverride], - }), - ], - builtinExtensions: [], - parameters: ['b', 'c', 'a'].map(id => ({ id, disabled: false })), - }); - - expect(result.map(r => r.extension.id)).toEqual(['b', 'c', 'a']); - }); -}); - -describe('readAppExtensionParameters', () => { +describe('readAppExtensionsConfig', () => { it('should disable extension with shorthand notation', () => { expect( - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [{ 'core.router': false }] } }), ), ).toEqual([ @@ -222,7 +34,7 @@ describe('readAppExtensionParameters', () => { }, ]); expect( - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [{ 'core.router': { disabled: true } }] }, }), @@ -239,7 +51,7 @@ describe('readAppExtensionParameters', () => { it('should enable extension with shorthand notation', () => { expect( - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: ['core.router'] } }), ), ).toEqual([ @@ -249,7 +61,7 @@ describe('readAppExtensionParameters', () => { }, ]); expect( - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [{ 'core.router': true }] } }), ), ).toEqual([ @@ -259,7 +71,7 @@ describe('readAppExtensionParameters', () => { }, ]); expect( - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [{ 'core.router': { disabled: false } }] }, }), @@ -274,7 +86,7 @@ describe('readAppExtensionParameters', () => { it('should not allow string keys', () => { expect(() => - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [{ 'core.router': 'some-string' }], @@ -288,7 +100,7 @@ describe('readAppExtensionParameters', () => { it('should not allow invalid keys', () => { expect(() => - readAppExtensionParameters( + readAppExtensionsConfig( new ConfigReader({ app: { extensions: [ diff --git a/packages/frontend-app-api/src/graph/readAppExtensionsConfig.ts b/packages/frontend-app-api/src/graph/readAppExtensionsConfig.ts new file mode 100644 index 0000000000..2b5b51ce92 --- /dev/null +++ b/packages/frontend-app-api/src/graph/readAppExtensionsConfig.ts @@ -0,0 +1,199 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { JsonValue } from '@backstage/types'; + +export interface ExtensionParameters { + id: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + config?: unknown; +} + +const knownExtensionParameters = ['attachTo', 'disabled', 'config']; + +// Since we'll never merge arrays in config the config reader context +// isn't too much of a help. Fall back to manual config reading logic +// as the Config interface makes it quite hard for us otherwise. +/** @internal */ +export function readAppExtensionsConfig( + rootConfig: Config, +): ExtensionParameters[] { + const arr = rootConfig.getOptional('app.extensions'); + if (!Array.isArray(arr)) { + if (arr === undefined) { + return []; + } + // This will throw, and show which part of config had the wrong type + rootConfig.getConfigArray('app.extensions'); + return []; + } + + return arr.map((arrayEntry, arrayIndex) => + expandShorthandExtensionParameters(arrayEntry, arrayIndex), + ); +} + +/** @internal */ +export function expandShorthandExtensionParameters( + arrayEntry: JsonValue, + arrayIndex: number, +): ExtensionParameters { + function errorMsg(msg: string, key?: string, prop?: string) { + return `Invalid extension configuration at app.extensions[${arrayIndex}]${ + key ? `[${key}]` : '' + }${prop ? `.${prop}` : ''}, ${msg}`; + } + + // NOTE(freben): This check is intentionally not complete and doesn't check + // whether letters and digits are used, etc. It's not up to the config reading + // logic to decide what constitutes a valid extension ID; that should be + // decided by the logic that loads and instantiates the extensions. This check + // is just here to catch real mistakes or truly conceptually wrong input. + function assertValidId(id: string) { + if (!id || id !== id.trim()) { + throw new Error( + errorMsg('extension ID must not be empty or contain whitespace'), + ); + } + + if (id.includes('/')) { + let message = `extension ID must not contain slashes; got '${id}'`; + const good = id.split('/')[0]; + if (good) { + message += `, did you mean '${good}'?`; + } + throw new Error(errorMsg(message)); + } + } + + // Example YAML: + // - entity.card.about + if (typeof arrayEntry === 'string') { + assertValidId(arrayEntry); + return { + id: arrayEntry, + disabled: false, + }; + } + + // All remaining cases are single-key objects + if ( + typeof arrayEntry !== 'object' || + arrayEntry === null || + Array.isArray(arrayEntry) + ) { + throw new Error(errorMsg('must be a string or an object')); + } + const keys = Object.keys(arrayEntry); + if (keys.length !== 1) { + const joinedKeys = keys.length ? `'${keys.join("', '")}'` : 'none'; + throw new Error(errorMsg(`must have exactly one key, got ${joinedKeys}`)); + } + + const id = String(keys[0]); + const value = arrayEntry[id]; + assertValidId(id); + + // This example covers a potentially common mistake in the syntax + // Example YAML: + // - entity.card.about: + if (value === null) { + return { + id, + disabled: false, + }; + } + + // Example YAML: + // - catalog.page.cicd: false + if (typeof value === 'boolean') { + return { + id, + disabled: !value, + }; + } + + // The remaining case is the generic object. Example YAML: + // - tech-radar.page: + // at: core.router/routes + // disabled: false + // config: + // path: /tech-radar + // width: 1500 + // height: 800 + if (typeof value !== 'object' || Array.isArray(value)) { + // We don't mention null here - we don't want people to explicitly enter + // - entity.card.about: null + throw new Error(errorMsg('value must be a boolean or object', id)); + } + + const attachTo = value.attachTo as { id: string; input: string } | undefined; + const disabled = value.disabled; + const config = value.config; + + if (attachTo !== undefined) { + if ( + attachTo === null || + typeof attachTo !== 'object' || + Array.isArray(attachTo) + ) { + throw new Error(errorMsg('must be an object', id, 'attachTo')); + } + if (typeof attachTo.id !== 'string' || attachTo.id === '') { + throw new Error( + errorMsg('must be a non-empty string', id, 'attachTo.id'), + ); + } + if (typeof attachTo.input !== 'string' || attachTo.input === '') { + throw new Error( + errorMsg('must be a non-empty string', id, 'attachTo.input'), + ); + } + } + if (disabled !== undefined && typeof disabled !== 'boolean') { + throw new Error(errorMsg('must be a boolean', id, 'disabled')); + } + if ( + config !== undefined && + (typeof config !== 'object' || config === null || Array.isArray(config)) + ) { + throw new Error(errorMsg('must be an object', id, 'config')); + } + + const unknownKeys = Object.keys(value).filter( + k => !knownExtensionParameters.includes(k), + ); + if (unknownKeys.length > 0) { + throw new Error( + errorMsg( + `unknown parameter; expected one of '${knownExtensionParameters.join( + "', '", + )}'`, + id, + unknownKeys.join(', '), + ), + ); + } + + return { + id, + attachTo, + disabled, + config, + }; +} diff --git a/packages/frontend-app-api/src/graph/resolveAppGraph.test.ts b/packages/frontend-app-api/src/graph/resolveAppGraph.test.ts new file mode 100644 index 0000000000..2668c51863 --- /dev/null +++ b/packages/frontend-app-api/src/graph/resolveAppGraph.test.ts @@ -0,0 +1,166 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createExtension } from '@backstage/frontend-plugin-api'; +import { resolveAppGraph } from './resolveAppGraph'; + +const extBaseConfig = { + id: 'test', + attachTo: { id: 'nonexistent', input: 'nonexistent' }, + output: {}, + factory() {}, +}; + +const extension = createExtension(extBaseConfig); + +const baseSpec = { + extension, + attachTo: { id: 'nonexistent', input: 'nonexistent' }, + disabled: false, +}; + +describe('buildAppGraph', () => { + it('should fail to create an empty graph', () => { + expect(() => resolveAppGraph('core', [])).toThrow( + "No root node with id 'core' found in app graph", + ); + }); + + it('should create a graph with only one node', () => { + const graph = resolveAppGraph('core', [{ ...baseSpec, id: 'core' }]); + expect(graph.root).toEqual({ + spec: { ...baseSpec, id: 'core' }, + edges: { attachments: new Map() }, + }); + expect(Array.from(graph.orphans)).toEqual([]); + expect(Array.from(graph.nodes.keys())).toEqual(['core']); + }); + + it('should create a graph', () => { + const graph = resolveAppGraph('b', [ + { ...baseSpec, id: 'a' }, + { ...baseSpec, id: 'b' }, + { ...baseSpec, id: 'c' }, + { ...baseSpec, attachTo: { id: 'b', input: 'x' }, id: 'bx1' }, + { ...baseSpec, attachTo: { id: 'b', input: 'x' }, id: 'bx2' }, + { ...baseSpec, attachTo: { id: 'b', input: 'y' }, id: 'by1' }, + { ...baseSpec, attachTo: { id: 'd', input: 'x' }, id: 'dx1' }, + ]); + + expect(Array.from(graph.nodes.keys())).toEqual([ + 'a', + 'b', + 'c', + 'bx1', + 'bx2', + 'by1', + 'dx1', + ]); + + expect(JSON.parse(JSON.stringify(graph.root))).toMatchInlineSnapshot(` + { + "attachments": { + "x": [ + { + "id": "bx1", + }, + { + "id": "bx2", + }, + ], + "y": [ + { + "id": "by1", + }, + ], + }, + "id": "b", + } + `); + expect(String(graph.root)).toMatchInlineSnapshot(` + " + x [ + + + ] + y [ + + ] + " + `); + + const orphans = Array.from(graph.orphans).map(String); + expect(orphans).toMatchInlineSnapshot(` + [ + "", + "", + "", + ] + `); + }); + + it('should create a graph out of order', () => { + const graph = resolveAppGraph('b', [ + { ...baseSpec, attachTo: { id: 'b', input: 'x' }, id: 'bx2' }, + { ...baseSpec, id: 'a' }, + { ...baseSpec, attachTo: { id: 'b', input: 'y' }, id: 'by1' }, + { ...baseSpec, id: 'b' }, + { ...baseSpec, attachTo: { id: 'b', input: 'x' }, id: 'bx1' }, + { ...baseSpec, id: 'c' }, + { ...baseSpec, attachTo: { id: 'd', input: 'x' }, id: 'dx1' }, + ]); + + expect(Array.from(graph.nodes.keys())).toEqual([ + 'bx2', + 'a', + 'by1', + 'b', + 'bx1', + 'c', + 'dx1', + ]); + + expect(String(graph.root)).toMatchInlineSnapshot(` + " + x [ + + + ] + y [ + + ] + " + `); + + const orphans = Array.from(graph.orphans).map(String); + expect(orphans).toMatchInlineSnapshot(` + [ + "", + "", + "", + ] + `); + }); + + it('throws an error when duplicated extensions are detected', () => { + expect(() => + resolveAppGraph('core', [ + { ...baseSpec, id: 'a' }, + { ...baseSpec, id: 'a' }, + ]), + ).toThrow("Unexpected duplicate extension id 'a'"); + }); +}); diff --git a/packages/frontend-app-api/src/graph/resolveAppGraph.ts b/packages/frontend-app-api/src/graph/resolveAppGraph.ts new file mode 100644 index 0000000000..354b4c53ee --- /dev/null +++ b/packages/frontend-app-api/src/graph/resolveAppGraph.ts @@ -0,0 +1,152 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AppGraph, AppNode, AppNodeInstance, AppNodeSpec } from './types'; + +function indent(str: string) { + return str.replace(/^/gm, ' '); +} + +/** @internal */ +class SerializableAppNode implements AppNode { + public readonly spec: AppNodeSpec; + public readonly edges = { + attachedTo: undefined as { node: AppNode; input: string } | undefined, + attachments: new Map(), + }; + public readonly instance?: AppNodeInstance; + + constructor(spec: AppNodeSpec) { + this.spec = spec; + } + + setParent(parent: SerializableAppNode) { + const input = this.spec.attachTo.input; + + this.edges.attachedTo = { node: parent, input }; + + const parentInputEdges = parent.edges.attachments.get(input); + if (parentInputEdges) { + parentInputEdges.push(this); + } else { + parent.edges.attachments.set(input, [this]); + } + } + + toJSON() { + const dataRefs = this.instance && [...this.instance.getDataRefs()]; + return { + id: this.spec.id, + output: + dataRefs && dataRefs.length > 0 + ? dataRefs.map(ref => ref.id) + : undefined, + attachments: + this.edges.attachments.size > 0 + ? Object.fromEntries(this.edges.attachments) + : undefined, + }; + } + + toString(): string { + const dataRefs = this.instance && [...this.instance.getDataRefs()]; + const out = + dataRefs && dataRefs.length > 0 + ? ` out=[${[...dataRefs.keys()].join(', ')}]` + : ''; + + if (this.edges.attachments.size === 0) { + return `<${this.spec.id}${out} />`; + } + + return [ + `<${this.spec.id}${out}>`, + ...[...this.edges.attachments.entries()].map(([k, v]) => + indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\n')), + ), + ``, + ].join('\n'); + } +} + +/** + * Build the app graph by iterating through all node specs and constructing the app + * tree with all attachments in the same order as they appear in the input specs array. + * @internal + */ +export function resolveAppGraph( + rootNodeId: string, + specs: AppNodeSpec[], +): AppGraph { + const nodes = new Map(); + + // A node with the provided rootNodeId must be found in the graph, and it must not be attached to anything + let rootNode: AppNode | undefined = undefined; + + // While iterating through the inputs specs we keep track of all nodes that were created + // before their parent, and attach them later when the parent is created. + // As we find the parents and attach the children, we remove them from this map. This means + // that after iterating through all input specs, this will be a map for each root node. + const orphansByParent = new Map< + string /* parentId */, + SerializableAppNode[] + >(); + + for (const spec of specs) { + // The main check with a more helpful error message happens in resolveAppNodeSpecs + if (nodes.has(spec.id)) { + throw new Error(`Unexpected duplicate extension id '${spec.id}'`); + } + + const node = new SerializableAppNode(spec); + nodes.set(spec.id, node); + + // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it + if (spec.id === rootNodeId) { + rootNode = node; + } else { + const parent = nodes.get(spec.attachTo.id); + if (parent) { + node.setParent(parent); + } else { + const orphanNodesForParent = orphansByParent.get(spec.attachTo.id); + if (orphanNodesForParent) { + orphanNodesForParent.push(node); + } else { + orphansByParent.set(spec.attachTo.id, [node]); + } + } + } + + const orphanedChildren = orphansByParent.get(spec.id); + if (orphanedChildren) { + orphansByParent.delete(spec.id); + for (const orphan of orphanedChildren) { + orphan.setParent(node); + } + } + } + + if (!rootNode) { + throw new Error(`No root node with id '${rootNodeId}' found in app graph`); + } + + return { + root: rootNode, + nodes, + orphans: Array.from(orphansByParent.values()).flat(), + }; +} diff --git a/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.test.ts b/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.test.ts new file mode 100644 index 0000000000..59930968c6 --- /dev/null +++ b/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.test.ts @@ -0,0 +1,278 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createExtensionOverrides, + createPlugin, + Extension, +} from '@backstage/frontend-plugin-api'; +import { resolveAppNodeSpecs } from './resolveAppNodeSpecs'; + +function makeExt( + id: string, + status: 'disabled' | 'enabled' = 'enabled', + attachId: string = 'root', +) { + return { + id, + attachTo: { id: attachId, input: 'default' }, + disabled: status === 'disabled', + } as Extension; +} + +describe('resolveAppNodeSpecs', () => { + it('should filter out disabled extension instances', () => { + expect( + resolveAppNodeSpecs({ + features: [], + builtinExtensions: [makeExt('a', 'disabled')], + parameters: [], + }), + ).toEqual([]); + }); + + it('should pass through extension instances', () => { + const a = makeExt('a'); + const b = makeExt('b'); + expect( + resolveAppNodeSpecs({ + features: [], + builtinExtensions: [a, b], + parameters: [], + }), + ).toEqual([ + { + id: 'a', + extension: a, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'b', + extension: b, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + ]); + }); + + it('should override attachment points', () => { + const a = makeExt('a'); + const b = makeExt('b'); + const pluginA = createPlugin({ id: 'test', extensions: [a] }); + expect( + resolveAppNodeSpecs({ + features: [pluginA], + builtinExtensions: [b], + parameters: [ + { + id: 'b', + attachTo: { id: 'derp', input: 'default' }, + }, + ], + }), + ).toEqual([ + { + id: 'a', + extension: a, + attachTo: { id: 'root', input: 'default' }, + source: pluginA, + disabled: false, + }, + { + id: 'b', + extension: b, + attachTo: { id: 'derp', input: 'default' }, + disabled: false, + }, + ]); + }); + + it('should fully override configuration and duplicate', () => { + const a = makeExt('a'); + const b = makeExt('b'); + const plugin = createPlugin({ id: 'test', extensions: [a, b] }); + expect( + resolveAppNodeSpecs({ + features: [plugin], + builtinExtensions: [], + parameters: [ + { + id: 'a', + config: { foo: { bar: 1 } }, + }, + { + id: 'b', + config: { foo: { bar: 2 } }, + }, + { + id: 'b', + config: { foo: { qux: 3 } }, + }, + ], + }), + ).toEqual([ + { + id: 'a', + extension: a, + attachTo: { id: 'root', input: 'default' }, + source: plugin, + config: { foo: { bar: 1 } }, + disabled: false, + }, + { + id: 'b', + extension: b, + attachTo: { id: 'root', input: 'default' }, + source: plugin, + config: { foo: { qux: 3 } }, + disabled: false, + }, + ]); + }); + + it('should place enabled instances in the order that they were enabled', () => { + const a = makeExt('a', 'disabled'); + const b = makeExt('b', 'disabled'); + expect( + resolveAppNodeSpecs({ + features: [createPlugin({ id: 'empty', extensions: [] })], + builtinExtensions: [a, b], + parameters: [ + { + id: 'b', + disabled: false, + }, + { + id: 'a', + disabled: false, + }, + ], + }), + ).toEqual([ + { + id: 'b', + extension: b, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + { + id: 'a', + extension: a, + attachTo: { id: 'root', input: 'default' }, + disabled: false, + }, + ]); + }); + + it('should apply extension overrides', () => { + const a = makeExt('a'); + const b = makeExt('b'); + const plugin = createPlugin({ id: 'test', extensions: [a, b] }); + const aOverride = makeExt('a', 'enabled', 'other'); + const bOverride = makeExt('b', 'disabled', 'other'); + const cOverride = makeExt('c'); + + const result = resolveAppNodeSpecs({ + features: [ + plugin, + createExtensionOverrides({ + extensions: [aOverride, bOverride, cOverride], + }), + ], + builtinExtensions: [], + parameters: [], + }); + + expect(result.length).toBe(2); + expect(result[0].extension).toBe(aOverride); + expect(result[0].attachTo).toEqual({ id: 'other', input: 'default' }); + expect(result[0].config).toEqual(undefined); + expect(result[0].source).toBe(plugin); + + expect(result[1]).toEqual({ + id: 'c', + extension: cOverride, + attachTo: { id: 'root', input: 'default' }, + config: undefined, + source: undefined, + disabled: false, + }); + }); + + it('should use order from configuration when rather than overrides', () => { + const a = makeExt('a', 'disabled'); + const b = makeExt('b', 'disabled'); + const c = makeExt('c', 'disabled'); + const aOverride = makeExt('c', 'disabled'); + const bOverride = makeExt('b', 'disabled'); + const cOverride = makeExt('a', 'disabled'); + + const result = resolveAppNodeSpecs({ + features: [ + createPlugin({ id: 'test', extensions: [a, b, c] }), + createExtensionOverrides({ + extensions: [cOverride, bOverride, aOverride], + }), + ], + builtinExtensions: [], + parameters: ['b', 'c', 'a'].map(id => ({ id, disabled: false })), + }); + + expect(result.map(r => r.extension.id)).toEqual(['b', 'c', 'a']); + }); + + it('throws an error when a forbidden extension is overridden by a plugin', () => { + expect(() => + resolveAppNodeSpecs({ + features: [ + createPlugin({ id: 'test', extensions: [makeExt('forbidden')] }), + ], + builtinExtensions: [], + parameters: [], + forbidden: new Set(['forbidden']), + }), + ).toThrow( + "It is forbidden to override the following extension(s): 'forbidden', which is done by the following plugin(s): 'test'", + ); + }); + + it('throws an error when a forbidden extension is overridden by overrides', () => { + expect(() => + resolveAppNodeSpecs({ + features: [ + createExtensionOverrides({ extensions: [makeExt('forbidden')] }), + ], + builtinExtensions: [], + parameters: [], + forbidden: new Set(['forbidden']), + }), + ).toThrow( + "It is forbidden to override the following extension(s): 'forbidden', which is done by one or more extension overrides", + ); + }); + + it('throws an error when a forbidden extension is parametrized', () => { + expect(() => + resolveAppNodeSpecs({ + features: [], + builtinExtensions: [], + parameters: [{ id: 'forbidden', disabled: false }], + forbidden: new Set(['forbidden']), + }), + ).toThrow("Configuration of the 'forbidden' extension is forbidden"); + }); +}); diff --git a/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.ts b/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.ts new file mode 100644 index 0000000000..ca3c4fd1ea --- /dev/null +++ b/packages/frontend-app-api/src/graph/resolveAppNodeSpecs.ts @@ -0,0 +1,212 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + BackstagePlugin, + Extension, + ExtensionOverrides, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; +import { ExtensionParameters } from './readAppExtensionsConfig'; +import { AppNodeSpec } from './types'; + +/** @internal */ +export function resolveAppNodeSpecs(options: { + features: (BackstagePlugin | ExtensionOverrides)[]; + builtinExtensions: Extension[]; + parameters: Array; + forbidden?: Set; +}): AppNodeSpec[] { + const { builtinExtensions, parameters, forbidden = new Set() } = options; + + const plugins = options.features.filter( + (f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin', + ); + const overrides = options.features.filter( + (f): f is ExtensionOverrides => + f.$$type === '@backstage/ExtensionOverrides', + ); + + const pluginExtensions = plugins.flatMap(source => { + return source.extensions.map(extension => ({ ...extension, source })); + }); + const overrideExtensions = overrides.flatMap( + override => toInternalExtensionOverrides(override).extensions, + ); + + // Prevent core override + if (pluginExtensions.some(({ id }) => forbidden.has(id))) { + const pluginsStr = pluginExtensions + .filter(({ id }) => forbidden.has(id)) + .map(({ source }) => `'${source.id}'`) + .join(', '); + const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', '); + throw new Error( + `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by the following plugin(s): ${pluginsStr}`, + ); + } + + if (overrideExtensions.some(({ id }) => forbidden.has(id))) { + const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', '); + throw new Error( + `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by one or more extension overrides`, + ); + } + const overrideExtensionIds = overrideExtensions.map(({ id }) => id); + if (overrideExtensionIds.length !== new Set(overrideExtensionIds).size) { + const counts = new Map(); + for (const id of overrideExtensionIds) { + counts.set(id, (counts.get(id) ?? 0) + 1); + } + const duplicated = Array.from(counts.entries()) + .filter(([, count]) => count > 1) + .map(([id]) => id); + throw new Error( + `The following extensions had duplicate overrides: ${duplicated.join( + ', ', + )}`, + ); + } + + const configuredExtensions = [ + ...pluginExtensions.map(({ source, ...extension }) => ({ + extension, + params: { + source, + attachTo: extension.attachTo, + disabled: extension.disabled, + config: undefined as unknown, + }, + })), + ...builtinExtensions.map(extension => ({ + extension, + params: { + source: undefined, + attachTo: extension.attachTo, + disabled: extension.disabled, + config: undefined as unknown, + }, + })), + ]; + + // Install all extension overrides + for (const extension of overrideExtensions) { + // Check if our override is overriding an extension that already exists + const index = configuredExtensions.findIndex( + e => e.extension.id === extension.id, + ); + if (index !== -1) { + // Only implementation, attachment point and default disabled status are overridden, the source is kept + configuredExtensions[index].extension = extension; + configuredExtensions[index].params.attachTo = extension.attachTo; + configuredExtensions[index].params.disabled = extension.disabled; + } else { + // Add the extension as a new one when not overriding an existing one + configuredExtensions.push({ + extension, + params: { + source: undefined, + attachTo: extension.attachTo, + disabled: extension.disabled, + config: undefined, + }, + }); + } + } + + const duplicatedExtensionIds = new Set(); + const duplicatedExtensionData = configuredExtensions.reduce< + Record> + >((data, { extension, params }) => { + const extensionId = extension.id; + const extensionData = data?.[extensionId]; + if (extensionData) duplicatedExtensionIds.add(extensionId); + const pluginId = params.source?.id ?? 'internal'; + const pluginCount = extensionData?.[pluginId] ?? 0; + return { + ...data, + [extensionId]: { ...extensionData, [pluginId]: pluginCount + 1 }, + }; + }, {}); + + if (duplicatedExtensionIds.size > 0) { + throw new Error( + `The following extensions are duplicated: ${Array.from( + duplicatedExtensionIds, + ) + .map( + extensionId => + `The extension '${extensionId}' was provided ${Object.keys( + duplicatedExtensionData[extensionId], + ) + .map( + pluginId => + `${duplicatedExtensionData[extensionId][pluginId]} time(s) by the plugin '${pluginId}'`, + ) + .join(' and ')}`, + ) + .join(', ')}`, + ); + } + + for (const overrideParam of parameters) { + const extensionId = overrideParam.id; + + if (forbidden.has(extensionId)) { + throw new Error( + `Configuration of the '${extensionId}' extension is forbidden`, + ); + } + + const existingIndex = configuredExtensions.findIndex( + e => e.extension.id === extensionId, + ); + if (existingIndex !== -1) { + const existing = configuredExtensions[existingIndex]; + if (overrideParam.attachTo) { + existing.params.attachTo = overrideParam.attachTo; + } + if (overrideParam.config) { + // TODO: merge config? + existing.params.config = overrideParam.config; + } + if ( + Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled) + ) { + existing.params.disabled = Boolean(overrideParam.disabled); + if (!existing.params.disabled) { + // bump + configuredExtensions.splice(existingIndex, 1); + configuredExtensions.push(existing); + } + } + } else { + throw new Error(`Extension ${extensionId} does not exist`); + } + } + + return configuredExtensions + .filter(override => !override.params.disabled) + .map(param => ({ + id: param.extension.id, + attachTo: param.params.attachTo, + extension: param.extension, + disabled: param.params.disabled, + source: param.params.source, + config: param.params.config, + })); +} diff --git a/packages/frontend-app-api/src/graph/types.ts b/packages/frontend-app-api/src/graph/types.ts new file mode 100644 index 0000000000..9267f13158 --- /dev/null +++ b/packages/frontend-app-api/src/graph/types.ts @@ -0,0 +1,101 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + BackstagePlugin, + Extension, + ExtensionDataRef, +} from '@backstage/frontend-plugin-api'; + +/* +NOTE: These types are marked as @internal for now, but the intention is for this to be a public API in the future. +*/ + +/** + * The specification for this node in the app graph. + * + * @internal + * @remarks + * + * The specifications for a collection of app nodes is all the information needed + * to build the graph and instantiate the nodes. + */ +export interface AppNodeSpec { + readonly id: string; + readonly attachTo: { id: string; input: string }; + readonly extension: Extension; + readonly disabled: boolean; + readonly config?: unknown; + readonly source?: BackstagePlugin; +} + +/** + * The connections from this node to other nodes. + * + * @internal + * @remarks + * + * The app node edges are resolved based on the app node specs, regardless of whether + * adjacent nodes are disabled or not. If no parent attachment is present or + */ +export interface AppNodeEdges { + readonly attachedTo?: { node: AppNode; input: string }; + readonly attachments: ReadonlyMap; +} + +/** + * The instance of this node in the app graph. + * + * @internal + * @remarks + * + * The app node instance is created when the `factory` function of an extension is called. + * Instances will only be present for nodes in the app that are connected to the root + * node and not disabled + */ +export interface AppNodeInstance { + /** Returns a sequence of all extension data refs that were output by this instance */ + getDataRefs(): Iterable>; + /** Get the output data for a single extension data ref */ + getData(ref: ExtensionDataRef): T | undefined; +} + +/** + * + * @internal + */ +export interface AppNode { + /** The specification for how this node should be instantiated */ + readonly spec: AppNodeSpec; + /** The edges from this node to other nodes in the app graph */ + readonly edges: AppNodeEdges; + /** The instance of this node, if it was instantiated */ + readonly instance?: AppNodeInstance; +} + +/** + * The app graph containing all nodes of the app. + * + * @internal + */ +export interface AppGraph { + /** The root node of the app */ + root: AppNode; + /** A map of all nodes in the app by ID, including orphaned or disabled nodes */ + nodes: ReadonlyMap; + /** A sequence of all nodes with a parent that is not reachable from the app root node */ + orphans: Iterable; +} diff --git a/packages/frontend-app-api/src/index.ts b/packages/frontend-app-api/src/index.ts index f2dfa0f029..ad82b4ceef 100644 --- a/packages/frontend-app-api/src/index.ts +++ b/packages/frontend-app-api/src/index.ts @@ -21,3 +21,4 @@ */ export * from './wiring'; +export * from './routing'; diff --git a/packages/frontend-app-api/src/routing/RouteResolver.test.ts b/packages/frontend-app-api/src/routing/RouteResolver.test.ts new file mode 100644 index 0000000000..81e9d10be4 --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteResolver.test.ts @@ -0,0 +1,365 @@ +/* + * 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 { + createRouteRef, + createSubRouteRef, + createExternalRouteRef, + ExternalRouteRef, + RouteRef, + SubRouteRef, +} from '@backstage/frontend-plugin-api'; +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { RouteResolver } from './RouteResolver'; +import { MATCH_ALL_ROUTE } from './extractRouteInfoFromAppNode'; + +const rest = { + element: null, + caseSensitive: false, + children: [MATCH_ALL_ROUTE], + plugins: new Set(), +}; + +const ref1 = createRouteRef(); +const ref2 = createRouteRef({ params: ['x'] }); +const ref3 = createRouteRef({ params: ['y'] }); +const subRef1 = createSubRouteRef({ parent: ref1, path: '/foo' }); +const subRef2 = createSubRouteRef({ parent: ref1, path: '/foo/:a' }); +const subRef3 = createSubRouteRef({ parent: ref2, path: '/bar' }); +const subRef4 = createSubRouteRef({ parent: ref2, path: '/bar/:a' }); +const externalRef1 = createExternalRouteRef(); +const externalRef2 = createExternalRouteRef({ optional: true }); +const externalRef3 = createExternalRouteRef({ params: ['x'] }); +const externalRef4 = createExternalRouteRef({ optional: true, params: ['x'] }); + +describe('RouteResolver', () => { + it('should not resolve anything with an empty resolver', () => { + const r = new RouteResolver(new Map(), new Map(), [], new Map(), ''); + + expect(r.resolve(ref1, '/')?.()).toBe(undefined); + expect(r.resolve(ref2, '/')?.({ x: '1x' })).toBe(undefined); + expect(r.resolve(subRef1, '/')?.()).toBe(undefined); + expect(r.resolve(subRef2, '/')?.({ a: '2a' })).toBe(undefined); + expect(r.resolve(subRef3, '/')?.({ x: '3x' })).toBe(undefined); + expect(r.resolve(subRef4, '/')?.({ x: '4x', a: '4a' })).toBe(undefined); + expect(r.resolve(externalRef1, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef2, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef3, '/')?.({ x: '5x' })).toBe(undefined); + expect(r.resolve(externalRef4, '/')?.({ x: '6x' })).toBe(undefined); + }); + + it('should resolve an absolute route', () => { + const r = new RouteResolver( + new Map([[ref1, 'my-route']]), + new Map(), + [{ routeRefs: new Set([ref1]), path: 'my-route', ...rest }], + new Map(), + '', + ); + + expect(r.resolve(ref1, '/')?.()).toBe('/my-route'); + expect(r.resolve(ref2, '/')?.({ x: '1x' })).toBe(undefined); + expect(r.resolve(subRef1, '/')?.()).toBe('/my-route/foo'); + expect(r.resolve(subRef2, '/')?.({ a: '2a' })).toBe('/my-route/foo/2a'); + expect(r.resolve(subRef3, '/')?.({ x: '3x' })).toBe(undefined); + expect(r.resolve(subRef4, '/')?.({ x: '4x', a: '4a' })).toBe(undefined); + expect(r.resolve(externalRef1, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef2, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef3, '/')?.({ x: '5x' })).toBe(undefined); + expect(r.resolve(externalRef4, '/')?.({ x: '6x' })).toBe(undefined); + }); + + it('should resolve an absolute route and sub route with an app base path', () => { + const r = new RouteResolver( + new Map([ + [ref2, 'my-parent/:x'], + [ref1, 'my-route'], + ]), + new Map([[ref1, ref2]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map(), + '/base', + ); + + expect(r.resolve(ref1, '/my-parent/1x')?.()).toBe( + '/base/my-parent/1x/my-route', + ); + expect(r.resolve(ref1, '/base/my-parent/1x')?.()).toBe( + '/base/my-parent/1x/my-route', + ); + expect(r.resolve(ref2, '/')?.({ x: '1x' })).toBe('/base/my-parent/1x'); + expect(r.resolve(ref2, '/base')?.({ x: '1x' })).toBe('/base/my-parent/1x'); + expect(r.resolve(ref3, '/')?.({ y: '1y' })).toBe(undefined); + expect(r.resolve(subRef1, '/my-parent/2x')?.()).toBe( + '/base/my-parent/2x/my-route/foo', + ); + expect(r.resolve(subRef1, '/base/my-parent/2x')?.()).toBe( + '/base/my-parent/2x/my-route/foo', + ); + expect(r.resolve(subRef2, '/my-parent/3x')?.({ a: '2a' })).toBe( + '/base/my-parent/3x/my-route/foo/2a', + ); + expect(r.resolve(subRef2, '/base/my-parent/3x')?.({ a: '2a' })).toBe( + '/base/my-parent/3x/my-route/foo/2a', + ); + expect(r.resolve(subRef3, '/')?.({ x: '5x' })).toBe( + '/base/my-parent/5x/bar', + ); + expect(r.resolve(subRef4, '/')?.({ x: '6x', a: '4a' })).toBe( + '/base/my-parent/6x/bar/4a', + ); + expect(r.resolve(externalRef1, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef2, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef3, '/')?.({ x: '5x' })).toBe(undefined); + expect(r.resolve(externalRef4, '/')?.({ x: '6x' })).toBe(undefined); + }); + + it('should resolve an absolute route with a param and with a parent', () => { + const r = new RouteResolver( + new Map([ + [ref1, 'my-route'], + [ref2, 'my-parent/:x'], + ]), + new Map([[ref2, ref1]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map([ + [externalRef1, ref1], + [externalRef3, ref2], + [externalRef4, subRef3], + ]), + '', + ); + + expect(r.resolve(ref1, '/')?.()).toBe('/my-route'); + expect(r.resolve(ref2, '/')?.({ x: '1x' })).toBe('/my-route/my-parent/1x'); + expect(r.resolve(subRef1, '/')?.()).toBe('/my-route/foo'); + expect(r.resolve(subRef2, '/')?.({ a: '2a' })).toBe('/my-route/foo/2a'); + expect(r.resolve(subRef3, '/')?.({ x: '3x' })).toBe( + '/my-route/my-parent/3x/bar', + ); + expect(r.resolve(subRef4, '/')?.({ x: '4x', a: '4a' })).toBe( + '/my-route/my-parent/4x/bar/4a', + ); + expect(r.resolve(externalRef1, '/')?.()).toBe('/my-route'); + expect(r.resolve(externalRef2, '/')?.()).toBe(undefined); + expect(r.resolve(externalRef3, '/')?.({ x: '5x' })).toBe( + '/my-route/my-parent/5x', + ); + expect(r.resolve(externalRef4, '/')?.({ x: '6x' })).toBe( + '/my-route/my-parent/6x/bar', + ); + }); + + it('should resolve the most specific match', () => { + const r = new RouteResolver( + new Map([ + [ref1, 'deep'], + [ref2, 'root/:x'], + [ref3, 'sub/:y'], + ]), + new Map([ + [ref3, ref2], + [ref1, ref3], + ]), + [ + { + routeRefs: new Set([ref2]), + path: 'root/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { + routeRefs: new Set([ref3]), + path: 'sub/:y', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { + routeRefs: new Set([ref1]), + path: 'deep', + ...rest, + }, + ], + }, + ], + }, + ], + new Map(), + '', + ); + + expect(r.resolve(ref2, '/')?.({ x: 'x' })).toBe('/root/x'); + expect(r.resolve(ref3, '/root/x')?.({ y: 'y' })).toBe('/root/x/sub/y'); + + expect(() => r.resolve(ref1, '/')?.()).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(() => r.resolve(ref1, '/root/x')?.()).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(ref1, '/root/x/sub/y')?.()).toBe('/root/x/sub/y/deep'); + // Without the MATCH_ALL_ROUTE, we wouldn't properly match the route here + expect(r.resolve(ref1, '/root/x/sub/y/any/nested/path/here')?.()).toBe( + '/root/x/sub/y/deep', + ); + }); + + it('should resolve an absolute route with multiple parents', () => { + const r = new RouteResolver( + new Map([ + [ref1, 'my-route'], + [ref2, 'my-parent/:x'], + [ref3, 'my-grandparent/:y'], + ]), + new Map([ + [ref1, ref2], + [ref2, ref3], + ]), + [ + { + routeRefs: new Set([ref3]), + path: 'my-grandparent/:y', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + }, + ], + new Map([ + [externalRef1, ref1], + [externalRef3, ref2], + [externalRef4, subRef3], + ]), + '', + ); + + const l = '/my-grandparent/my-y/my-parent/my-x'; + expect(r.resolve(ref1, l)?.()).toBe( + '/my-grandparent/my-y/my-parent/my-x/my-route', + ); + expect(() => r.resolve(ref1, '/')?.()).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(ref2, l)?.({ x: '1x' })).toBe( + '/my-grandparent/my-y/my-parent/1x', + ); + expect(r.resolve(ref2, '/my-grandparent/my-y')?.({ x: '1x' })).toBe( + '/my-grandparent/my-y/my-parent/1x', + ); + expect(() => r.resolve(ref2, '/')?.({ x: '1x' })).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(subRef1, l)?.()).toBe( + '/my-grandparent/my-y/my-parent/my-x/my-route/foo', + ); + expect(() => r.resolve(subRef1, '/')?.()).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(subRef2, l)?.({ a: '2a' })).toBe( + '/my-grandparent/my-y/my-parent/my-x/my-route/foo/2a', + ); + expect(() => r.resolve(subRef2, '/')?.({ a: '2a' })).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(subRef3, l)?.({ x: '3x' })).toBe( + '/my-grandparent/my-y/my-parent/3x/bar', + ); + expect(r.resolve(subRef3, '/my-grandparent/my-y')?.({ x: '3x' })).toBe( + '/my-grandparent/my-y/my-parent/3x/bar', + ); + expect(r.resolve(subRef4, l)?.({ x: '4x', a: '4a' })).toBe( + '/my-grandparent/my-y/my-parent/4x/bar/4a', + ); + expect( + r.resolve(subRef4, '/my-grandparent/my-y')?.({ x: '4x', a: '4a' }), + ).toBe('/my-grandparent/my-y/my-parent/4x/bar/4a'); + expect(r.resolve(externalRef1, l)?.()).toBe( + '/my-grandparent/my-y/my-parent/my-x/my-route', + ); + expect(() => r.resolve(externalRef1, '/')?.()).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(externalRef2, l)?.()).toBe(undefined); + expect(r.resolve(externalRef3, l)?.({ x: '5x' })).toBe( + '/my-grandparent/my-y/my-parent/5x', + ); + expect(() => r.resolve(externalRef3, '/')?.({ x: '5x' })).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + expect(r.resolve(externalRef4, l)?.({ x: '6x' })).toBe( + '/my-grandparent/my-y/my-parent/6x/bar', + ); + expect(() => r.resolve(externalRef4, '/')?.({ x: '6x' })).toThrow( + /^Cannot route.*with parent.*as it has parameters$/, + ); + }); + + it('should encode some characters in params', () => { + const r = new RouteResolver( + new Map([ + [ref2, 'my-parent/:x'], + [ref1, 'my-route'], + ]), + new Map([[ref1, ref2]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map(), + '/base', + ); + + expect(r.resolve(ref2, '/')?.({ x: 'a/#&?b' })).toBe( + '/base/my-parent/a%2F%23%26%3Fb', + ); + }); +}); diff --git a/packages/frontend-app-api/src/routing/RouteResolver.ts b/packages/frontend-app-api/src/routing/RouteResolver.ts new file mode 100644 index 0000000000..77336988e2 --- /dev/null +++ b/packages/frontend-app-api/src/routing/RouteResolver.ts @@ -0,0 +1,268 @@ +/* + * 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 { generatePath, matchRoutes } from 'react-router-dom'; +import { + RouteRef, + ExternalRouteRef, + SubRouteRef, + AnyRouteRefParams, + RouteFunc, +} from '@backstage/frontend-plugin-api'; +import mapValues from 'lodash/mapValues'; +import { AnyRouteRef, BackstageRouteObject } from './types'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { isRouteRef } from '../../../frontend-plugin-api/src/routing/RouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { + isSubRouteRef, + toInternalSubRouteRef, +} from '../../../frontend-plugin-api/src/routing/SubRouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { isExternalRouteRef } from '../../../frontend-plugin-api/src/routing/ExternalRouteRef'; + +// Joins a list of paths together, avoiding trailing and duplicate slashes +export function joinPaths(...paths: string[]): string { + const normalized = paths.join('/').replace(/\/\/+/g, '/'); + if (normalized !== '/' && normalized.endsWith('/')) { + return normalized.slice(0, -1); + } + return normalized; +} + +/** + * Resolves the absolute route ref that our target route ref is pointing pointing to, as well + * as the relative target path. + * + * Returns an undefined target ref if one could not be fully resolved. + */ +function resolveTargetRef( + anyRouteRef: AnyRouteRef, + routePaths: Map, + routeBindings: Map, +): readonly [RouteRef | undefined, string] { + // First we figure out which absolute route ref we're dealing with, an if there was an sub route path to append. + // For sub routes it will be the parent path, while for external routes it will be the bound route. + let targetRef: RouteRef; + let subRoutePath = ''; + if (isRouteRef(anyRouteRef)) { + targetRef = anyRouteRef; + } else if (isSubRouteRef(anyRouteRef)) { + const internal = toInternalSubRouteRef(anyRouteRef); + targetRef = internal.getParent(); + subRoutePath = internal.path; + } else if (isExternalRouteRef(anyRouteRef)) { + const resolvedRoute = routeBindings.get(anyRouteRef); + if (!resolvedRoute) { + return [undefined, '']; + } + if (isRouteRef(resolvedRoute)) { + targetRef = resolvedRoute; + } else if (isSubRouteRef(resolvedRoute)) { + const internal = toInternalSubRouteRef(resolvedRoute); + targetRef = internal.getParent(); + subRoutePath = resolvedRoute.path; + } else { + throw new Error( + `ExternalRouteRef was bound to invalid target, ${resolvedRoute}`, + ); + } + } else { + throw new Error(`Unknown object passed to useRouteRef, got ${anyRouteRef}`); + } + + // Bail if no absolute path could be resolved + if (!targetRef) { + return [undefined, '']; + } + + // Find the path that our target route is bound to + const resolvedPath = routePaths.get(targetRef); + if (resolvedPath === undefined) { + return [undefined, '']; + } + + // SubRouteRefs join the path from the parent route with its own path + const targetPath = joinPaths(resolvedPath, subRoutePath); + return [targetRef, targetPath]; +} + +/** + * Resolves the complete base path for navigating to the target RouteRef. + */ +function resolveBasePath( + targetRef: RouteRef, + sourceLocation: Parameters[1], + routePaths: Map, + routeParents: Map, + routeObjects: BackstageRouteObject[], +) { + // While traversing the app element tree we build up the routeObjects structure + // used here. It is the same kind of structure that react-router creates, with the + // addition that associated route refs are stored throughout the tree. This lets + // us look up all route refs that can be reached from our source location. + // Because of the similar route object structure, we can use `matchRoutes` from + // react-router to do the lookup of our current location. + const match = matchRoutes(routeObjects, sourceLocation) ?? []; + + // While we search for a common routing root between our current location and + // the target route, we build a list of all route refs we find that we need + // to traverse to reach the target. + const refDiffList = Array(); + + let matchIndex = -1; + for ( + let targetSearchRef: RouteRef | undefined = targetRef; + targetSearchRef; + targetSearchRef = routeParents.get(targetSearchRef) + ) { + // The match contains a list of all ancestral route refs present at our current location + // Starting at the desired target ref and traversing back through its parents, we search + // for a target ref that is present in the match for our current location. When a match + // is found it means we have found a common base to resolve the route from. + matchIndex = match.findIndex(m => + (m.route as BackstageRouteObject).routeRefs.has(targetSearchRef!), + ); + if (matchIndex !== -1) { + break; + } + + // Every time we move a step up in the ancestry of the target ref, we add the current ref + // to the diff list, which ends up being the list of route refs to traverse form the common base + // in order to reach our target. + refDiffList.unshift(targetSearchRef); + } + + // If our target route is present in the initial match we need to construct the final path + // from the parent of the matched route segment. That's to allow the caller of the route + // function to supply their own params. + if (refDiffList.length === 0) { + matchIndex -= 1; + } + + // This is the part of the route tree that the target and source locations have in common. + // We re-use the existing pathname directly along with all params. + const parentPath = matchIndex === -1 ? '' : match[matchIndex].pathname; + + // This constructs the mid section of the path using paths resolved from all route refs + // we need to traverse to reach our target except for the very last one. None of these + // paths are allowed to require any parameters, as the caller would have no way of knowing + // what parameters those are. + const diffPaths = refDiffList.slice(0, -1).map(ref => { + const path = routePaths.get(ref); + if (path === undefined) { + throw new Error(`No path for ${ref}`); + } + if (path.includes(':')) { + throw new Error( + `Cannot route to ${targetRef} with parent ${ref} as it has parameters`, + ); + } + return path; + }); + + return `${joinPaths(parentPath, ...diffPaths)}/`; +} + +export class RouteResolver { + constructor( + private readonly routePaths: Map, + private readonly routeParents: Map, + private readonly routeObjects: BackstageRouteObject[], + private readonly routeBindings: Map< + ExternalRouteRef, + RouteRef | SubRouteRef + >, + private readonly appBasePath: string, // base path without a trailing slash + ) {} + + resolve( + anyRouteRef: + | RouteRef + | SubRouteRef + | ExternalRouteRef, + sourceLocation: Parameters[1], + ): RouteFunc | undefined { + // First figure out what our target absolute ref is, as well as our target path. + const [targetRef, targetPath] = resolveTargetRef( + anyRouteRef, + this.routePaths, + this.routeBindings, + ); + if (!targetRef) { + return undefined; + } + + // The location that we get passed in uses the full path, so start by trimming off + // the app base path prefix in case we're running the app on a sub-path. + let relativeSourceLocation: Parameters[1]; + if (typeof sourceLocation === 'string') { + relativeSourceLocation = this.trimPath(sourceLocation); + } else if (sourceLocation.pathname) { + relativeSourceLocation = { + ...sourceLocation, + pathname: this.trimPath(sourceLocation.pathname), + }; + } else { + relativeSourceLocation = sourceLocation; + } + + // Next we figure out the base path, which is the combination of the common parent path + // between our current location and our target location, as well as the additional path + // that is the difference between the parent path and the base of our target location. + const basePath = + this.appBasePath + + resolveBasePath( + targetRef, + relativeSourceLocation, + this.routePaths, + this.routeParents, + this.routeObjects, + ); + + const routeFunc: RouteFunc = (...[params]) => { + // We selectively encode some some known-dangerous characters in the + // params. The reason that we don't perform a blanket `encodeURIComponent` + // here is that this encoding was added defensively long after the initial + // release of this code. There's likely to be many users of this code that + // already encode their parameters knowing that this code didn't do this + // for them in the past. Therefore, we are extra careful NOT to include + // the percent character in this set, even though that might seem like a + // bad idea. + const encodedParams = + params && + mapValues(params, value => { + if (typeof value === 'string') { + return value.replaceAll(/[&?#;\/]/g, c => encodeURIComponent(c)); + } + return value; + }); + return joinPaths(basePath, generatePath(targetPath, encodedParams)); + }; + return routeFunc; + } + + private trimPath(targetPath: string) { + if (!targetPath) { + return targetPath; + } + + if (targetPath.startsWith(this.appBasePath)) { + return targetPath.slice(this.appBasePath.length); + } + return targetPath; + } +} diff --git a/packages/frontend-app-api/src/routing/RoutingProvider.tsx b/packages/frontend-app-api/src/routing/RoutingProvider.tsx new file mode 100644 index 0000000000..965faa3655 --- /dev/null +++ b/packages/frontend-app-api/src/routing/RoutingProvider.tsx @@ -0,0 +1,66 @@ +/* + * 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 React, { ReactNode } from 'react'; +import { + ExternalRouteRef, + RouteRef, + SubRouteRef, +} from '@backstage/frontend-plugin-api'; +import { + createVersionedValueMap, + createVersionedContext, +} from '@backstage/version-bridge'; +import { RouteResolver } from './RouteResolver'; +import { BackstageRouteObject } from './types'; + +const RoutingContext = createVersionedContext<{ 1: RouteResolver }>( + 'routing-context', +); + +type ProviderProps = { + routePaths: Map; + routeParents: Map; + routeObjects: BackstageRouteObject[]; + routeBindings: Map; + basePath?: string; + children: ReactNode; +}; + +// TODO(Rugvip): Migrate to a routing API instead +export const RoutingProvider = ({ + routePaths, + routeParents, + routeObjects, + routeBindings, + basePath = '', + children, +}: ProviderProps) => { + const resolver = new RouteResolver( + routePaths, + routeParents, + routeObjects, + routeBindings, + basePath, + ); + + const versionedValue = createVersionedValueMap({ 1: resolver }); + return ( + + {children} + + ); +}; diff --git a/packages/frontend-app-api/src/routing/collectRouteIds.test.ts b/packages/frontend-app-api/src/routing/collectRouteIds.test.ts new file mode 100644 index 0000000000..95a5afd8cd --- /dev/null +++ b/packages/frontend-app-api/src/routing/collectRouteIds.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createRouteRef, + createExternalRouteRef, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { collectRouteIds } from './collectRouteIds'; + +describe('collectRouteIds', () => { + it('should assign IDs to routes', () => { + const ref = createRouteRef(); + const extRef = createExternalRouteRef(); + + expect(String(ref)).toMatch( + /^RouteRef\{created at '.*collectRouteIds\.test\.ts.*'\}$/, + ); + expect(String(extRef)).toMatch( + /^ExternalRouteRef\{created at '.*collectRouteIds\.test\.ts.*'\}$/, + ); + + const collected = collectRouteIds([ + createPlugin({ id: 'test', routes: { ref }, externalRoutes: { extRef } }), + ]); + expect(Object.fromEntries(collected.routes)).toEqual({ + 'plugin.test.routes.ref': ref, + }); + expect(Object.fromEntries(collected.externalRoutes)).toEqual({ + 'plugin.test.externalRoutes.extRef': extRef, + }); + + expect(String(ref)).toBe('RouteRef{plugin.test.routes.ref}'); + expect(String(extRef)).toBe( + 'ExternalRouteRef{plugin.test.externalRoutes.extRef}', + ); + }); +}); diff --git a/packages/frontend-app-api/src/routing/collectRouteIds.ts b/packages/frontend-app-api/src/routing/collectRouteIds.ts new file mode 100644 index 0000000000..7e2a4cad2e --- /dev/null +++ b/packages/frontend-app-api/src/routing/collectRouteIds.ts @@ -0,0 +1,70 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + BackstagePlugin, + ExtensionOverrides, + RouteRef, + SubRouteRef, + ExternalRouteRef, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalRouteRef } from '../../../frontend-plugin-api/src/routing/RouteRef'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { toInternalExternalRouteRef } from '../../../frontend-plugin-api/src/routing/ExternalRouteRef'; + +/** @internal */ +export interface RouteRefsById { + routes: Map; + externalRoutes: Map; +} + +/** @internal */ +export function collectRouteIds( + features: (BackstagePlugin | ExtensionOverrides)[], +): RouteRefsById { + const routesById = new Map(); + const externalRoutesById = new Map(); + + for (const feature of features) { + if (feature.$$type !== '@backstage/BackstagePlugin') { + continue; + } + + for (const [name, ref] of Object.entries(feature.routes)) { + const refId = `plugin.${feature.id}.routes.${name}`; + if (routesById.has(refId)) { + throw new Error(`Unexpected duplicate route '${refId}'`); + } + + const internalRef = toInternalRouteRef(ref); + internalRef.setId(refId); + routesById.set(refId, ref); + } + for (const [name, ref] of Object.entries(feature.externalRoutes)) { + const refId = `plugin.${feature.id}.externalRoutes.${name}`; + if (externalRoutesById.has(refId)) { + throw new Error(`Unexpected duplicate external route '${refId}'`); + } + + const internalRef = toInternalExternalRouteRef(ref); + internalRef.setId(refId); + externalRoutesById.set(refId, ref); + } + } + + return { routes: routesById, externalRoutes: externalRoutesById }; +} diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts similarity index 93% rename from packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts rename to packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts index e70f588e0e..e0adf3062a 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.test.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts @@ -15,28 +15,31 @@ */ import React from 'react'; +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { extractRouteInfoFromAppNode } from './extractRouteInfoFromAppNode'; import { - BackstagePlugin, - RouteRef, - createRouteRef, -} from '@backstage/core-plugin-api'; -import { extractRouteInfoFromInstanceTree } from './extractRouteInfoFromInstanceTree'; -import { + AnyRouteRefParams, Extension, + RouteRef, coreExtensionData, createExtension, createExtensionInput, createPlugin, + createRouteRef, } from '@backstage/frontend-plugin-api'; -import { createInstances } from '../wiring/createApp'; import { MockConfigApi } from '@backstage/test-utils'; +import { createAppGraph } from '../graph'; +import { Core } from '../extensions/Core'; +import { CoreRoutes } from '../extensions/CoreRoutes'; +import { CoreNav } from '../extensions/CoreNav'; +import { CoreLayout } from '../extensions/CoreLayout'; -const ref1 = createRouteRef({ id: 'page1' }); -const ref2 = createRouteRef({ id: 'page2' }); -const ref3 = createRouteRef({ id: 'page3' }); -const ref4 = createRouteRef({ id: 'page4' }); -const ref5 = createRouteRef({ id: 'page5' }); -const refOrder = [ref1, ref2, ref3, ref4, ref5]; +const ref1 = createRouteRef(); +const ref2 = createRouteRef(); +const ref3 = createRouteRef(); +const ref4 = createRouteRef(); +const ref5 = createRouteRef(); +const refOrder: RouteRef[] = [ref1, ref2, ref3, ref4, ref5]; function createTestExtension(options: { id: string; @@ -74,12 +77,13 @@ function routeInfoFromExtensions(extensions: Extension[]) { id: 'test', extensions, }); - const { coreInstance } = createInstances({ + const graph = createAppGraph({ config: new MockConfigApi({}), + builtinExtensions: [Core, CoreRoutes, CoreNav, CoreLayout], features: [plugin], }); - return extractRouteInfoFromInstanceTree(coreInstance); + return extractRouteInfoFromAppNode(graph.root); } function sortedEntries(map: Map): [RouteRef, T][] { diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts similarity index 85% rename from packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts rename to packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts index fa9f87dce0..71991ee44e 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromInstanceTree.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import { RouteRef } from '@backstage/core-plugin-api'; -import { coreExtensionData } from '@backstage/frontend-plugin-api'; -import { ExtensionInstance } from '../wiring/createExtensionInstance'; +import { RouteRef, coreExtensionData } from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { BackstageRouteObject } from '../../../core-app-api/src/routing/types'; import { toLegacyPlugin } from '../wiring/createApp'; +import { BackstageRouteObject } from './types'; +import { AppNode } from '../graph'; // We always add a child that matches all subroutes but without any route refs. This makes // sure that we're always able to match each route no matter how deep the navigation goes. @@ -42,7 +41,7 @@ export function joinPaths(...paths: string[]): string { return normalized; } -export function extractRouteInfoFromInstanceTree(core: ExtensionInstance): { +export function extractRouteInfoFromAppNode(node: AppNode): { routePaths: Map; routeParents: Map; routeObjects: BackstageRouteObject[]; @@ -57,17 +56,17 @@ export function extractRouteInfoFromInstanceTree(core: ExtensionInstance): { const routeObjects = new Array(); function visit( - current: ExtensionInstance, + current: AppNode, collectedPath?: string, foundRefForCollectedPath: boolean = false, parentRef?: RouteRef, candidateParentRef?: RouteRef, parentObj?: BackstageRouteObject, ) { - const routePath = current - .getData(coreExtensionData.routePath) + const routePath = current.instance + ?.getData(coreExtensionData.routePath) ?.replace(/^\//, ''); - const routeRef = current.getData(coreExtensionData.routeRef); + const routeRef = current.instance?.getData(coreExtensionData.routeRef); const parentChildren = parentObj?.children ?? routeObjects; let currentObj = parentObj; @@ -109,13 +108,6 @@ export function extractRouteInfoFromInstanceTree(core: ExtensionInstance): { // Whenever a route ref is encountered, we need to give it a route path and position in the ref tree. if (routeRef) { - const routeRefId = (routeRef as any).id; // TODO: properly - if (routeRefId !== current.id) { - throw new Error( - `Route ref '${routeRefId}' must have the same ID as extension '${current.id}'`, - ); - } - // The first route ref we find after encountering a route path is selected to be used as the // parent ref further down the tree. We don't start using this candidate ref until we encounter // another route path though, at which point we repeat the process and select another candidate. @@ -132,12 +124,12 @@ export function extractRouteInfoFromInstanceTree(core: ExtensionInstance): { routeParents.set(routeRef, newParentRef); currentObj?.routeRefs.add(routeRef); - if (current.source) { - currentObj?.plugins.add(toLegacyPlugin(current.source)); + if (current.spec.source) { + currentObj?.plugins.add(toLegacyPlugin(current.spec.source)); } } - for (const children of current.attachments.values()) { + for (const children of current.edges.attachments.values()) { for (const child of children) { visit( child, @@ -151,7 +143,7 @@ export function extractRouteInfoFromInstanceTree(core: ExtensionInstance): { } } - visit(core); + visit(node); return { routePaths, routeParents, routeObjects }; } diff --git a/plugins/scaffolder/src/next/Router/index.ts b/packages/frontend-app-api/src/routing/index.ts similarity index 82% rename from plugins/scaffolder/src/next/Router/index.ts rename to packages/frontend-app-api/src/routing/index.ts index dac1db7b3a..8c26a732d3 100644 --- a/plugins/scaffolder/src/next/Router/index.ts +++ b/packages/frontend-app-api/src/routing/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,5 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { Router } from './Router'; -export type { NextRouterProps } from './Router'; + +export { type AppRouteBinder } from './resolveRouteBindings'; diff --git a/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts b/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts new file mode 100644 index 0000000000..d80a02e34d --- /dev/null +++ b/packages/frontend-app-api/src/routing/resolveRouteBindings.test.ts @@ -0,0 +1,120 @@ +/* + * 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 { + createExternalRouteRef, + createRouteRef, +} from '@backstage/frontend-plugin-api'; +import { resolveRouteBindings } from './resolveRouteBindings'; +import { ConfigReader } from '@backstage/config'; + +const emptyIds = { routes: new Map(), externalRoutes: new Map() }; + +describe('resolveRouteBindings', () => { + it('runs happy path', () => { + const external = { myRoute: createExternalRouteRef() }; + const ref = createRouteRef(); + const result = resolveRouteBindings( + ({ bind }) => { + bind(external, { myRoute: ref }); + }, + new ConfigReader({}), + emptyIds, + ); + + expect(result.get(external.myRoute)).toBe(ref); + }); + + it('throws on unknown keys', () => { + const external = { myRoute: createExternalRouteRef() }; + const ref = createRouteRef(); + expect(() => + resolveRouteBindings( + ({ bind }) => { + bind(external, { someOtherRoute: ref } as any); + }, + new ConfigReader({}), + emptyIds, + ), + ).toThrow('Key someOtherRoute is not an existing external route'); + }); + + it('reads bindings from config', () => { + const mySource = createExternalRouteRef(); + const myTarget = createRouteRef(); + const result = resolveRouteBindings( + () => {}, + new ConfigReader({ + app: { routes: { bindings: { mySource: 'myTarget' } } }, + }), + { + routes: new Map([['myTarget', myTarget]]), + externalRoutes: new Map([['mySource', mySource]]), + }, + ); + + expect(result.get(mySource)).toBe(myTarget); + }); + + it('throws on invalid config', () => { + expect(() => + resolveRouteBindings( + () => {}, + new ConfigReader({ app: { routes: { bindings: 'derp' } } }), + emptyIds, + ), + ).toThrow( + "Invalid type in config for key 'app.routes.bindings' in 'mock-config', got string, wanted object", + ); + + expect(() => + resolveRouteBindings( + () => {}, + new ConfigReader({ app: { routes: { bindings: { mySource: true } } } }), + emptyIds, + ), + ).toThrow( + "Invalid config at app.routes.bindings['mySource'], value must be a non-empty string", + ); + + expect(() => + resolveRouteBindings( + () => {}, + new ConfigReader({ + app: { routes: { bindings: { mySource: 'myTarget' } } }, + }), + emptyIds, + ), + ).toThrow( + "Invalid config at app.routes.bindings, 'mySource' is not a valid external route", + ); + + expect(() => + resolveRouteBindings( + () => {}, + new ConfigReader({ + app: { routes: { bindings: { mySource: 'myTarget' } } }, + }), + { + ...emptyIds, + externalRoutes: new Map([['mySource', createExternalRouteRef()]]), + }, + ), + ).toThrow( + "Invalid config at app.routes.bindings['mySource'], 'myTarget' is not a valid route", + ); + }); +}); diff --git a/packages/frontend-app-api/src/routing/resolveRouteBindings.ts b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts new file mode 100644 index 0000000000..f5a2e5bd94 --- /dev/null +++ b/packages/frontend-app-api/src/routing/resolveRouteBindings.ts @@ -0,0 +1,142 @@ +/* + * 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 { + RouteRef, + SubRouteRef, + ExternalRouteRef, +} from '@backstage/frontend-plugin-api'; +import { RouteRefsById } from './collectRouteIds'; +import { Config } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; + +/** + * Extracts a union of the keys in a map whose value extends the given type + * + * @ignore + */ +type KeysWithType = { + [key in keyof Obj]: Obj[key] extends Type ? key : never; +}[keyof Obj]; + +/** + * Takes a map Map required values and makes all keys matching Keys optional + * + * @ignore + */ +type PartialKeys< + Map extends { [name in string]: any }, + Keys extends keyof Map, +> = Partial> & Required>; + +/** + * Creates a map of target routes with matching parameters based on a map of external routes. + * + * @ignore + */ +type TargetRouteMap< + ExternalRoutes extends { [name: string]: ExternalRouteRef }, +> = { + [name in keyof ExternalRoutes]: ExternalRoutes[name] extends ExternalRouteRef< + infer Params, + any + > + ? RouteRef | SubRouteRef + : never; +}; + +/** + * A function that can bind from external routes of a given plugin, to concrete + * routes of other plugins. See {@link createApp}. + * + * @public + */ +export type AppRouteBinder = < + TExternalRoutes extends { [name: string]: ExternalRouteRef }, +>( + externalRoutes: TExternalRoutes, + targetRoutes: PartialKeys< + TargetRouteMap, + KeysWithType> + >, +) => void; + +/** @internal */ +export function resolveRouteBindings( + bindRoutes: ((context: { bind: AppRouteBinder }) => void) | undefined, + config: Config, + routesById: RouteRefsById, +): Map { + const result = new Map(); + + if (bindRoutes) { + const bind: AppRouteBinder = ( + externalRoutes, + targetRoutes: { [name: string]: RouteRef | SubRouteRef }, + ) => { + for (const [key, value] of Object.entries(targetRoutes)) { + const externalRoute = externalRoutes[key]; + if (!externalRoute) { + throw new Error(`Key ${key} is not an existing external route`); + } + if (!value && !externalRoute.optional) { + throw new Error( + `External route ${key} is required but was undefined`, + ); + } + if (value) { + result.set(externalRoute, value); + } + } + }; + bindRoutes({ bind }); + } + + const bindingsConfig = config.getOptionalConfig('app.routes.bindings'); + if (!bindingsConfig) { + return result; + } + + const bindings = bindingsConfig.get(); + for (const [externalRefId, targetRefId] of Object.entries(bindings)) { + if (typeof targetRefId !== 'string' || targetRefId === '') { + throw new Error( + `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string`, + ); + } + + const externalRef = routesById.externalRoutes.get(externalRefId); + if (!externalRef) { + throw new Error( + `Invalid config at app.routes.bindings, '${externalRefId}' is not a valid external route`, + ); + } + // Route bindings defined in config have lower priority than those defined in code + if (result.has(externalRef)) { + continue; + } + const targetRef = routesById.routes.get(targetRefId); + if (!targetRef) { + throw new Error( + `Invalid config at app.routes.bindings['${externalRefId}'], '${targetRefId}' is not a valid route`, + ); + } + + result.set(externalRef, targetRef); + } + + return result; +} diff --git a/packages/frontend-app-api/src/routing/types.ts b/packages/frontend-app-api/src/routing/types.ts new file mode 100644 index 0000000000..5f1ed9be84 --- /dev/null +++ b/packages/frontend-app-api/src/routing/types.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ExternalRouteRef, + RouteRef, + SubRouteRef, +} from '@backstage/frontend-plugin-api'; +import { BackstagePlugin as LegacyBackstagePlugin } from '@backstage/core-plugin-api'; + +/** @internal */ +export type AnyRouteRef = RouteRef | SubRouteRef | ExternalRouteRef; + +/** + * A duplicate of the react-router RouteObject, but with routeRef added + * @internal + */ +export interface BackstageRouteObject { + caseSensitive: boolean; + children?: BackstageRouteObject[]; + element: React.ReactNode; + path: string; + routeRefs: Set; + plugins: Set; +} diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index 65f278b49b..e9fb48f957 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -15,122 +15,14 @@ */ import { - createExtension, - createExtensionOverrides, createPageExtension, createPlugin, createThemeExtension, } from '@backstage/frontend-plugin-api'; -import { createApp, createInstances } from './createApp'; -import { screen } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; +import { createApp } from './createApp'; import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import React from 'react'; -import { createRouteRef } from '@backstage/core-plugin-api'; - -const extBaseConfig = { - id: 'test', - attachTo: { id: 'root', input: 'default' }, - output: {}, - factory() {}, -}; - -describe('createInstances', () => { - it('throws an error when a core extension is parametrized', () => { - const config = new MockConfigApi({ - app: { - extensions: [ - { - core: {}, - }, - ], - }, - }); - const features = [ - createPlugin({ - id: 'plugin', - extensions: [], - }), - ]; - expect(() => createInstances({ config, features })).toThrow( - "A 'core' extension configuration was detected, but the core extension is not configurable", - ); - }); - - it('throws an error when a core extension is overridden', () => { - const config = new MockConfigApi({}); - const features = [ - createPlugin({ - id: 'plugin', - extensions: [ - createExtension({ - id: 'core', - attachTo: { id: 'core.routes', input: 'route' }, - inputs: {}, - output: {}, - factory() {}, - }), - ], - }), - ]; - expect(() => createInstances({ config, features })).toThrow( - "The following plugin(s) are overriding the 'core' extension which is forbidden: plugin", - ); - }); - - it('throws an error when duplicated extensions are detected', () => { - const config = new MockConfigApi({}); - - const ExtensionA = createPageExtension({ - id: 'A', - defaultPath: '/', - routeRef: createRouteRef({ id: 'A.route' }), - loader: async () =>
Extension A
, - }); - - const ExtensionB = createPageExtension({ - id: 'B', - defaultPath: '/', - routeRef: createRouteRef({ id: 'B.route' }), - loader: async () =>
Extension B
, - }); - - const PluginA = createPlugin({ - id: 'A', - extensions: [ExtensionA, ExtensionA], - }); - - const PluginB = createPlugin({ - id: 'B', - extensions: [ExtensionA, ExtensionB, ExtensionB], - }); - - const features = [PluginA, PluginB]; - - expect(() => createInstances({ config, features })).toThrow( - "The following extensions are duplicated: The extension 'A' was provided 2 time(s) by the plugin 'A' and 1 time(s) by the plugin 'B', The extension 'B' was provided 2 time(s) by the plugin 'B'", - ); - }); - - it('throws an error when duplicated extension overrides are detected', () => { - expect(() => - createInstances({ - config: new MockConfigApi({}), - features: [ - createExtensionOverrides({ - extensions: [ - createExtension({ ...extBaseConfig, id: 'a' }), - createExtension({ ...extBaseConfig, id: 'a' }), - createExtension({ ...extBaseConfig, id: 'b' }), - ], - }), - createExtensionOverrides({ - extensions: [createExtension({ ...extBaseConfig, id: 'b' })], - }), - ], - }), - ).toThrow('The following extensions had duplicate overrides: a, b'); - }); -}); describe('createApp', () => { it('should allow themes to be installed', async () => { @@ -161,87 +53,41 @@ describe('createApp', () => { await expect(screen.findByText('Derp')).resolves.toBeInTheDocument(); }); - it('should log an app', () => { - const { coreInstance } = createInstances({ - config: new MockConfigApi({}), - features: [], + it('should deduplicate features keeping the last received one', async () => { + const duplicatedFeatureId = 'test'; + const app = createApp({ + configLoader: async () => new MockConfigApi({}), + features: [ + createPlugin({ + id: duplicatedFeatureId, + extensions: [ + createPageExtension({ + id: 'test.page.first', + defaultPath: '/', + loader: async () =>
First Page
, + }), + ], + }), + createPlugin({ + id: duplicatedFeatureId, + extensions: [ + createPageExtension({ + id: 'test.page.last', + defaultPath: '/', + loader: async () =>
Last Page
, + }), + ], + }), + ], }); - expect(String(coreInstance)).toMatchInlineSnapshot(` - " - root [ - - content [ - - ] - nav [ - - ] - - ] - themes [ - - - ] - " - `); - }); + await renderWithEffects(app.createRoot()); - it('should serialize an app as JSON', () => { - const { coreInstance } = createInstances({ - config: new MockConfigApi({}), - features: [], - }); - - expect(JSON.parse(JSON.stringify(coreInstance))).toMatchInlineSnapshot(` - { - "attachments": { - "root": [ - { - "attachments": { - "content": [ - { - "id": "core.routes", - "output": [ - "core.reactElement", - ], - }, - ], - "nav": [ - { - "id": "core.nav", - "output": [ - "core.reactElement", - ], - }, - ], - }, - "id": "core.layout", - "output": [ - "core.reactElement", - ], - }, - ], - "themes": [ - { - "id": "themes.light", - "output": [ - "core.theme", - ], - }, - { - "id": "themes.dark", - "output": [ - "core.theme", - ], - }, - ], - }, - "id": "core", - "output": [ - "core.reactElement", - ], - } - `); + await waitFor(() => + expect(screen.queryByText('First Page')).not.toBeInTheDocument(), + ); + await waitFor(() => + expect(screen.getByText('Last Page')).toBeInTheDocument(), + ); }); }); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index f262ecde72..4f7817314a 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -21,20 +21,13 @@ import { coreExtensionData, ExtensionDataRef, ExtensionOverrides, + RouteRef, + useRouteRef, } from '@backstage/frontend-plugin-api'; import { Core } from '../extensions/Core'; import { CoreRoutes } from '../extensions/CoreRoutes'; import { CoreLayout } from '../extensions/CoreLayout'; import { CoreNav } from '../extensions/CoreNav'; -import { - createExtensionInstance, - ExtensionInstance, -} from './createExtensionInstance'; -import { - ExtensionInstanceParameters, - mergeExtensionParameters, - readAppExtensionParameters, -} from './parameters'; import { AnyApiFactory, ApiHolder, @@ -44,11 +37,9 @@ import { ConfigApi, configApiRef, IconComponent, - RouteRef, BackstagePlugin as LegacyBackstagePlugin, featureFlagsApiRef, attachComponentData, - useRouteRef, identityApiRef, AppTheme, } from '@backstage/core-plugin-api'; @@ -57,7 +48,6 @@ import { ApiFactoryRegistry, ApiProvider, ApiResolver, - AppRouteBinder, AppThemeSelector, } from '@backstage/core-app-api'; @@ -75,10 +65,6 @@ import { defaultConfigLoaderSync } from '../../../core-app-api/src/app/defaultCo // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { overrideBaseUrlConfigs } from '../../../core-app-api/src/app/overrideBaseUrlConfigs'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { RoutingProvider } from '../../../core-app-api/src/routing/RoutingProvider'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { resolveRouteBindings } from '../../../core-app-api/src/app/resolveRouteBindings'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppLanguageSelector } from '../../../core-app-api/src/apis/implementations/AppLanguageApi/AppLanguageSelector'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { I18nextTranslationApi } from '../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi'; @@ -91,12 +77,26 @@ import { import { BrowserRouter, Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; import { DarkTheme, LightTheme } from '../extensions/themes'; -import { extractRouteInfoFromInstanceTree } from '../routing/extractRouteInfoFromInstanceTree'; +import { extractRouteInfoFromAppNode } from '../routing/extractRouteInfoFromAppNode'; import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; import { appLanguageApiRef, translationApiRef, } from '@backstage/core-plugin-api/alpha'; +import { AppRouteBinder } from '../routing'; +import { RoutingProvider } from '../routing/RoutingProvider'; +import { resolveRouteBindings } from '../routing/resolveRouteBindings'; +import { collectRouteIds } from '../routing/collectRouteIds'; +import { AppNode, createAppGraph } from '../graph'; + +const builtinExtensions = [ + Core, + CoreRoutes, + CoreNav, + CoreLayout, + LightTheme, + DarkTheme, +]; /** @public */ export interface ExtensionTreeNode { @@ -116,21 +116,39 @@ export interface ExtensionTree { export function createExtensionTree(options: { config: Config; }): ExtensionTree { - const features = getAvailableFeatures(); - const { instances } = createInstances({ + const features = getAvailableFeatures(options.config); + const graph = createAppGraph({ features, + builtinExtensions, config: options.config, }); + function convertNode(node?: AppNode): ExtensionTreeNode | undefined { + return ( + node && { + id: node.spec.id, + getData(ref: ExtensionDataRef): T | undefined { + return node.instance?.getData(ref); + }, + } + ); + } + return { getExtension(id: string): ExtensionTreeNode | undefined { - return instances.get(id); + return convertNode(graph.nodes.get(id)); }, getExtensionAttachments( id: string, inputName: string, ): ExtensionTreeNode[] { - return instances.get(id)?.attachments.get(inputName) ?? []; + return ( + graph.nodes + .get(id) + ?.edges.attachments.get(inputName) + ?.map(convertNode) + .filter((node): node is ExtensionTreeNode => Boolean(node)) ?? [] + ); }, getRootRoutes(): JSX.Element[] { return this.getExtensionAttachments('core.routes', 'routes').map(node => { @@ -180,92 +198,27 @@ export function createExtensionTree(options: { }; } -/** - * @internal - */ -export function createInstances(options: { - features: (BackstagePlugin | ExtensionOverrides)[]; - config: Config; -}) { - const builtinExtensions = [ - Core, - CoreRoutes, - CoreNav, - CoreLayout, - LightTheme, - DarkTheme, - ]; +function deduplicateFeatures( + allFeatures: (BackstagePlugin | ExtensionOverrides)[], +): (BackstagePlugin | ExtensionOverrides)[] { + // Start by removing duplicates by reference + const features = Array.from(new Set(allFeatures)); - // pull in default extension instance from discovered packages - // apply config to adjust default extension instances and add more - const extensionParams = mergeExtensionParameters({ - features: options.features, - builtinExtensions, - parameters: readAppExtensionParameters(options.config), - }); - - // TODO: validate the config of all extension instances - // We do it at this point to ensure that merging (if any) of config has already happened - - // Create attachment map so that we can look attachments up during instance creation - const attachmentMap = new Map< - string, - Map - >(); - for (const instanceParams of extensionParams) { - const extensionId = instanceParams.attachTo.id; - const pointId = instanceParams.attachTo.input; - let pointMap = attachmentMap.get(extensionId); - if (!pointMap) { - pointMap = new Map(); - attachmentMap.set(extensionId, pointMap); - } - - let instances = pointMap.get(pointId); - if (!instances) { - instances = []; - pointMap.set(pointId, instances); - } - - instances.push(instanceParams); - } - - const instances = new Map(); - - function createInstance( - instanceParams: ExtensionInstanceParameters, - ): ExtensionInstance { - const extensionId = instanceParams.extension.id; - const existingInstance = instances.get(extensionId); - if (existingInstance) { - return existingInstance; - } - - const attachments = new Map( - Array.from(attachmentMap.get(extensionId)?.entries() ?? []).map( - ([inputName, attachmentConfigs]) => { - return [inputName, attachmentConfigs.map(createInstance)]; - }, - ), - ); - - const newInstance = createExtensionInstance({ - extension: instanceParams.extension, - source: instanceParams.source, - config: instanceParams.config, - attachments, - }); - - instances.set(extensionId, newInstance); - - return newInstance; - } - - const coreInstance = createInstance( - extensionParams.find(p => p.extension.id === 'core')!, - ); - - return { coreInstance, instances }; + // Plugins are deduplicated by ID, last one wins + const seenIds = new Set(); + return features + .reverse() + .filter(feature => { + if (feature.$$type !== '@backstage/BackstagePlugin') { + return true; + } + if (seenIds.has(feature.id)) { + return false; + } + seenIds.add(feature.id); + return true; + }) + .reverse(); } /** @public */ @@ -286,18 +239,17 @@ export function createApp(options: { overrideBaseUrlConfigs(defaultConfigLoaderSync()), ); - const discoveredFeatures = getAvailableFeatures(); + const discoveredFeatures = getAvailableFeatures(config); const loadedFeatures = (await options.featureLoader?.({ config })) ?? []; - const allFeatures = Array.from( - new Set([ - ...discoveredFeatures, - ...(options.features ?? []), - ...loadedFeatures, - ]), - ); + const allFeatures = deduplicateFeatures([ + ...discoveredFeatures, + ...loadedFeatures, + ...(options.features ?? []), + ]); - const { coreInstance } = createInstances({ + const appGraph = createAppGraph({ features: allFeatures, + builtinExtensions, config, }); @@ -307,17 +259,25 @@ export function createApp(options: { ), ); + const routeIds = collectRouteIds(allFeatures); + const App = () => ( - + {/* TODO: set base path using the logic from AppRouter */} - {coreInstance.getData(coreExtensionData.reactElement)} + {appGraph.root.instance!.getData( + coreExtensionData.reactElement, + )} @@ -398,22 +358,19 @@ function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { }; } -function createApiHolder( - coreExtension: ExtensionInstance, - configApi: ConfigApi, -): ApiHolder { +function createApiHolder(core: AppNode, configApi: ConfigApi): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); const pluginApis = - coreExtension.attachments + core.edges.attachments .get('apis') - ?.map(e => e.getData(coreExtensionData.apiFactory)) + ?.map(e => e.instance?.getData(coreExtensionData.apiFactory)) .filter((x): x is AnyApiFactory => !!x) ?? []; const themeExtensions = - coreExtension.attachments + core.edges.attachments .get('themes') - ?.map(e => e.getData(coreExtensionData.theme)) + ?.map(e => e.instance?.getData(coreExtensionData.theme)) .filter((x): x is AppTheme => !!x) ?? []; for (const factory of [...defaultApis, ...pluginApis]) { @@ -466,6 +423,21 @@ function createApiHolder( factory: () => AppThemeSelector.createWithStorage(themeExtensions), }); + factoryRegistry.register('static', { + api: appLanguageApiRef, + deps: {}, + factory: () => AppLanguageSelector.createWithStorage(), + }); + + factoryRegistry.register('default', { + api: translationApiRef, + deps: { languageApi: appLanguageApiRef }, + factory: ({ languageApi }) => + I18nextTranslationApi.create({ + languageApi, + }), + }); + factoryRegistry.register('static', { api: configApiRef, deps: {}, diff --git a/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts b/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts deleted file mode 100644 index 6e69e99cb7..0000000000 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.test.ts +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - createExtension, - createExtensionDataRef, - createExtensionInput, - createSchemaFromZod, -} from '@backstage/frontend-plugin-api'; -import { createExtensionInstance } from './createExtensionInstance'; - -const testDataRef = createExtensionDataRef('test'); -const otherDataRef = createExtensionDataRef('other'); -const inputMirrorDataRef = createExtensionDataRef('mirror'); - -const simpleExtension = createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - other: otherDataRef.optional(), - }, - configSchema: createSchemaFromZod(z => - z.object({ - output: z.string().default('test'), - other: z.number().optional(), - }), - ), - factory({ bind, config }) { - bind({ test: config.output, other: config.other }); - }, -}); - -describe('createExtensionInstance', () => { - it('should create a simple extension instance', () => { - const attachments = new Map(); - const instance = createExtensionInstance({ - attachments, - config: undefined, - extension: simpleExtension, - }); - - expect(instance.id).toBe('core.test'); - expect(instance.attachments).toBe(attachments); - expect(instance.getData(testDataRef)).toEqual('test'); - }); - - it('should create an extension with different kind of inputs', () => { - const attachments = new Map([ - [ - 'optionalSingletonPresent', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'optionalSingletonPresent' }, - extension: simpleExtension, - }), - ], - ], - [ - 'singleton', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'singleton', other: 2 }, - extension: simpleExtension, - }), - ], - ], - [ - 'many', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many2', other: 3 }, - extension: simpleExtension, - }), - ], - ], - ]); - const instance = createExtensionInstance({ - attachments, - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - optionalSingletonPresent: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - optionalSingletonMissing: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true, optional: true }, - ), - singleton: createExtensionInput( - { - test: testDataRef, - other: otherDataRef.optional(), - }, - { singleton: true }, - ), - many: createExtensionInput({ - test: testDataRef, - other: otherDataRef.optional(), - }), - }, - output: { - inputMirror: inputMirrorDataRef, - }, - factory({ bind, inputs }) { - bind({ inputMirror: inputs }); - }, - }), - }); - - expect(instance.id).toBe('core.test'); - expect(instance.attachments).toBe(attachments); - expect(instance.getData(inputMirrorDataRef)).toEqual({ - optionalSingletonPresent: { test: 'optionalSingletonPresent' }, - singleton: { test: 'singleton', other: 2 }, - many: [{ test: 'many1' }, { test: 'many2', other: 3 }], - }); - }); - - it('should refuse to create an extension with invalid config', () => { - expect(() => - createExtensionInstance({ - attachments: new Map(), - config: { other: 'not-a-number' }, - extension: simpleExtension, - }), - ).toThrow( - "Invalid configuration for extension 'core.test'; caused by Error: Expected number, received string at 'other'", - ); - }); - - it('should forward extension factory errors', () => { - expect(() => - createExtensionInstance({ - attachments: new Map(), - config: { other: 'not-a-number' }, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory() { - const error = new Error('NOPE'); - error.name = 'NopeError'; - throw error; - }, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test'; caused by NopeError: NOPE", - ); - }); - - it('should refuse to create an instance with duplicate output', () => { - const attachments = new Map(); - expect(() => - createExtensionInstance({ - attachments, - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test1: testDataRef, - test2: testDataRef, - }, - factory({ bind }) { - bind({ test1: 'test', test2: 'test2' }); - }, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', duplicate extension data 'test' received via output 'test2'", - ); - }); - - it('should refuse to create an instance with disconnected output data', () => { - const attachments = new Map(); - expect(() => - createExtensionInstance({ - attachments, - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: { - test: testDataRef, - }, - factory({ bind }) { - bind({ nonexistent: 'test' } as any); - }, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', unknown output provided via 'nonexistent'", - ); - }); - - it('should refuse to create an instance with missing required input', () => { - expect(() => - createExtensionInstance({ - attachments: new Map(), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' is required but was not received", - ); - }); - - it('should refuse to create an instance with undeclared inputs', () => { - expect(() => - createExtensionInstance({ - attachments: new Map([ - [ - 'declared', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - ], - ], - [ - 'undeclared', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - ], - ], - ]), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - declared: createExtensionInput({ - test: testDataRef, - }), - }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared input 'undeclared' from extension 'core.test'", - ); - }); - - it('should refuse to create an instance with multiple undeclared inputs', () => { - expect(() => - createExtensionInstance({ - attachments: new Map([ - [ - 'undeclared1', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - ], - ], - [ - 'undeclared2', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - ], - ], - ]), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', received undeclared inputs 'undeclared1' from extension 'core.test' and 'undeclared2' from extensions 'core.test', 'core.test'", - ); - }); - - it('should refuse to create an instance with multiple inputs for required singleton', () => { - expect(() => - createExtensionInstance({ - attachments: new Map([ - [ - 'singleton', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many2' }, - extension: simpleExtension, - }), - ], - ], - ]), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', expected exactly one 'singleton' input but received multiple: 'core.test', 'core.test'", - ); - }); - - it('should refuse to create an instance with multiple inputs for optional singleton', () => { - expect(() => - createExtensionInstance({ - attachments: new Map([ - [ - 'singleton', - [ - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many1' }, - extension: simpleExtension, - }), - createExtensionInstance({ - attachments: new Map(), - config: { output: 'many2' }, - extension: simpleExtension, - }), - ], - ], - ]), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - test: testDataRef, - }, - { singleton: true, optional: true }, - ), - }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', expected at most one 'singleton' input but received multiple: 'core.test', 'core.test'", - ); - }); - - it('should refuse to create an instance with multiple inputs that did not provide required data', () => { - expect(() => - createExtensionInstance({ - attachments: new Map([ - [ - 'singleton', - [ - createExtensionInstance({ - attachments: new Map(), - config: undefined, - extension: simpleExtension, - }), - ], - ], - ]), - config: undefined, - extension: createExtension({ - id: 'core.test', - attachTo: { id: 'ignored', input: 'ignored' }, - inputs: { - singleton: createExtensionInput( - { - other: otherDataRef, - }, - { singleton: true }, - ), - }, - output: {}, - factory() {}, - }), - }), - ).toThrow( - "Failed to instantiate extension 'core.test', input 'singleton' did not receive required extension data 'other' from extension 'core.test'", - ); - }); -}); diff --git a/packages/frontend-app-api/src/wiring/discovery.test.ts b/packages/frontend-app-api/src/wiring/discovery.test.ts index 54294bbd45..6008ce6746 100644 --- a/packages/frontend-app-api/src/wiring/discovery.test.ts +++ b/packages/frontend-app-api/src/wiring/discovery.test.ts @@ -16,24 +16,29 @@ import { createPlugin } from '@backstage/frontend-plugin-api'; import { getAvailableFeatures } from './discovery'; +import { ConfigReader } from '@backstage/config'; const globalSpy = jest.fn(); Object.defineProperty(global, '__@backstage/discovered__', { get: globalSpy, }); +const config = new ConfigReader({ + app: { experimental: { packages: 'all' } }, +}); + describe('getAvailableFeatures', () => { afterEach(jest.resetAllMocks); it('should discover nothing with undefined global', () => { - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); }); it('should discover nothing with empty global', () => { globalSpy.mockReturnValue({ modules: [], }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); }); it('should discover a plugin', () => { @@ -41,24 +46,24 @@ describe('getAvailableFeatures', () => { globalSpy.mockReturnValue({ modules: [{ default: testPlugin }], }); - expect(getAvailableFeatures()).toEqual([testPlugin]); + expect(getAvailableFeatures(config)).toEqual([testPlugin]); }); it('should ignore garbage', () => { globalSpy.mockReturnValueOnce({ modules: [{ default: null }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: undefined }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: Symbol() }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: () => {} }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: 0 }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: false }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); globalSpy.mockReturnValueOnce({ modules: [{ default: true }] }); - expect(getAvailableFeatures()).toEqual([]); + expect(getAvailableFeatures(config)).toEqual([]); }); it('should discover multiple plugins', () => { @@ -72,7 +77,7 @@ describe('getAvailableFeatures', () => { { default: test3Plugin }, ], }); - expect(getAvailableFeatures()).toEqual([ + expect(getAvailableFeatures(config)).toEqual([ test1Plugin, test2Plugin, test3Plugin, diff --git a/packages/frontend-app-api/src/wiring/discovery.ts b/packages/frontend-app-api/src/wiring/discovery.ts index 14786c93d9..1181992d53 100644 --- a/packages/frontend-app-api/src/wiring/discovery.ts +++ b/packages/frontend-app-api/src/wiring/discovery.ts @@ -14,28 +14,75 @@ * limitations under the License. */ +import { Config, ConfigReader } from '@backstage/config'; import { BackstagePlugin, ExtensionOverrides, } from '@backstage/frontend-plugin-api'; interface DiscoveryGlobal { - modules: Array<{ name: string; default: unknown }>; + modules: Array<{ name: string; export?: string; default: unknown }>; +} + +function readPackageDetectionConfig(config: Config) { + const packages = config.getOptional('app.experimental.packages'); + if (packages === undefined || packages === null) { + return undefined; + } + + if (typeof packages === 'string') { + if (packages !== 'all') { + throw new Error( + `Invalid app.experimental.packages mode, got '${packages}', expected 'all'`, + ); + } + return {}; + } + + if (typeof packages !== 'object' || Array.isArray(packages)) { + throw new Error( + "Invalid config at 'app.experimental.packages', expected object", + ); + } + const packagesConfig = new ConfigReader( + packages, + 'app.experimental.packages', + ); + + return { + include: packagesConfig.getOptionalStringArray('include'), + exclude: packagesConfig.getOptionalStringArray('exclude'), + }; } /** * @public */ -export function getAvailableFeatures(): ( - | BackstagePlugin - | ExtensionOverrides -)[] { +export function getAvailableFeatures( + config: Config, +): (BackstagePlugin | ExtensionOverrides)[] { const discovered = ( window as { '__@backstage/discovered__'?: DiscoveryGlobal } )['__@backstage/discovered__']; + const detection = readPackageDetectionConfig(config); + if (!detection) { + return []; + } + return ( - discovered?.modules.map(m => m.default).filter(isBackstageFeature) ?? [] + discovered?.modules + .filter(({ name }) => { + if (detection.exclude?.includes(name)) { + return false; + } + if (detection.include && !detection.include.includes(name)) { + return false; + } + return true; + }) + .map(m => m.default) + .filter(isBackstageFeature) ?? [] ); } diff --git a/packages/frontend-app-api/src/wiring/parameters.ts b/packages/frontend-app-api/src/wiring/parameters.ts deleted file mode 100644 index 911f12f416..0000000000 --- a/packages/frontend-app-api/src/wiring/parameters.ts +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Config } from '@backstage/config'; -import { - BackstagePlugin, - Extension, - ExtensionOverrides, -} from '@backstage/frontend-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides'; -import { JsonValue } from '@backstage/types'; - -export interface ExtensionParameters { - id: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - config?: unknown; -} - -const knownExtensionParameters = ['attachTo', 'disabled', 'config']; - -// Since we'll never merge arrays in config the config reader context -// isn't too much of a help. Fall back to manual config reading logic -// as the Config interface makes it quite hard for us otherwise. -/** @internal */ -export function readAppExtensionParameters( - rootConfig: Config, -): ExtensionParameters[] { - const arr = rootConfig.getOptional('app.extensions'); - if (!Array.isArray(arr)) { - if (arr === undefined) { - return []; - } - // This will throw, and show which part of config had the wrong type - rootConfig.getConfigArray('app.extensions'); - return []; - } - - return arr.map((arrayEntry, arrayIndex) => - expandShorthandExtensionParameters(arrayEntry, arrayIndex), - ); -} - -/** @internal */ -export function expandShorthandExtensionParameters( - arrayEntry: JsonValue, - arrayIndex: number, -): ExtensionParameters { - function errorMsg(msg: string, key?: string, prop?: string) { - return `Invalid extension configuration at app.extensions[${arrayIndex}]${ - key ? `[${key}]` : '' - }${prop ? `.${prop}` : ''}, ${msg}`; - } - - // NOTE(freben): This check is intentionally not complete and doesn't check - // whether letters and digits are used, etc. It's not up to the config reading - // logic to decide what constitutes a valid extension ID; that should be - // decided by the logic that loads and instantiates the extensions. This check - // is just here to catch real mistakes or truly conceptually wrong input. - function assertValidId(id: string) { - if (!id || id !== id.trim()) { - throw new Error( - errorMsg('extension ID must not be empty or contain whitespace'), - ); - } - - if (id.includes('/')) { - let message = `extension ID must not contain slashes; got '${id}'`; - const good = id.split('/')[0]; - if (good) { - message += `, did you mean '${good}'?`; - } - throw new Error(errorMsg(message)); - } - } - - // Example YAML: - // - entity.card.about - if (typeof arrayEntry === 'string') { - assertValidId(arrayEntry); - return { - id: arrayEntry, - disabled: false, - }; - } - - // All remaining cases are single-key objects - if ( - typeof arrayEntry !== 'object' || - arrayEntry === null || - Array.isArray(arrayEntry) - ) { - throw new Error(errorMsg('must be a string or an object')); - } - const keys = Object.keys(arrayEntry); - if (keys.length !== 1) { - const joinedKeys = keys.length ? `'${keys.join("', '")}'` : 'none'; - throw new Error(errorMsg(`must have exactly one key, got ${joinedKeys}`)); - } - - const id = String(keys[0]); - const value = arrayEntry[id]; - assertValidId(id); - - // This example covers a potentially common mistake in the syntax - // Example YAML: - // - entity.card.about: - if (value === null) { - return { - id, - disabled: false, - }; - } - - // Example YAML: - // - catalog.page.cicd: false - if (typeof value === 'boolean') { - return { - id, - disabled: !value, - }; - } - - // The remaining case is the generic object. Example YAML: - // - tech-radar.page: - // at: core.router/routes - // disabled: false - // config: - // path: /tech-radar - // width: 1500 - // height: 800 - if (typeof value !== 'object' || Array.isArray(value)) { - // We don't mention null here - we don't want people to explicitly enter - // - entity.card.about: null - throw new Error(errorMsg('value must be a boolean or object', id)); - } - - const attachTo = value.attachTo as { id: string; input: string } | undefined; - const disabled = value.disabled; - const config = value.config; - - if (attachTo !== undefined) { - if ( - attachTo === null || - typeof attachTo !== 'object' || - Array.isArray(attachTo) - ) { - throw new Error(errorMsg('must be an object', id, 'attachTo')); - } - if (typeof attachTo.id !== 'string' || attachTo.id === '') { - throw new Error( - errorMsg('must be a non-empty string', id, 'attachTo.id'), - ); - } - if (typeof attachTo.input !== 'string' || attachTo.input === '') { - throw new Error( - errorMsg('must be a non-empty string', id, 'attachTo.input'), - ); - } - } - if (disabled !== undefined && typeof disabled !== 'boolean') { - throw new Error(errorMsg('must be a boolean', id, 'disabled')); - } - if ( - config !== undefined && - (typeof config !== 'object' || config === null || Array.isArray(config)) - ) { - throw new Error(errorMsg('must be an object', id, 'config')); - } - - const unknownKeys = Object.keys(value).filter( - k => !knownExtensionParameters.includes(k), - ); - if (unknownKeys.length > 0) { - throw new Error( - errorMsg( - `unknown parameter; expected one of '${knownExtensionParameters.join( - "', '", - )}'`, - id, - unknownKeys.join(', '), - ), - ); - } - - return { - id, - attachTo, - disabled, - config, - }; -} - -export interface ExtensionInstanceParameters { - extension: Extension; - source?: BackstagePlugin; - attachTo: { id: string; input: string }; - config?: unknown; -} - -/** @internal */ -export function mergeExtensionParameters(options: { - features: (BackstagePlugin | ExtensionOverrides)[]; - builtinExtensions: Extension[]; - parameters: Array; -}): ExtensionInstanceParameters[] { - const { builtinExtensions, parameters } = options; - - const plugins = options.features.filter( - (f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin', - ); - const overrides = options.features.filter( - (f): f is ExtensionOverrides => - f.$$type === '@backstage/ExtensionOverrides', - ); - - const pluginExtensions = plugins.flatMap(source => { - return source.extensions.map(extension => ({ ...extension, source })); - }); - const overrideExtensions = overrides.flatMap( - override => toInternalExtensionOverrides(override).extensions, - ); - - // Prevent core override - if (pluginExtensions.some(({ id }) => id === 'core')) { - const pluginIds = pluginExtensions - .filter(({ id }) => id === 'core') - .map(({ source }) => source.id); - throw new Error( - `The following plugin(s) are overriding the 'core' extension which is forbidden: ${pluginIds.join( - ',', - )}`, - ); - } - - if (overrideExtensions.some(({ id }) => id === 'root')) { - throw new Error( - `An extension override is overriding the 'root' extension which is forbidden`, - ); - } - const overrideExtensionIds = overrideExtensions.map(({ id }) => id); - if (overrideExtensionIds.length !== new Set(overrideExtensionIds).size) { - const counts = new Map(); - for (const id of overrideExtensionIds) { - counts.set(id, (counts.get(id) ?? 0) + 1); - } - const duplicated = Array.from(counts.entries()) - .filter(([, count]) => count > 1) - .map(([id]) => id); - throw new Error( - `The following extensions had duplicate overrides: ${duplicated.join( - ', ', - )}`, - ); - } - - const configuredExtensions = [ - ...pluginExtensions.map(({ source, ...extension }) => ({ - extension, - params: { - source, - attachTo: extension.attachTo, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), - ...builtinExtensions.map(extension => ({ - extension, - params: { - source: undefined, - attachTo: extension.attachTo, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), - ]; - - // Install all extension overrides - for (const extension of overrideExtensions) { - // Check if our override is overriding an extension that already exists - const index = configuredExtensions.findIndex( - e => e.extension.id === extension.id, - ); - if (index !== -1) { - // Only implementation, attachment point and default disabled status are overridden, the source is kept - configuredExtensions[index].extension = extension; - configuredExtensions[index].params.attachTo = extension.attachTo; - configuredExtensions[index].params.disabled = extension.disabled; - } else { - // Add the extension as a new one when not overriding an existing one - configuredExtensions.push({ - extension, - params: { - source: undefined, - attachTo: extension.attachTo, - disabled: extension.disabled, - config: undefined, - }, - }); - } - } - - const duplicatedExtensionIds = new Set(); - const duplicatedExtensionData = configuredExtensions.reduce< - Record> - >((data, { extension, params }) => { - const extensionId = extension.id; - const extensionData = data?.[extensionId]; - if (extensionData) duplicatedExtensionIds.add(extensionId); - const pluginId = params.source?.id ?? 'internal'; - const pluginCount = extensionData?.[pluginId] ?? 0; - return { - ...data, - [extensionId]: { ...extensionData, [pluginId]: pluginCount + 1 }, - }; - }, {}); - - if (duplicatedExtensionIds.size > 0) { - throw new Error( - `The following extensions are duplicated: ${Array.from( - duplicatedExtensionIds, - ) - .map( - extensionId => - `The extension '${extensionId}' was provided ${Object.keys( - duplicatedExtensionData[extensionId], - ) - .map( - pluginId => - `${duplicatedExtensionData[extensionId][pluginId]} time(s) by the plugin '${pluginId}'`, - ) - .join(' and ')}`, - ) - .join(', ')}`, - ); - } - - for (const overrideParam of parameters) { - const extensionId = overrideParam.id; - - // Prevent core parametrization - if (extensionId === 'core') { - throw new Error( - "A 'core' extension configuration was detected, but the core extension is not configurable", - ); - } - - const existingIndex = configuredExtensions.findIndex( - e => e.extension.id === extensionId, - ); - if (existingIndex !== -1) { - const existing = configuredExtensions[existingIndex]; - if (overrideParam.attachTo) { - existing.params.attachTo = overrideParam.attachTo; - } - if (overrideParam.config) { - // TODO: merge config? - existing.params.config = overrideParam.config; - } - if ( - Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled) - ) { - existing.params.disabled = Boolean(overrideParam.disabled); - if (!existing.params.disabled) { - // bump - configuredExtensions.splice(existingIndex, 1); - configuredExtensions.push(existing); - } - } - } else { - throw new Error(`Extension ${extensionId} does not exist`); - } - } - - return configuredExtensions - .filter(override => !override.params.disabled) - .map(param => ({ - extension: param.extension, - attachTo: param.params.attachTo, - source: param.params.source, - config: param.params.config, - })); -} diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 056ff0b143..8fa9a49726 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/frontend-plugin-api +## 0.2.0 + +### Minor Changes + +- 06432f900c: Extension attachment point is now configured via `attachTo: { id, input }` instead of `at: 'id/input'`. +- 4461d87d5a: Removed support for the new `useRouteRef`. + +### Patch Changes + +- d3a37f55c0: Add support for `SidebarGroup` on the sidebar item extension. +- 2ecd33618a: Plugins can now be assigned `routes` and `externalRoutes` when created. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- c1e9ca6500: Added `createExtensionOverrides` which can be used to install a collection of extensions in an app that will replace any existing ones. +- 52366db5b3: Added `createThemeExtension` and `coreExtensionData.theme`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/types@1.1.1 + ## 0.2.0-next.2 ### Minor Changes diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 071b617851..ac8d164fae 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -7,15 +7,12 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { AppTheme } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; -import { RouteRef } from '@backstage/core-plugin-api'; import { z } from 'zod'; import { ZodSchema } from 'zod'; import { ZodTypeDef } from 'zod'; @@ -41,6 +38,23 @@ export type AnyExtensionInputMap = { >; }; +// @public (undocumented) +export type AnyExternalRoutes = { + [name in string]: ExternalRouteRef; +}; + +// @public +export type AnyRouteRefParams = + | { + [param in string]: string; + } + | undefined; + +// @public (undocumented) +export type AnyRoutes = { + [name in string]: RouteRef; +}; + // @public (undocumented) export interface BackstagePlugin< Routes extends AnyRoutes = AnyRoutes, @@ -79,7 +93,7 @@ export const coreExtensionData: { reactElement: ConfigurableExtensionDataRef; routePath: ConfigurableExtensionDataRef; apiFactory: ConfigurableExtensionDataRef; - routeRef: ConfigurableExtensionDataRef; + routeRef: ConfigurableExtensionDataRef, {}>; navTarget: ConfigurableExtensionDataRef; theme: ConfigurableExtensionDataRef; }; @@ -173,10 +187,35 @@ export function createExtensionOverrides( options: ExtensionOverridesOptions, ): ExtensionOverrides; +// @public +export function createExternalRouteRef< + TParams extends + | { + [param in TParamKeys]: string; + } + | undefined = undefined, + TOptional extends boolean = false, + TParamKeys extends string = string, +>(options?: { + readonly params?: string extends TParamKeys + ? (keyof TParams)[] + : TParamKeys[]; + optional?: TOptional; +}): ExternalRouteRef< + keyof TParams extends never + ? undefined + : string extends TParamKeys + ? TParams + : { + [param in TParamKeys]: string; + }, + TOptional +>; + // @public export function createNavItemExtension(options: { id: string; - routeRef: RouteRef; + routeRef: RouteRef; title: string; icon: IconComponent; }): Extension<{ @@ -215,17 +254,46 @@ export function createPageExtension< // @public (undocumented) export function createPlugin< - Routes extends AnyRoutes = AnyRoutes, - ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, + Routes extends AnyRoutes = {}, + ExternalRoutes extends AnyExternalRoutes = {}, >( options: PluginOptions, ): BackstagePlugin; +// @public +export function createRouteRef< + TParams extends + | { + [param in TParamKeys]: string; + } + | undefined = undefined, + TParamKeys extends string = string, +>(config?: { + readonly params: string extends TParamKeys ? (keyof TParams)[] : TParamKeys[]; +}): RouteRef< + keyof TParams extends never + ? undefined + : string extends TParamKeys + ? TParams + : { + [param in TParamKeys]: string; + } +>; + // @public (undocumented) export function createSchemaFromZod( schemaCreator: (zImpl: typeof z) => ZodSchema, ): PortableSchema; +// @public +export function createSubRouteRef< + Path extends string, + ParentParams extends AnyRouteRefParams = never, +>(config: { + path: Path; + parent: RouteRef; +}): MakeSubRouteRef, ParentParams>; + // @public (undocumented) export function createThemeExtension(theme: AppTheme): Extension; @@ -270,6 +338,10 @@ export interface ExtensionBoundaryProps { // (undocumented) children: ReactNode; // (undocumented) + id: string; + // (undocumented) + routable?: boolean; + // (undocumented) source?: BackstagePlugin; } @@ -344,11 +416,24 @@ export interface ExtensionOverridesOptions { extensions: Extension[]; } +// @public +export interface ExternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, + TOptional extends boolean = boolean, +> { + // (undocumented) + readonly $$type: '@backstage/ExternalRouteRef'; + // (undocumented) + readonly optional: TOptional; + // (undocumented) + readonly T: TParams; +} + // @public (undocumented) export type NavTarget = { title: string; icon: IconComponent; - routeRef: RouteRef<{}>; + routeRef: RouteRef; }; // @public (undocumented) @@ -371,4 +456,51 @@ export type PortableSchema = { parse: (input: unknown) => TOutput; schema: JsonObject; }; + +// @public +export type RouteFunc = ( + ...[params]: TParams extends undefined + ? readonly [] + : readonly [params: TParams] +) => string; + +// @public +export interface RouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> { + // (undocumented) + readonly $$type: '@backstage/RouteRef'; + // (undocumented) + readonly T: TParams; +} + +// @public +export interface SubRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> { + // (undocumented) + readonly $$type: '@backstage/SubRouteRef'; + // (undocumented) + readonly path: string; + // (undocumented) + readonly T: TParams; +} + +// @public +export function useRouteRef< + TOptional extends boolean, + TParams extends AnyRouteRefParams, +>( + routeRef: ExternalRouteRef, +): TParams extends true ? RouteFunc | undefined : RouteFunc; + +// @public +export function useRouteRef( + routeRef: RouteRef | SubRouteRef, +): RouteFunc; + +// @public +export function useRouteRefParams( + _routeRef: RouteRef | SubRouteRef, +): Params; ``` diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index d80e2baee4..528d86e0d1 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.2.0-next.2", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,18 +27,22 @@ "@backstage/frontend-app-api": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3" + "@testing-library/react": "^14.0.0", + "history": "^5.3.0" }, "files": [ "dist" ], "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "dependencies": { + "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/types": "workspace:^", + "@backstage/version-bridge": "workspace:^", + "@material-ui/core": "^4.12.4", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", "zod": "^3.21.4", diff --git a/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx new file mode 100644 index 0000000000..1191b75a1d --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx @@ -0,0 +1,80 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { Component, PropsWithChildren } from 'react'; +// TODO: Dependency on MUI should be removed from core packages +import { Button } from '@material-ui/core'; +import { ErrorPanel } from '@backstage/core-components'; +import { BackstagePlugin } from '../wiring'; + +type DefaultErrorBoundaryFallbackProps = PropsWithChildren<{ + plugin?: BackstagePlugin; + error: Error; + resetError: () => void; +}>; + +const DefaultErrorBoundaryFallback = ({ + plugin, + error, + resetError, +}: DefaultErrorBoundaryFallbackProps) => { + const title = `Error in ${plugin?.id}`; + + return ( + + + + ); +}; + +type ErrorBoundaryProps = PropsWithChildren<{ plugin?: BackstagePlugin }>; +type ErrorBoundaryState = { error?: Error }; + +/** @internal */ +export class ErrorBoundary extends Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + static getDerivedStateFromError(error: Error) { + return { error }; + } + + state: ErrorBoundaryState = { error: undefined }; + + handleErrorReset = () => { + this.setState({ error: undefined }); + }; + + render() { + const { error } = this.state; + const { plugin, children } = this.props; + + if (error) { + // TODO: use a configurable error boundary fallback + return ( + + ); + } + + return children; + } +} diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx new file mode 100644 index 0000000000..704cafda2d --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx @@ -0,0 +1,134 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect } from 'react'; +import { screen, waitFor } from '@testing-library/react'; +import { + MockAnalyticsApi, + MockConfigApi, + TestApiProvider, + renderWithEffects, +} from '@backstage/test-utils'; +import { ExtensionBoundary } from './ExtensionBoundary'; +import { + Extension, + coreExtensionData, + createExtension, + createPlugin, +} from '../wiring'; +import { analyticsApiRef, useAnalytics } from '@backstage/core-plugin-api'; +import { createApp } from '@backstage/frontend-app-api'; +import { JsonObject } from '@backstage/types'; +import { createRouteRef } from '../routing'; + +function renderExtensionInTestApp( + extension: Extension, + options?: { + config?: JsonObject; + }, +) { + const { config = {} } = options ?? {}; + + const app = createApp({ + features: [ + createPlugin({ + id: 'plugin', + extensions: [extension], + }), + ], + configLoader: async () => new MockConfigApi(config), + }); + + return renderWithEffects(app.createRoot()); +} + +const wrapInBoundaryExtension = (element: JSX.Element) => { + const id = 'plugin.extension'; + const routeRef = createRouteRef(); + return createExtension({ + id, + attachTo: { id: 'core.routes', input: 'routes' }, + output: { + element: coreExtensionData.reactElement, + path: coreExtensionData.routePath, + routeRef: coreExtensionData.routeRef.optional(), + }, + factory({ bind, source }) { + bind({ + routeRef, + path: '/', + element: ( + + {element} + + ), + }); + }, + }); +}; + +describe('ExtensionBoundary', () => { + it('should render children when there is no error', async () => { + const text = 'Text Component'; + const TextComponent = () => { + return

{text}

; + }; + await renderExtensionInTestApp(wrapInBoundaryExtension()); + await waitFor(() => expect(screen.getByText(text)).toBeInTheDocument()); + }); + + it('should show app error component when an error is thrown', async () => { + const error = 'Something went wrong'; + const ErrorComponent = () => { + throw new Error(error); + }; + await renderExtensionInTestApp(wrapInBoundaryExtension()); + await waitFor(() => expect(screen.getByText(error)).toBeInTheDocument()); + }); + + it('should wrap children with analytics context', async () => { + const action = 'render'; + const subject = 'analytics'; + const analyticsApiMock = new MockAnalyticsApi(); + + const AnalyticsComponent = () => { + const analytics = useAnalytics(); + useEffect(() => { + analytics.captureEvent(action, subject); + }, [analytics]); + return null; + }; + + await renderExtensionInTestApp( + wrapInBoundaryExtension( + + + , + ), + ); + + await waitFor(() => + expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + action, + subject, + context: { + extension: 'plugin.extension', + routeRef: 'unknown', + }, + }), + ); + }); +}); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx index c6a218c15f..a9ea297216 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx @@ -14,16 +14,59 @@ * limitations under the License. */ -import React, { ReactNode } from 'react'; +import React, { PropsWithChildren, ReactNode, useEffect } from 'react'; +import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '../wiring'; +import { ErrorBoundary } from './ErrorBoundary'; +import { ExtensionSuspense } from './ExtensionSuspense'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { routableExtensionRenderedEvent } from '../../../core-plugin-api/src/analytics/Tracker'; + +type RouteTrackerProps = PropsWithChildren<{ + disableTracking?: boolean; +}>; + +const RouteTracker = (props: RouteTrackerProps) => { + const { disableTracking, children } = props; + const analytics = useAnalytics(); + + // This event, never exposed to end-users of the analytics API, + // helps inform which extension metadata gets associated with a + // navigation event when the route navigated to is a gathered + // mountpoint. + useEffect(() => { + if (disableTracking) return; + analytics.captureEvent(routableExtensionRenderedEvent, ''); + }, [analytics, disableTracking]); + + return <>{children}; +}; /** @public */ export interface ExtensionBoundaryProps { - children: ReactNode; + id: string; source?: BackstagePlugin; + routable?: boolean; + children: ReactNode; } /** @public */ export function ExtensionBoundary(props: ExtensionBoundaryProps) { - return <>{props.children}; + const { id, source, routable, children } = props; + + // Skipping "routeRef" attribute in the new system, the extension "id" should provide more insight + const attributes = { + extension: id, + pluginId: source?.id, + }; + + return ( + + + + {children} + + + + ); } diff --git a/packages/frontend-plugin-api/src/components/ExtensionSuspense.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionSuspense.test.tsx new file mode 100644 index 0000000000..166c57b83b --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ExtensionSuspense.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { lazy } from 'react'; +import { screen, waitFor } from '@testing-library/react'; +import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; +import { ExtensionSuspense } from './ExtensionSuspense'; + +describe('ExtensionSuspense', () => { + it('should render the app progress component as fallback', async () => { + const LazyComponent = lazy(() => new Promise(() => {})); + + await renderWithEffects( + wrapInTestApp( + + + , + ), + ); + + expect(screen.getByTestId('progress')).toBeInTheDocument(); + }); + + it('should render the lazy loaded children component', async () => { + const LazyComponent = lazy(() => + Promise.resolve({ default: () =>
Lazy Component
}), + ); + + await renderWithEffects( + wrapInTestApp( + + + , + ), + ); + + await waitFor(() => + expect(screen.getByText('Lazy Component')).toBeInTheDocument(), + ); + }); +}); diff --git a/packages/frontend-plugin-api/src/components/ExtensionSuspense.tsx b/packages/frontend-plugin-api/src/components/ExtensionSuspense.tsx new file mode 100644 index 0000000000..e80f59f09c --- /dev/null +++ b/packages/frontend-plugin-api/src/components/ExtensionSuspense.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { ReactNode, Suspense } from 'react'; +import { useApp } from '@backstage/core-plugin-api'; + +/** @public */ +export interface ExtensionSuspenseProps { + children: ReactNode; +} + +/** @public */ +export function ExtensionSuspense(props: ExtensionSuspenseProps) { + const { children } = props; + + const app = useApp(); + const { Progress } = app.getComponents(); + + return }>{children}; +} diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 8e5a9e9f33..f728261072 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -21,7 +21,8 @@ import { createExtension, coreExtensionData, } from '../wiring'; -import { AnyExtensionInputMap, Expand } from '../wiring/createExtension'; +import { AnyExtensionInputMap } from '../wiring/createExtension'; +import { Expand } from '../types'; /** @public */ export function createApiExtension< diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index f208c975b7..ee38dda016 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -14,9 +14,10 @@ * limitations under the License. */ -import { IconComponent, RouteRef } from '@backstage/core-plugin-api'; +import { IconComponent } from '@backstage/core-plugin-api'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; import { coreExtensionData, createExtension } from '../wiring'; +import { RouteRef } from '../routing'; /** * Helper for creating extensions for a nav item. @@ -24,7 +25,7 @@ import { coreExtensionData, createExtension } from '../wiring'; */ export function createNavItemExtension(options: { id: string; - routeRef: RouteRef; + routeRef: RouteRef; title: string; icon: IconComponent; }) { diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx index 125bf3495d..37d97e7621 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.test.tsx @@ -15,10 +15,23 @@ */ import React from 'react'; +import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; +import { useAnalytics } from '@backstage/core-plugin-api'; +import { waitFor } from '@testing-library/react'; import { PortableSchema } from '../schema'; -import { coreExtensionData, createExtensionInput } from '../wiring'; +import { + ExtensionInputValues, + coreExtensionData, + createExtensionInput, + createPlugin, +} from '../wiring'; import { createPageExtension } from './createPageExtension'; +jest.mock('@backstage/core-plugin-api', () => ({ + ...jest.requireActual('@backstage/core-plugin-api'), + useAnalytics: jest.fn(), +})); + describe('createPageExtension', () => { it('creates the extension properly', () => { const configSchema: PortableSchema<{ path: string }> = { @@ -100,4 +113,35 @@ describe('createPageExtension', () => { factory: expect.any(Function), }); }); + + it('capture page view event in analytics', async () => { + const captureEvent = jest.fn(); + + (useAnalytics as jest.Mock).mockReturnValue({ + captureEvent, + }); + + const extension = createPageExtension({ + id: 'plugin.page', + defaultPath: '/', + loader: async () =>
Component
, + }); + + extension.factory({ + bind: (values: ExtensionInputValues) => + renderWithEffects( + wrapInTestApp(values.element as unknown as JSX.Element), + ), + source: createPlugin({ id: 'plugin ' }), + config: { path: '/' }, + inputs: {}, + }); + + await waitFor(() => + expect(captureEvent).toHaveBeenCalledWith( + '_ROUTABLE-EXTENSION-RENDERED', + '', + ), + ); + }); }); diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index 712c55f896..f05182149b 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ -import { RouteRef } from '@backstage/core-plugin-api'; -import React from 'react'; +import React, { lazy } from 'react'; import { ExtensionBoundary } from '../components'; import { createSchemaFromZod, PortableSchema } from '../schema'; import { @@ -23,8 +22,10 @@ import { createExtension, Extension, ExtensionInputValues, + AnyExtensionInputMap, } from '../wiring'; -import { AnyExtensionInputMap, Expand } from '../wiring/createExtension'; +import { RouteRef } from '../routing'; +import { Expand } from '../types'; /** * Helper for creating extensions for a routable React page component. @@ -54,6 +55,8 @@ export function createPageExtension< }) => Promise; }, ): Extension { + const { id } = options; + const configSchema = 'configSchema' in options ? options.configSchema @@ -62,18 +65,18 @@ export function createPageExtension< ) as PortableSchema); return createExtension({ - id: options.id, + id, attachTo: options.attachTo ?? { id: 'core.routes', input: 'routes' }, + configSchema, + inputs: options.inputs, disabled: options.disabled, output: { element: coreExtensionData.reactElement, path: coreExtensionData.routePath, routeRef: coreExtensionData.routeRef.optional(), }, - inputs: options.inputs, - configSchema, factory({ bind, config, inputs, source }) { - const LazyComponent = React.lazy(() => + const ExtensionComponent = lazy(() => options .loader({ config, inputs }) .then(element => ({ default: () => element })), @@ -81,14 +84,12 @@ export function createPageExtension< bind({ path: config.path, + routeRef: options.routeRef, element: ( - - - - + + ), - routeRef: options.routeRef, }); }, }); diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index 512723b5d4..73abf28ce4 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -22,5 +22,6 @@ export * from './components'; export * from './extensions'; +export * from './routing'; export * from './schema'; export * from './wiring'; diff --git a/packages/frontend-plugin-api/src/routing/ExternalRouteRef.test.ts b/packages/frontend-plugin-api/src/routing/ExternalRouteRef.test.ts new file mode 100644 index 0000000000..727dc1f53e --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/ExternalRouteRef.test.ts @@ -0,0 +1,114 @@ +/* + * 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 { + ExternalRouteRef, + createExternalRouteRef, + toInternalExternalRouteRef, +} from './ExternalRouteRef'; +import { AnyRouteRefParams } from './types'; + +describe('ExternalRouteRef', () => { + it('should be created', () => { + const routeRef: ExternalRouteRef = createExternalRouteRef(); + const internal = toInternalExternalRouteRef(routeRef); + expect(internal.getParams()).toEqual([]); + expect(internal.optional).toBe(false); + + expect(String(internal)).toMatch( + /^ExternalRouteRef\{created at '.*ExternalRouteRef\.test\.ts.*'\}$/, + ); + internal.setId('some-id'); + expect(String(internal)).toBe('ExternalRouteRef{some-id}'); + }); + + it('should be created as optional', () => { + const routeRef: ExternalRouteRef = createExternalRouteRef({ + params: [], + optional: true, + }); + const internal = toInternalExternalRouteRef(routeRef); + expect(internal.getParams()).toEqual([]); + expect(internal.optional).toEqual(true); + }); + + it('should be created with params', () => { + const routeRef: ExternalRouteRef<{ + x: string; + y: string; + }> = createExternalRouteRef({ params: ['x', 'y'] }); + const internal = toInternalExternalRouteRef(routeRef); + expect(internal.getParams()).toEqual(['x', 'y']); + expect(internal.optional).toEqual(false); + }); + + it('should be created as optional with params', () => { + const routeRef: ExternalRouteRef<{ + x: string; + y: string; + }> = createExternalRouteRef({ params: ['x', 'y'], optional: true }); + const internal = toInternalExternalRouteRef(routeRef); + expect(internal.getParams()).toEqual(['x', 'y']); + expect(internal.optional).toEqual(true); + }); + + it('should properly infer and validate parameter types and assignments', () => { + function checkRouteRef< + T extends AnyRouteRefParams, + TOptional extends boolean, + TCheck extends TOptional, + >( + _ref: ExternalRouteRef, + _params: T extends undefined ? undefined : T, + _optional: TCheck, + ) {} + + const _1 = createExternalRouteRef({ params: ['notX'] }); + checkRouteRef(_1, { notX: '' }, false); + // @ts-expect-error + checkRouteRef(_1, { x: '' }, false); + + const _2 = createExternalRouteRef({ params: ['x'], optional: true }); + checkRouteRef(_2, { x: '' }, true); + // @ts-expect-error + checkRouteRef(_2, undefined, false); + + const _3 = createExternalRouteRef({ params: ['x', 'y'] }); + checkRouteRef(_3, { x: '', y: '' }, false); + // @ts-expect-error + checkRouteRef(_3, { x: '' }, false); + // @ts-expect-error + checkRouteRef(_3, { x: '', y: '', z: '' }, false); + + const _4 = createExternalRouteRef({ params: [] }); + checkRouteRef(_4, undefined, false); + // @ts-expect-error + checkRouteRef(_4, { x: '' }); + + const _5 = createExternalRouteRef(); + checkRouteRef(_5, undefined, false); + // @ts-expect-error + checkRouteRef(_5, { x: '' }); + + const _6 = createExternalRouteRef({ optional: true }); + checkRouteRef(_6, undefined, true); + // @ts-expect-error + checkRouteRef(_6, undefined, false); + + // To avoid complains about missing expectations and unused vars + expect([_1, _2, _3, _4, _5, _6].join('')).toEqual(expect.any(String)); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/ExternalRouteRef.ts b/packages/frontend-plugin-api/src/routing/ExternalRouteRef.ts new file mode 100644 index 0000000000..c9aabdef27 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/ExternalRouteRef.ts @@ -0,0 +1,131 @@ +/* + * 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 { RouteRefImpl } from './RouteRef'; +import { describeParentCallSite } from './describeParentCallSite'; +import { AnyRouteRefParams } from './types'; + +/** + * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system}. + * + * @public + */ +export interface ExternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, + TOptional extends boolean = boolean, +> { + readonly $$type: '@backstage/ExternalRouteRef'; + readonly T: TParams; + readonly optional: TOptional; +} + +/** @internal */ +export interface InternalExternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, + TOptional extends boolean = boolean, +> extends ExternalRouteRef { + readonly version: 'v1'; + getParams(): string[]; + getDescription(): string; + + setId(id: string): void; +} + +/** @internal */ +export function toInternalExternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, + TOptional extends boolean = boolean, +>( + resource: ExternalRouteRef, +): InternalExternalRouteRef { + const r = resource as InternalExternalRouteRef; + if (r.$$type !== '@backstage/ExternalRouteRef') { + throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`); + } + + return r; +} + +/** @internal */ +export function isExternalRouteRef(opaque: { + $$type: string; +}): opaque is ExternalRouteRef { + return opaque.$$type === '@backstage/ExternalRouteRef'; +} + +/** @internal */ +class ExternalRouteRefImpl + extends RouteRefImpl + implements InternalExternalRouteRef +{ + readonly $$type = '@backstage/ExternalRouteRef' as any; + + constructor( + readonly optional: boolean, + readonly params: string[] = [], + creationSite: string, + ) { + super(params, creationSite); + } +} + +/** + * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system}. + * + * @param options - Description of the route reference to be created. + * @public + */ +export function createExternalRouteRef< + TParams extends { [param in TParamKeys]: string } | undefined = undefined, + TOptional extends boolean = false, + TParamKeys extends string = string, +>(options?: { + /** + * The parameters that will be provided to the external route reference. + */ + readonly params?: string extends TParamKeys + ? (keyof TParams)[] + : TParamKeys[]; + + /** + * Whether or not this route is optional, defaults to false. + * + * Optional external routes are not required to be bound in the app, and + * if they aren't, `useExternalRouteRef` will return `undefined`. + */ + optional?: TOptional; +}): ExternalRouteRef< + keyof TParams extends never + ? undefined + : string extends TParamKeys + ? TParams + : { [param in TParamKeys]: string }, + TOptional +> { + return new ExternalRouteRefImpl( + Boolean(options?.optional), + options?.params as string[] | undefined, + describeParentCallSite(), + ) as ExternalRouteRef; +} diff --git a/packages/frontend-plugin-api/src/routing/RouteRef.test.ts b/packages/frontend-plugin-api/src/routing/RouteRef.test.ts new file mode 100644 index 0000000000..de7a3de887 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/RouteRef.test.ts @@ -0,0 +1,93 @@ +/* + * 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 { AnyRouteRefParams } from './types'; +import { RouteRef, createRouteRef, toInternalRouteRef } from './RouteRef'; + +describe('RouteRef', () => { + it('should be created and have a mutable ID', () => { + const routeRef: RouteRef = createRouteRef(); + const internal = toInternalRouteRef(routeRef); + expect(internal.T).toBe(undefined); + expect(internal.getParams()).toEqual([]); + expect(internal.getDescription()).toMatch(/RouteRef\.test\.ts/); + + expect(String(internal)).toMatch( + /^RouteRef\{created at .*RouteRef\.test\.ts.*\}$/, + ); + + expect(() => internal.setId('')).toThrow( + 'RouteRef id must be a non-empty string', + ); + + internal.setId('some-id'); + expect(String(internal)).toBe('RouteRef{some-id}'); + + expect(() => internal.setId('some-other-id')).toThrow( + "RouteRef was referenced twice as both 'some-id' and 'some-other-id'", + ); + }); + + it('should be created with params', () => { + const routeRef: RouteRef<{ + x: string; + y: string; + }> = createRouteRef({ + params: ['x', 'y'], + }); + const internal = toInternalRouteRef(routeRef); + expect(internal.getParams()).toEqual(['x', 'y']); + expect(internal.getDescription()).toMatch(/RouteRef\.test\.ts/); + }); + + it('should properly infer and validate parameter types and assignments', () => { + function checkRouteRef( + _ref: RouteRef, + _params: T extends undefined ? undefined : T, + ) {} + + const _1 = createRouteRef({ params: ['x'] }); + checkRouteRef(_1, { x: '' }); + // @ts-expect-error + checkRouteRef(_1, { y: '' }); + // @ts-expect-error + checkRouteRef(_1, undefined); + + const _2 = createRouteRef({ params: ['x', 'y'] }); + checkRouteRef(_2, { x: '', y: '' }); + // @ts-expect-error + checkRouteRef(_2, { x: '' }); + // @ts-expect-error + checkRouteRef(_2, undefined); + // @ts-expect-error + checkRouteRef(_2, { x: '', z: '' }); + // @ts-expect-error + checkRouteRef(_2, { x: '', y: '', z: '' }); + + const _3 = createRouteRef({ params: [] }); + checkRouteRef(_3, undefined); + // @ts-expect-error + checkRouteRef(_3, { x: '' }); + + const _4 = createRouteRef(); + checkRouteRef(_4, undefined); + // @ts-expect-error + checkRouteRef(_4, { x: '' }); + + // To avoid complains about missing expectations and unused vars + expect([_1, _2, _3, _4].join('')).toEqual(expect.any(String)); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/RouteRef.ts b/packages/frontend-plugin-api/src/routing/RouteRef.ts new file mode 100644 index 0000000000..da562e5273 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/RouteRef.ts @@ -0,0 +1,136 @@ +/* + * 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 { describeParentCallSite } from './describeParentCallSite'; +import { AnyRouteRefParams } from './types'; + +/** + * Absolute route reference. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system}. + * + * @public + */ +export interface RouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> { + readonly $$type: '@backstage/RouteRef'; + readonly T: TParams; +} + +/** @internal */ +export interface InternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> extends RouteRef { + readonly version: 'v1'; + getParams(): string[]; + getDescription(): string; + + setId(id: string): void; +} + +/** @internal */ +export function toInternalRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +>(resource: RouteRef): InternalRouteRef { + const r = resource as InternalRouteRef; + if (r.$$type !== '@backstage/RouteRef') { + throw new Error(`Invalid RouteRef, bad type '${r.$$type}'`); + } + + return r; +} + +/** @internal */ +export function isRouteRef(opaque: { $$type: string }): opaque is RouteRef { + return opaque.$$type === '@backstage/RouteRef'; +} + +/** @internal */ +export class RouteRefImpl implements InternalRouteRef { + readonly $$type = '@backstage/RouteRef'; + readonly version = 'v1'; + declare readonly T: never; + + #id?: string; + #params: string[]; + #creationSite: string; + + constructor(readonly params: string[] = [], creationSite: string) { + this.#params = params; + this.#creationSite = creationSite; + } + + getParams(): string[] { + return this.#params; + } + + getDescription(): string { + if (this.#id) { + return this.#id; + } + return `created at '${this.#creationSite}'`; + } + + get #name() { + return this.$$type.slice('@backstage/'.length); + } + + setId(id: string): void { + if (!id) { + throw new Error(`${this.#name} id must be a non-empty string`); + } + if (this.#id) { + throw new Error( + `${this.#name} was referenced twice as both '${this.#id}' and '${id}'`, + ); + } + this.#id = id; + } + + toString(): string { + return `${this.#name}{${this.getDescription()}}`; + } +} + +/** + * Create a {@link RouteRef} from a route descriptor. + * + * @param config - Description of the route reference to be created. + * @public + */ +export function createRouteRef< + // Params is the type that we care about and the one to be embedded in the route ref. + // For example, given the params ['name', 'kind'], Params will be {name: string, kind: string} + TParams extends { [param in TParamKeys]: string } | undefined = undefined, + TParamKeys extends string = string, +>(config?: { + /** A list of parameter names that the path that this route ref is bound to must contain */ + readonly params: string extends TParamKeys ? (keyof TParams)[] : TParamKeys[]; +}): RouteRef< + keyof TParams extends never + ? undefined + : string extends TParamKeys + ? TParams + : { [param in TParamKeys]: string } +> { + return new RouteRefImpl( + config?.params as string[] | undefined, + describeParentCallSite(), + ) as RouteRef; +} diff --git a/packages/frontend-plugin-api/src/routing/SubRouteRef.test.ts b/packages/frontend-plugin-api/src/routing/SubRouteRef.test.ts new file mode 100644 index 0000000000..b04728c49b --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/SubRouteRef.test.ts @@ -0,0 +1,139 @@ +/* + * 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 { AnyRouteRefParams } from './types'; +import { + SubRouteRef, + createSubRouteRef, + toInternalSubRouteRef, +} from './SubRouteRef'; +import { createRouteRef, toInternalRouteRef } from './RouteRef'; + +const parent = createRouteRef(); +const parentX = createRouteRef({ params: ['x'] }); + +describe('SubRouteRef', () => { + it('should be created', () => { + const internalParent = toInternalRouteRef(createRouteRef()); + const routeRef: SubRouteRef = createSubRouteRef({ + parent: internalParent, + path: '/foo', + }); + const internal = toInternalSubRouteRef(routeRef); + expect(internal.path).toBe('/foo'); + expect(internal.T).toBe(undefined); + expect(internal.getParent()).toBe(internalParent); + expect(internal.getParams()).toEqual([]); + expect(String(internal)).toMatch( + /SubRouteRef\{at \/foo with parent created at '.*SubRouteRef\.test\.ts.*'\}/, + ); + internalParent.setId('some-id'); + expect(String(internal)).toBe('SubRouteRef{at /foo with parent some-id}'); + }); + + it('should be created with params', () => { + const routeRef: SubRouteRef<{ bar: string }> = createSubRouteRef({ + parent, + path: '/foo/:bar', + }); + const internal = toInternalSubRouteRef(routeRef); + expect(internal.path).toBe('/foo/:bar'); + expect(internal.getParent()).toBe(parent); + expect(internal.getParams()).toEqual(['bar']); + }); + + it('should be created with merged params', () => { + const routeRef: SubRouteRef<{ + x: string; + y: string; + z: string; + }> = createSubRouteRef({ + parent: parentX, + path: '/foo/:y/:z', + }); + const internal = toInternalSubRouteRef(routeRef); + expect(internal.path).toBe('/foo/:y/:z'); + expect(internal.getParent()).toBe(parentX); + expect(internal.getParams()).toEqual(['x', 'y', 'z']); + }); + + it('should be created with params from parent', () => { + const routeRef: SubRouteRef<{ x: string }> = createSubRouteRef({ + parent: parentX, + path: '/foo/bar', + }); + const internal = toInternalSubRouteRef(routeRef); + expect(internal.path).toBe('/foo/bar'); + expect(internal.getParent()).toBe(parentX); + expect(internal.getParams()).toEqual(['x']); + }); + + it.each([ + ['foo', "SubRouteRef path must start with '/', got 'foo'"], + [':foo', "SubRouteRef path must start with '/', got ':foo'"], + ['', "SubRouteRef path must start with '/', got ''"], + ['/', "SubRouteRef path must not end with '/', got '/'"], + ['/foo/', "SubRouteRef path must not end with '/', got '/foo/'"], + ['/foo/:x', 'SubRouteRef may not have params that overlap with its parent'], + ['/:/foo', "SubRouteRef path has invalid param, got ''"], + ['/:inva:lid/foo', "SubRouteRef path has invalid param, got 'inva:lid'"], + ['/:inva=lid/foo', "SubRouteRef path has invalid param, got 'inva=lid'"], + ])('should throw if path is invalid, %s', (path, message) => { + expect(() => createSubRouteRef({ path, parent: parentX })).toThrow(message); + }); + + it('should properly infer and parse path parameters', () => { + function checkSubRouteRef( + _ref: SubRouteRef, + _params: T extends undefined ? undefined : T, + ) {} + + const _1 = createSubRouteRef({ parent, path: '/foo/bar' }); + // @ts-expect-error + checkSubRouteRef(_1, { x: '' }); + checkSubRouteRef(_1, undefined); + + const _2 = createSubRouteRef({ parent, path: '/foo/:x/:y' }); + // @ts-expect-error + checkSubRouteRef(_2, undefined); + // @ts-expect-error + checkSubRouteRef(_2, { x: '', z: '' }); + // @ts-expect-error + checkSubRouteRef(_2, { y: '' }); + // @ts-expect-error + checkSubRouteRef(_2, { x: '', y: '', z: '' }); + checkSubRouteRef(_2, { x: '', y: '' }); + + const _3 = createSubRouteRef({ parent: parentX, path: '/foo' }); + // @ts-expect-error + checkSubRouteRef(_3, undefined); + // @ts-expect-error + checkSubRouteRef(_3, { y: '' }); + checkSubRouteRef(_3, { x: '' }); + + const _4 = createSubRouteRef({ parent: parentX, path: '/foo/:y' }); + // @ts-expect-error + checkSubRouteRef(_4, undefined); + // @ts-expect-error + checkSubRouteRef(_4, { x: '', z: '' }); + // @ts-expect-error + checkSubRouteRef(_4, { y: '' }); + checkSubRouteRef(_4, { x: '', y: '' }); + + // To avoid complains about missing expectations and unused vars + expect([_1, _2, _3, _4].join('')).toEqual(expect.any(String)); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/SubRouteRef.ts b/packages/frontend-plugin-api/src/routing/SubRouteRef.ts new file mode 100644 index 0000000000..74996ab4e7 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/SubRouteRef.ts @@ -0,0 +1,208 @@ +/* + * 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 { RouteRef, toInternalRouteRef } from './RouteRef'; +import { AnyRouteRefParams } from './types'; + +// Should match the pattern in react-router +const PARAM_PATTERN = /^\w+$/; + +/** + * Descriptor of a route relative to an absolute {@link RouteRef}. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system}. + * + * @public + */ +export interface SubRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> { + readonly $$type: '@backstage/SubRouteRef'; + + readonly T: TParams; + + readonly path: string; +} + +/** @internal */ +export interface InternalSubRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +> extends SubRouteRef { + readonly version: 'v1'; + + getParams(): string[]; + getParent(): RouteRef; + getDescription(): string; +} + +/** @internal */ +export function toInternalSubRouteRef< + TParams extends AnyRouteRefParams = AnyRouteRefParams, +>(resource: SubRouteRef): InternalSubRouteRef { + const r = resource as InternalSubRouteRef; + if (r.$$type !== '@backstage/SubRouteRef') { + throw new Error(`Invalid SubRouteRef, bad type '${r.$$type}'`); + } + + return r; +} + +/** @internal */ +export function isSubRouteRef(opaque: { + $$type: string; +}): opaque is SubRouteRef { + return opaque.$$type === '@backstage/SubRouteRef'; +} + +/** @internal */ +export class SubRouteRefImpl + implements SubRouteRef +{ + readonly $$type = '@backstage/SubRouteRef'; + readonly version = 'v1'; + declare readonly T: never; + + #params: string[]; + #parent: RouteRef; + + constructor(readonly path: string, params: string[], parent: RouteRef) { + this.#params = params; + this.#parent = parent; + } + + getParams(): string[] { + return this.#params; + } + + getParent(): RouteRef { + return this.#parent; + } + + getDescription(): string { + const parent = toInternalRouteRef(this.#parent); + return `at ${this.path} with parent ${parent.getDescription()}`; + } + + toString(): string { + return `SubRouteRef{${this.getDescription()}}`; + } +} + +/** + * Used in {@link PathParams} type declaration. + * @ignore + */ +type ParamPart = S extends `:${infer Param}` ? Param : never; + +/** + * Used in {@link PathParams} type declaration. + * @ignore + */ +type ParamNames = S extends `${infer Part}/${infer Rest}` + ? ParamPart | ParamNames + : ParamPart; +/** + * This utility type helps us infer a Param object type from a string path + * For example, `/foo/:bar/:baz` inferred to `{ bar: string, baz: string }` + * @ignore + */ +type PathParams = { [name in ParamNames]: string }; + +/** + * Merges a param object type with an optional params type into a params object. + * @ignore + */ +type MergeParams< + P1 extends { [param in string]: string }, + P2 extends AnyRouteRefParams, +> = (P1[keyof P1] extends never ? {} : P1) & (P2 extends undefined ? {} : P2); + +/** + * Convert empty params to undefined. + * @ignore + */ +type TrimEmptyParams = + keyof Params extends never ? undefined : Params; + +/** + * Creates a SubRouteRef type given the desired parameters and parent route parameters. + * The parameters types are merged together while ensuring that there is no overlap between the two. + * + * @ignore + */ +type MakeSubRouteRef< + Params extends { [param in string]: string }, + ParentParams extends AnyRouteRefParams, +> = keyof Params & keyof ParentParams extends never + ? SubRouteRef>> + : never; + +/** + * Create a {@link SubRouteRef} from a route descriptor. + * + * @param config - Description of the route reference to be created. + * @public + */ +export function createSubRouteRef< + Path extends string, + ParentParams extends AnyRouteRefParams = never, +>(config: { + path: Path; + parent: RouteRef; +}): MakeSubRouteRef, ParentParams> { + const { path, parent } = config; + type Params = PathParams; + + const internalParent = toInternalRouteRef(parent); + const parentParams = internalParent.getParams(); + + // Collect runtime parameters from the path, e.g. ['bar', 'baz'] from '/foo/:bar/:baz' + const pathParams = path + .split('/') + .filter(p => p.startsWith(':')) + .map(p => p.substring(1)); + const params = [...parentParams, ...pathParams]; + + if (parentParams.some(p => pathParams.includes(p as string))) { + throw new Error( + 'SubRouteRef may not have params that overlap with its parent', + ); + } + if (!path.startsWith('/')) { + throw new Error(`SubRouteRef path must start with '/', got '${path}'`); + } + if (path.endsWith('/')) { + throw new Error(`SubRouteRef path must not end with '/', got '${path}'`); + } + for (const param of pathParams) { + if (!PARAM_PATTERN.test(param)) { + throw new Error(`SubRouteRef path has invalid param, got '${param}'`); + } + } + + // We ensure that the type of the return type is sane here + const subRouteRef = new SubRouteRefImpl( + path, + params as string[], + parent, + ) as SubRouteRef>>; + + // But skip type checking of the return value itself, because the conditional + // type checking of the parent parameter overlap is tricky to express. + return subRouteRef as any; +} diff --git a/packages/frontend-plugin-api/src/routing/describeParentCallSite.test.ts b/packages/frontend-plugin-api/src/routing/describeParentCallSite.test.ts new file mode 100644 index 0000000000..03a94dcb45 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/describeParentCallSite.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describeParentCallSite } from './describeParentCallSite'; + +class ChromeError { + name = 'Error'; + message = 'eHgtF5hmbrXyiEvo'; + get stack() { + return `Error: eHgtF5hmbrXyiEvo + at describeParentCallSite (describeParentCallSite.js:1:11) + at parent (parent.js:2:22) + at caller (parent-caller.js:3:33) + at other.js:3:33`; + } +} + +class SafariError { + name = 'Error'; + message = 'eHgtF5hmbrXyiEvo'; + get stack() { + return `describeParentCallSite@describeParentCallSite.js:1:11 +parent@parent.js:2:22 +caller@parent-caller.js:3:33 +code@other.js:3:33`; + } +} + +class FirefoxError { + name = 'Error'; + message = 'eHgtF5hmbrXyiEvo'; + get stack() { + return `describeParentCallSite@describeParentCallSite.js:1:11 +parent@parent.js:2:22 +caller@parent-caller.js:3:33 +@other.js:3:33 +`; + } +} + +describe('describeParentCallSite', () => { + it('should work in Chrome', () => { + function myFactory() { + return describeParentCallSite(ChromeError); + } + function myCaller() { + return myFactory(); + } + expect(myCaller()).toBe('parent-caller.js:3:33'); + }); + + it('should work in Safari', () => { + function myFactory() { + return describeParentCallSite(SafariError); + } + function myCaller() { + return myFactory(); + } + expect(myCaller()).toBe('parent-caller.js:3:33'); + }); + + it('should work in Firefox', () => { + function myFactory() { + return describeParentCallSite(FirefoxError); + } + function myCaller() { + return myFactory(); + } + expect(myCaller()).toBe('parent-caller.js:3:33'); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/describeParentCallSite.ts b/packages/frontend-plugin-api/src/routing/describeParentCallSite.ts new file mode 100644 index 0000000000..72997e07db --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/describeParentCallSite.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const MESSAGE_MARKER = 'eHgtF5hmbrXyiEvo'; + +/** + * Internal helper that describes the location of the parent caller. + * @internal + */ +export function describeParentCallSite( + ErrorConstructor: { new (message: string): Error } = Error, +): string { + const { stack } = new ErrorConstructor(MESSAGE_MARKER); + if (!stack) { + return ''; + } + + // Safari and Firefox don't include the error itself in the stack + const startIndex = stack.includes(MESSAGE_MARKER) + ? stack.indexOf('\n') + 1 + : 0; + const secondEntryStart = + stack.indexOf('\n', stack.indexOf('\n', startIndex) + 1) + 1; + const secondEntryEnd = stack.indexOf('\n', secondEntryStart); + + const line = stack.substring(secondEntryStart, secondEntryEnd).trim(); + if (!line) { + return 'unknown'; + } + + // Below we try to extract the location for different browsers. + // Since RouteRefs are declared at the top-level of modules the caller name isn't interesting. + + // Chrome + if (line.includes('(')) { + return line.substring(line.indexOf('(') + 1, line.indexOf(')')); + } + + // Safari & Firefox + if (line.includes('@')) { + return line.substring(line.indexOf('@') + 1); + } + + // Give up + return line; +} diff --git a/packages/frontend-plugin-api/src/routing/index.ts b/packages/frontend-plugin-api/src/routing/index.ts new file mode 100644 index 0000000000..6c25f725b5 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/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. + */ + +export type { AnyRouteRefParams } from './types'; +export { createRouteRef, type RouteRef } from './RouteRef'; +export { createSubRouteRef, type SubRouteRef } from './SubRouteRef'; +export { + createExternalRouteRef, + type ExternalRouteRef, +} from './ExternalRouteRef'; +export { useRouteRef, type RouteFunc } from './useRouteRef'; +export { useRouteRefParams } from './useRouteRefParams'; diff --git a/packages/frontend-plugin-api/src/routing/types.ts b/packages/frontend-plugin-api/src/routing/types.ts new file mode 100644 index 0000000000..3bf1323210 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/types.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * Catch-all type for route params. + * + * @public + */ +export type AnyRouteRefParams = { [param in string]: string } | undefined; diff --git a/packages/frontend-plugin-api/src/routing/useRouteRef.test.tsx b/packages/frontend-plugin-api/src/routing/useRouteRef.test.tsx new file mode 100644 index 0000000000..dcd56f81a6 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/useRouteRef.test.tsx @@ -0,0 +1,157 @@ +/* + * 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 { renderHook } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter, Router } from 'react-router-dom'; +import { createVersionedContextForTesting } from '@backstage/version-bridge'; +import { useRouteRef } from './useRouteRef'; +import { createRouteRef } from './RouteRef'; +import { createBrowserHistory } from 'history'; + +describe('v1 consumer', () => { + const context = createVersionedContextForTesting('routing-context'); + + afterEach(() => { + context.reset(); + }); + + it('should resolve routes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); + + const routeRef = createRouteRef(); + + const renderedHook = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }); + + const routeFunc = renderedHook.result.current; + expect(routeFunc()).toBe('/hello'); + expect(resolve).toHaveBeenCalledWith( + routeRef, + expect.objectContaining({ + pathname: '/my-page', + }), + ); + }); + + it('re-resolves the routeFunc when the search parameters change', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); + + const routeRef = createRouteRef(); + const history = createBrowserHistory(); + history.push('/my-page'); + + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }); + + expect(resolve).toHaveBeenCalledTimes(1); + + history.push('/my-new-page'); + rerender(); + + expect(resolve).toHaveBeenCalledTimes(2); + }); + + it('does not re-resolve the routeFunc the location pathname does not change', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); + + const routeRef = createRouteRef(); + const history = createBrowserHistory(); + history.push('/my-page'); + + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }); + + expect(resolve).toHaveBeenCalledTimes(1); + + history.push('/my-page'); + rerender(); + + expect(resolve).toHaveBeenCalledTimes(1); + }); + + it('does not re-resolve the routeFunc when the search parameter changes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); + + const routeRef = createRouteRef(); + const history = createBrowserHistory(); + history.push('/my-page'); + + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }); + + expect(resolve).toHaveBeenCalledTimes(1); + + history.push('/my-page?foo=bar'); + rerender(); + + expect(resolve).toHaveBeenCalledTimes(1); + }); + + it('does not re-resolve the routeFunc when the hash parameter changes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); + + const routeRef = createRouteRef(); + const history = createBrowserHistory(); + history.push('/my-page'); + + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }); + + expect(resolve).toHaveBeenCalledTimes(1); + + history.push('/my-page#foo'); + rerender(); + + expect(resolve).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/useRouteRef.tsx b/packages/frontend-plugin-api/src/routing/useRouteRef.tsx new file mode 100644 index 0000000000..dfcb110930 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/useRouteRef.tsx @@ -0,0 +1,134 @@ +/* + * 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 { useMemo } from 'react'; +import { matchRoutes, useLocation } from 'react-router-dom'; +import { useVersionedContext } from '@backstage/version-bridge'; +import { AnyRouteRefParams } from './types'; +import { RouteRef } from './RouteRef'; +import { SubRouteRef } from './SubRouteRef'; +import { ExternalRouteRef } from './ExternalRouteRef'; + +/** + * TS magic for handling route parameters. + * + * @remarks + * + * The extra TS magic here is to require a single params argument if the RouteRef + * had at least one param defined, but require 0 arguments if there are no params defined. + * Without this we'd have to pass in empty object to all parameter-less RouteRefs + * just to make TypeScript happy, or we would have to make the argument optional in + * which case you might forget to pass it in when it is actually required. + * + * @public + */ +export type RouteFunc = ( + ...[params]: TParams extends undefined + ? readonly [] + : readonly [params: TParams] +) => string; + +/** + * @internal + */ +export interface RouteResolver { + resolve( + anyRouteRef: + | RouteRef + | SubRouteRef + | ExternalRouteRef, + sourceLocation: Parameters[1], + ): RouteFunc | undefined; +} + +/** + * React hook for constructing URLs to routes. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system} + * + * @param routeRef - The ref to route that should be converted to URL. + * @returns A function that will in turn return the concrete URL of the `routeRef`. + * @public + */ +export function useRouteRef< + TOptional extends boolean, + TParams extends AnyRouteRefParams, +>( + routeRef: ExternalRouteRef, +): TParams extends true ? RouteFunc | undefined : RouteFunc; + +/** + * React hook for constructing URLs to routes. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system} + * + * @param routeRef - The ref to route that should be converted to URL. + * @returns A function that will in turn return the concrete URL of the `routeRef`. + * @public + */ +export function useRouteRef( + routeRef: RouteRef | SubRouteRef, +): RouteFunc; + +/** + * React hook for constructing URLs to routes. + * + * @remarks + * + * See {@link https://backstage.io/docs/plugins/composability#routing-system} + * + * @param routeRef - The ref to route that should be converted to URL. + * @returns A function that will in turn return the concrete URL of the `routeRef`. + * @public + */ +export function useRouteRef( + routeRef: + | RouteRef + | SubRouteRef + | ExternalRouteRef, +): RouteFunc | undefined { + const { pathname } = useLocation(); + const versionedContext = useVersionedContext<{ 1: RouteResolver }>( + 'routing-context', + ); + if (!versionedContext) { + throw new Error('Routing context is not available'); + } + + const resolver = versionedContext.atVersion(1); + const routeFunc = useMemo( + () => resolver && resolver.resolve(routeRef, { pathname }), + [resolver, routeRef, pathname], + ); + + if (!versionedContext) { + throw new Error('useRouteRef used outside of routing context'); + } + if (!resolver) { + throw new Error('RoutingContext v1 not available'); + } + + const isOptional = 'optional' in routeRef && routeRef.optional; + if (!routeFunc && !isOptional) { + throw new Error(`No path for ${routeRef}`); + } + + return routeFunc; +} diff --git a/packages/frontend-plugin-api/src/routing/useRouteRefParams.test.tsx b/packages/frontend-plugin-api/src/routing/useRouteRefParams.test.tsx new file mode 100644 index 0000000000..37432b294e --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/useRouteRefParams.test.tsx @@ -0,0 +1,51 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { useRouteRefParams } from './useRouteRefParams'; +import { createRouteRef } from './RouteRef'; + +describe('useRouteRefParams', () => { + it('should provide types params', () => { + const routeRef = createRouteRef({ + params: ['a', 'b'], + }); + + const Page = () => { + const params: { a: string; b: string } = useRouteRefParams(routeRef); + + return ( +
+ {params.a} + {params.b} +
+ ); + }; + + const { getByText } = render( + + + } /> + + , + ); + + expect(getByText('foo')).toBeInTheDocument(); + expect(getByText('bar')).toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/routing/useRouteRefParams.ts b/packages/frontend-plugin-api/src/routing/useRouteRefParams.ts new file mode 100644 index 0000000000..1bbd8ec6b8 --- /dev/null +++ b/packages/frontend-plugin-api/src/routing/useRouteRefParams.ts @@ -0,0 +1,31 @@ +/* + * 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 { useParams } from 'react-router-dom'; +import { AnyRouteRefParams } from './types'; +import { RouteRef } from './RouteRef'; +import { SubRouteRef } from './SubRouteRef'; + +/** + * React hook for retrieving dynamic params from the current URL. + * @param _routeRef - Ref of the current route. + * @public + */ +export function useRouteRefParams( + _routeRef: RouteRef | SubRouteRef, +): Params { + return useParams() as Params; +} diff --git a/packages/frontend-plugin-api/src/types.ts b/packages/frontend-plugin-api/src/types.ts new file mode 100644 index 0000000000..8b6f02a942 --- /dev/null +++ b/packages/frontend-plugin-api/src/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// TODO(Rugvip): This might be a quite useful utility type, maybe add to @backstage/types? +/** + * Utility type to expand type aliases into their equivalent type. + * @ignore + */ +export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 6913501907..023eab57e1 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -19,15 +19,15 @@ import { AnyApiFactory, AppTheme, IconComponent, - RouteRef, } from '@backstage/core-plugin-api'; import { createExtensionDataRef } from './createExtensionDataRef'; +import { RouteRef } from '../routing'; /** @public */ export type NavTarget = { title: string; icon: IconComponent; - routeRef: RouteRef<{}>; + routeRef: RouteRef; }; /** @public */ diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 01d4962965..fa24a24797 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -15,6 +15,7 @@ */ import { PortableSchema } from '../schema'; +import { Expand } from '../types'; import { ExtensionDataRef } from './createExtensionDataRef'; import { ExtensionInput } from './createExtensionInput'; import { BackstagePlugin } from './createPlugin'; @@ -32,13 +33,6 @@ export type AnyExtensionInputMap = { >; }; -// TODO(Rugvip): This might be a quite useful utility type, maybe add to @backstage/types? -/** - * Utility type to expand type aliases into their equivalent type. - * @ignore - */ -export type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; - /** * Converts an extension data map into the matching concrete data values type. * @public diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index 3afb5cedff..84edd954ef 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -14,8 +14,14 @@ * limitations under the License. */ -import { AnyExternalRoutes, AnyRoutes } from '@backstage/core-plugin-api'; import { Extension } from './createExtension'; +import { ExternalRouteRef, RouteRef } from '../routing'; + +/** @public */ +export type AnyRoutes = { [name in string]: RouteRef }; + +/** @public */ +export type AnyExternalRoutes = { [name in string]: ExternalRouteRef }; /** @public */ export interface PluginOptions< @@ -42,8 +48,8 @@ export interface BackstagePlugin< /** @public */ export function createPlugin< - Routes extends AnyRoutes = AnyRoutes, - ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, + Routes extends AnyRoutes = {}, + ExternalRoutes extends AnyExternalRoutes = {}, >( options: PluginOptions, ): BackstagePlugin { diff --git a/packages/frontend-plugin-api/src/wiring/index.ts b/packages/frontend-plugin-api/src/wiring/index.ts index 4e4104de97..ec685d6c81 100644 --- a/packages/frontend-plugin-api/src/wiring/index.ts +++ b/packages/frontend-plugin-api/src/wiring/index.ts @@ -37,6 +37,8 @@ export { createPlugin, type BackstagePlugin, type PluginOptions, + type AnyRoutes, + type AnyExternalRoutes, } from './createPlugin'; export { createExtensionOverrides, diff --git a/packages/integration-aws-node/CHANGELOG.md b/packages/integration-aws-node/CHANGELOG.md index e1004246ff..87156a5623 100644 --- a/packages/integration-aws-node/CHANGELOG.md +++ b/packages/integration-aws-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/integration-aws-node +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/packages/integration-aws-node/package.json b/packages/integration-aws-node/package.json index 38948f03ad..714ccf4767 100644 --- a/packages/integration-aws-node/package.json +++ b/packages/integration-aws-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-aws-node", "description": "Helpers for fetching AWS account credentials", - "version": "0.1.7-next.0", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 9374887da8..f26a0e631b 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration-react +## 1.1.20 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/config@1.1.1 + ## 1.1.20-next.2 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 7a919ed13a..f5f77aa775 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.20-next.2", + "version": "1.1.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,8 +38,8 @@ "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 93332a6b23..552e225e3b 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration +## 1.7.1 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/config@1.1.1 + ## 1.7.1-next.1 ### Patch Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 45d9474336..42a6ba4bf3 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.7.1-next.1", + "version": "1.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index fc5cae179c..75ee910172 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/repo-tools +## 0.3.5 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/cli-node@0.1.5 + ## 0.3.5-next.1 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 304df34bec..fa398e598e 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.3.5-next.1", + "version": "0.3.5", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index f54090b226..7a935bc85c 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,24 @@ # techdocs-cli-embedded-app +## 0.2.87 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/test-utils@1.4.4 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/app-defaults@1.4.4 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.2.87-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 86e85f9173..8cd74ea71a 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.87-next.2", + "version": "0.2.87", "private": true, "backstage": { "role": "frontend" @@ -29,8 +29,8 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "history": "^5.0.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", "react-router-dom": "^6.3.0", "react-use": "^17.2.4" }, @@ -38,7 +38,7 @@ "@backstage/cli": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/react": "*", "@types/react-dom": "*", diff --git a/packages/techdocs-cli-embedded-app/src/index.tsx b/packages/techdocs-cli-embedded-app/src/index.tsx index b15bc4c102..e5ca03fe64 100644 --- a/packages/techdocs-cli-embedded-app/src/index.tsx +++ b/packages/techdocs-cli-embedded-app/src/index.tsx @@ -16,7 +16,7 @@ import '@backstage/cli/asset-types'; import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import App from './App'; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index a6592085bb..1ab192f698 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,22 @@ # @techdocs/cli +## 1.6.0 + +### Minor Changes + +- d06b30b050: Add possibility to use a mkdocs config file with a different name than `mkdocs. with the serve command using the `--mkdocs-config-file-name` argument + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 2b6e572051: Restructured tests. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + ## 1.6.0-next.2 ### Minor Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 516a7d108e..7b97f13e3f 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.6.0-next.2", + "version": "1.6.0", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 9b9b90f838..213877cfb0 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/test-utils +## 1.4.4 + +### Patch Changes + +- 322bbcae24: Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. +- 1a0616fa10: Add missing resource and template app icons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 1.4.4-next.2 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 5f7bbb6af8..28aa1715e6 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.4.4-next.2", + "version": "1.4.4", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index 19bdc15a48..79327afc0b 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -92,6 +92,11 @@ describe('wrapInTestApp', () => { }); expect(error).toEqual([ + expect.objectContaining({ + detail: new Error( + 'MockErrorApi received unexpected error, Error: NOPE', + ), + }), expect.objectContaining({ detail: new Error( 'MockErrorApi received unexpected error, Error: NOPE', diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index cf7d552883..69c88c79ab 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/theme +## 0.4.3 + +### Patch Changes + +- 5ad5344756: Added support for string `fontSize` values (e.g. `"2.5rem"`) in themes in addition to numbers. Also added an optional `fontFamily` prop for header typography variants to allow further customization. + ## 0.4.3-next.0 ### Patch Changes diff --git a/packages/theme/package.json b/packages/theme/package.json index 2129067042..77109aef87 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.4.3-next.0", + "version": "0.4.3", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -40,8 +40,8 @@ "peerDependencies": { "@material-ui/core": "^4.12.2", "@types/react": "^16.13.1 || ^17.0.0", - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0" + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/version-bridge/CHANGELOG.md b/packages/version-bridge/CHANGELOG.md index bd7136e3ed..bffaff7177 100644 --- a/packages/version-bridge/CHANGELOG.md +++ b/packages/version-bridge/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/version-bridge +## 1.0.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. + ## 1.0.5 ### Patch Changes diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 851128d025..caf196f497 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.5", + "version": "1.0.6", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -36,15 +36,14 @@ "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { "@backstage/cli": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/packages/version-bridge/src/lib/VersionedContext.test.tsx b/packages/version-bridge/src/lib/VersionedContext.test.tsx index 275e491324..4ffe3f45ca 100644 --- a/packages/version-bridge/src/lib/VersionedContext.test.tsx +++ b/packages/version-bridge/src/lib/VersionedContext.test.tsx @@ -15,7 +15,7 @@ */ import React, { useContext } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createVersionedContext, createVersionedContextForTesting, diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 44743f856a..16446bee2a 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-adr-backend +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-adr-common@0.2.16 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 0.4.3-next.2 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index 444e238158..ffc5740aaf 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.4.3-next.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index 32ac484e17..849b00fdac 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.7 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index d1c32a852a..f3021eb4b1 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.16-next.1", + "version": "0.2.16", "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 a52862b7f7..ea9f9519b0 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-adr +## 0.6.8 + +### Patch Changes + +- 499e34656e: Fix icon alignment in `AdrSearchResultListItem` +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 1204e7628e: Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/theme@0.4.3 + - @backstage/plugin-adr-common@0.2.16 + - @backstage/plugin-search-common@1.2.7 + ## 0.6.8-next.2 ### Patch Changes diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/alpha-api-report.md index 6dd1c8043f..5740556904 100644 --- a/plugins/adr/alpha-api-report.md +++ b/plugins/adr/alpha-api-report.md @@ -3,8 +3,6 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -26,7 +24,7 @@ export const adrTranslationRef: TranslationRef< >; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin<{}, {}>; export default _default; // (No @packageDocumentation comment for this package) diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 72511596e7..86e07013bf 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.6.8-next.2", + "version": "0.6.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,8 +62,8 @@ "remark-gfm": "^3.0.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -73,7 +73,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/git-url-parse": "^9.0.0", "cross-fetch": "^3.1.5", diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index 948861944a..d10077998b 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-airbrake-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index cccacd8197..dda7f4e28d 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index f930cc50df..725d9f883a 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-airbrake +## 0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/test-utils@1.4.4 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/dev-utils@1.0.22 + - @backstage/theme@0.4.3 + ## 0.3.25-next.2 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index e308bee851..4e6476ecea 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.25-next.2", + "version": "0.3.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -54,7 +54,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 591036d45e..7117a5e22a 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-allure +## 0.1.41 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.1.41-next.2 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index f3f02f86dd..628eea6651 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.41-next.2", + "version": "0.1.41", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,8 +42,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -53,7 +53,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 05f2a97e4a..72c42c20fb 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-analytics-module-ga +## 0.1.34 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.1.34-next.2 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 0b79da313f..44d922ed7a 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.34-next.2", + "version": "0.1.34", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,8 +40,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -51,7 +51,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/react": "^16.13.1 || ^17.0.0", "msw": "^1.0.0" diff --git a/plugins/analytics-module-ga4/CHANGELOG.md b/plugins/analytics-module-ga4/CHANGELOG.md index d50658a59f..366fc6e16f 100644 --- a/plugins/analytics-module-ga4/CHANGELOG.md +++ b/plugins/analytics-module-ga4/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-analytics-module-ga4 +## 0.1.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.1.5-next.2 ### Patch Changes diff --git a/plugins/analytics-module-ga4/package.json b/plugins/analytics-module-ga4/package.json index db8259cdfb..705a430424 100644 --- a/plugins/analytics-module-ga4/package.json +++ b/plugins/analytics-module-ga4/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga4", - "version": "0.1.5-next.2", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,8 +37,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -48,7 +48,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/jest": "^28.1.3", "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/analytics-module-newrelic-browser/CHANGELOG.md b/plugins/analytics-module-newrelic-browser/CHANGELOG.md index b22d4e64fc..2d7e7ea467 100644 --- a/plugins/analytics-module-newrelic-browser/CHANGELOG.md +++ b/plugins/analytics-module-newrelic-browser/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-newrelic-browser +## 0.0.3 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/config@1.1.1 + ## 0.0.3-next.2 ### Patch Changes diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index 040462ad20..06b3cf5e02 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-newrelic-browser", - "version": "0.0.3-next.2", + "version": "0.0.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", @@ -38,7 +38,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index cd7d737b8e..d245b155f6 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-apache-airflow +## 0.2.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + ## 0.2.16-next.2 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 1b314c9004..e87179784f 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.16-next.2", + "version": "0.2.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,8 +40,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -51,7 +51,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md index 3786ca011a..883ed270fa 100644 --- a/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md +++ b/plugins/api-docs-module-protoc-gen-doc/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-api-docs-module-protoc-gen-doc +## 0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. + ## 0.1.3 ### Patch Changes diff --git a/plugins/api-docs-module-protoc-gen-doc/package.json b/plugins/api-docs-module-protoc-gen-doc/package.json index c7a952bc4f..80fe6645d7 100644 --- a/plugins/api-docs-module-protoc-gen-doc/package.json +++ b/plugins/api-docs-module-protoc-gen-doc/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs-module-protoc-gen-doc", "description": "Additional functionalities for the api-docs plugin that renders the output of the protoc-gen-doc", - "version": "0.1.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,8 +36,8 @@ "grpc-docs": "^1.1.2" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 609a552a55..5cefe7b94b 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-api-docs +## 0.9.12 + +### Patch Changes + +- 0117a6b47e: Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 18f1756908: added aria-label on api definition button for better a11y. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.9.12-next.2 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index fb00aa8683..53832682af 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.9.12-next.2", + "version": "0.9.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,8 +52,8 @@ "swagger-ui-react": "^5.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -63,7 +63,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/swagger-ui-react": "^4.18.0", "cross-fetch": "^3.1.5", diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 5b7905e69f..a502d30e7d 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-apollo-explorer +## 0.1.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.1.16-next.2 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index c15726029d..6af85a2784 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.16-next.2", + "version": "0.1.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,8 +40,8 @@ "use-deep-compare-effect": "^1.8.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -51,7 +51,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 7478189eba..991c1defc5 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-app-backend +## 0.3.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config-loader@1.5.1 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.6 + ## 0.3.54-next.2 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index a8425c5186..cda5301de8 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.54-next.2", + "version": "0.3.54", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index b6bb4d4425..30bfaecc96 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-app-node +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index f25333588a..915c5a0881 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-node", "description": "Node.js library for the app plugin", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 4c57589972..9cf2657b6b 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.2.0 + +### Minor Changes + +- 6f142d5356: **BREAKING** `gcpIapAuthenticator.initialize()` is no longer `async` + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + ## 0.2.0-next.2 ### Minor Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 65f4c1c0ed..85ddf5aaba 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", "description": "A GCP IAP auth provider module for the Backstage auth backend", - "version": "0.2.0-next.2", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 4bebdabd8b..80f47d6c2b 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.3 + +### Patch Changes + +- 5d32a58b5a: Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index a9bcc1f21f..85b6927ba5 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", "description": "The github-provider backend module for the auth plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index eca91f503e..aad16984c2 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 375b386fb8..85fb4b77df 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", "description": "The gitlab-provider backend module for the auth plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index c06c8dfee0..4b78ea58fa 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 74a6688e7c..7332f0c5e9 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", "description": "A Google auth provider module for the Backstage auth backend", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index c9b6227920..4d982911e7 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.0 + +### Minor Changes + +- 2d8f7e82c1: Migrated the Microsoft auth provider to new `@backstage/plugin-auth-backend-module-microsoft-provider` module package. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 8555af2cbe..16c10667fe 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", "description": "The microsoft-provider backend module for the auth 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/auth-backend-module-microsoft-provider/src/authenticator.ts b/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts index bf2d7fcaba..ba1d75adf8 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/authenticator.ts @@ -60,7 +60,6 @@ export const microsoftAuthenticator = createOAuthAuthenticator({ async start(input, helper) { return helper.start(input, { accessType: 'offline', - prompt: 'consent', }); }, diff --git a/plugins/auth-backend-module-microsoft-provider/src/module.test.ts b/plugins/auth-backend-module-microsoft-provider/src/module.test.ts index ee7ed8f7f3..2cfedc5d5e 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/module.test.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/module.test.ts @@ -65,7 +65,6 @@ describe('authModuleMicrosoftProvider', () => { expect(startUrl.origin).toBe('https://login.microsoftonline.com'); expect(startUrl.pathname).toBe('/my-tenant-id/oauth2/v2.0/authorize'); expect(Object.fromEntries(startUrl.searchParams)).toEqual({ - prompt: 'consent', response_type: 'code', scope: 'user.read', client_id: 'my-client-id', diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 2588afe13a..3920726928 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 1f610405a0..dda9aca87a 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", "description": "The oauth2-provider backend module for the auth plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md new file mode 100644 index 0000000000..3d24e48a89 --- /dev/null +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -0,0 +1,14 @@ +# @backstage/plugin-auth-backend-module-pinniped-provider + +## 0.1.0 + +### Minor Changes + +- ae34255836: Add new Pinniped auth module and authenticator to be used alongside the new Pinniped auth provider. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 3d7dcf97d9..013fd6c49f 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", "description": "The pinniped-provider backend module for the auth plugin.", - "version": "0.0.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 8f00fb0e9a..d682f21c26 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-auth-backend +## 0.19.3 + +### Patch Changes + +- 9ff7935152: Fixed bug in oidc refresh handler, if token endpoints response on refresh request does not contain a scope, the requested scope is used. +- 2d8f7e82c1: Migrated the Microsoft auth provider to new `@backstage/plugin-auth-backend-module-microsoft-provider` module package. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.3 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.1.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.3 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.3 + ## 0.19.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 355c8eb554..61e7993ab3 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.19.3-next.2", + "version": "0.19.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 7638027b01..b6608aebbd 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -130,6 +130,9 @@ export class OidcAuthProvider implements OAuthHandlers { if (!tokenset.access_token) { throw new Error('Refresh failed'); } + if (!tokenset.scope) { + tokenset.scope = req.scope; + } const userinfo = await client.userinfo(tokenset.access_token); return { diff --git a/plugins/auth-backend/src/service/standaloneServer.ts b/plugins/auth-backend/src/service/standaloneServer.ts index 0c311d5949..834305553b 100644 --- a/plugins/auth-backend/src/service/standaloneServer.ts +++ b/plugins/auth-backend/src/service/standaloneServer.ts @@ -19,12 +19,12 @@ import { loadBackendConfig, ServerTokenManager, HostDiscovery, - useHotMemoize, + DatabaseManager, } from '@backstage/backend-common'; import { Server } from 'http'; -import Knex from 'knex'; import { LoggerService } from '@backstage/backend-plugin-api'; import { createRouter } from './router'; +import { ConfigReader } from '@backstage/config'; export interface ServerOptions { logger: LoggerService; @@ -37,27 +37,20 @@ export async function startStandaloneServer( const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = HostDiscovery.fromConfig(config); - const database = useHotMemoize(module, () => { - const knex = Knex({ - client: 'better-sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - return knex; - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('auth'); logger.debug('Starting application server...'); const router = await createRouter({ logger, config, - database: { - async getClient() { - return database; - }, - }, + database, discovery, tokenManager: ServerTokenManager.noop(), }); diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 9c5bf12cac..b20ddd7697 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-auth-node +## 0.4.0 + +### Minor Changes + +- 6f142d5356: **BREAKING**: The recently introduced `ProxyAuthenticator.initialize()` method is no longer `async` to match the way the OAuth equivalent is implemented. + +### Patch Changes + +- 6c2b0793bf: Fix for persisted scopes not being properly restored on sign-in. +- 8b8b1d23ae: Fixed cookie persisted scope not returned in OAuth refresh handler response. +- ae34255836: Adding optional audience parameter to OAuthState type declaration +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.4.0-next.2 ### Minor Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 9174e91d4c..bf2257c942 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.4.0-next.2", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index 7303ae4de7..605bc9c81c 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-azure-devops-backend +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.4.3-next.2 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 7a81effc70..0186a9268b 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.4.3-next.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index c136b8c5c7..1277fa0f1e 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-azure-devops +## 0.3.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.3.7-next.2 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 45dccce464..7b5d8ee97a 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.3.7-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index 08309c6073..203b9bab9c 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-azure-sites-backend +## 0.1.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.16-next.2 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index 5063a671d2..aa5d700be2 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.16-next.2", + "version": "0.1.16", "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 c4746dba08..1d96a10e10 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-azure-sites +## 0.1.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index ee97dae742..c00f1f21af 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.14-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,7 +58,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index 40fa6773f0..3bf44d0960 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-badges-backend +## 0.3.3 + +### Patch Changes + +- 817f2acbb1: Make sure the default badge factory is used if nothing is defined +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index e539075ff2..fb2ab72985 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.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/src/service/standaloneServer.ts b/plugins/badges-backend/src/service/standaloneServer.ts index 75185c4aef..661d218edb 100644 --- a/plugins/badges-backend/src/service/standaloneServer.ts +++ b/plugins/badges-backend/src/service/standaloneServer.ts @@ -21,12 +21,12 @@ import { loadBackendConfig, ServerTokenManager, HostDiscovery, - useHotMemoize, + DatabaseManager, } from '@backstage/backend-common'; import { createRouter } from './router'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { DatabaseBadgesStore } from '../database/badgesStore'; -import Knex from 'knex'; +import { ConfigReader } from '@backstage/config'; export interface ServerOptions { port: number; @@ -40,13 +40,14 @@ export async function startStandaloneServer( const logger = options.logger.child({ service: 'badges-backend' }); const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = HostDiscovery.fromConfig(config); - const database = useHotMemoize(module, () => { - return Knex({ - client: 'better-sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('badges'); logger.debug('Creating application...'); @@ -70,9 +71,7 @@ export async function startStandaloneServer( tokenManager, logger, identity, - badgeStore: await DatabaseBadgesStore.create({ - database: { getClient: async () => database }, - }), + badgeStore: await DatabaseBadgesStore.create({ database }), }); let service = createServiceBuilder(module) diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 75de6d7e62..7ba4750487 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-badges +## 0.2.49 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.2.49-next.2 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index e52a8a1c3c..6cb8fa7642 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.49-next.2", + "version": "0.2.49", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 8561a42918..f5df21413d 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bazaar-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index ff466356ce..3fdfa32a7f 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar-backend/src/service/standaloneServer.ts b/plugins/bazaar-backend/src/service/standaloneServer.ts index a50e350f39..c222777aae 100644 --- a/plugins/bazaar-backend/src/service/standaloneServer.ts +++ b/plugins/bazaar-backend/src/service/standaloneServer.ts @@ -15,15 +15,15 @@ */ import { + DatabaseManager, createServiceBuilder, loadBackendConfig, - useHotMemoize, } from '@backstage/backend-common'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; -import knexFactory from 'knex'; +import { ConfigReader } from '@backstage/config'; export interface ServerOptions { port: number; @@ -37,23 +37,18 @@ export async function startStandaloneServer( const logger = options.logger.child({ service: 'bazaar-backend' }); const config = await loadBackendConfig({ logger, argv: process.argv }); - const db = useHotMemoize(module, () => { - const knex = knexFactory({ - client: 'better-sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - - knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - - return knex; - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('bazaar'); const router = await createRouter({ logger, - database: { getClient: async () => db }, + database, config: config, identity: {} as IdentityApi, }); diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 28af791ac4..e39456be88 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-bazaar +## 0.2.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/plugin-catalog@1.14.0 + - @backstage/cli@0.23.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + ## 0.2.17-next.2 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index b035ec8fd9..ed3428d7f9 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.17-next.2", + "version": "0.2.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,8 +51,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index c7fc10f98f..ce604a6ef5 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + ## 0.2.13-next.1 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 63c197ecbd..9f0488749e 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.13-next.1", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 814ef241c2..175d1c20b0 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-bitrise +## 0.1.52 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.1.52-next.2 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 5a00a4e4b8..023472669b 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.52-next.2", + "version": "0.1.52", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,8 +46,8 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -57,7 +57,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/recharts": "^1.8.15", "msw": "^1.0.0" diff --git a/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx b/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx index 7992e08f37..65efb9b64f 100644 --- a/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx +++ b/plugins/bitrise/src/components/BitriseBuildDetailsDialog/BitriseBuildDetailsDialog.test.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { BitriseBuildDetailsDialog } from './BitriseBuildDetailsDialog'; import { BitriseBuildResult } from '../../api/bitriseApi.model'; +import userEvent from '@testing-library/user-event'; jest.mock('../BitriseArtifactsComponent', () => ({ BitriseArtifactsComponent: (_props: { build: string }) => <>VISIBLE, @@ -48,7 +49,7 @@ describe('BitriseArtifactsComponent', () => { expect(rendered.queryByText('VISIBLE')).not.toBeInTheDocument(); - btn.click(); + await userEvent.click(btn); expect(rendered.getByText('VISIBLE')).toBeInTheDocument(); }); diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 8db117460c..26971186d6 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.0 + +### Minor Changes + +- 5abc2fd4d6: AwsEksClusterProcessor supports Entity callback function and passes in region when initialize EKS cluster + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.2.9-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/api-report.md b/plugins/catalog-backend-module-aws/api-report.md index 83b072061b..a7a3f6816a 100644 --- a/plugins/catalog-backend-module-aws/api-report.md +++ b/plugins/catalog-backend-module-aws/api-report.md @@ -8,7 +8,9 @@ import { AwsCredentialsManager } from '@backstage/integration-aws-node'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { CatalogProcessorEmit } from '@backstage/plugin-catalog-node'; import { CatalogProcessorParser } from '@backstage/plugin-catalog-node'; +import type { Cluster } from '@aws-sdk/client-eks'; import { Config } from '@backstage/config'; +import type { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { LocationSpec } from '@backstage/plugin-catalog-common'; @@ -17,6 +19,12 @@ import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TaskRunner } from '@backstage/backend-tasks'; import { UrlReader } from '@backstage/backend-common'; +// @public +export const ANNOTATION_AWS_ACCOUNT_ID: string; + +// @public +export const ANNOTATION_AWS_ARN: string; + // @public export type AWSCredentialFactory = ( awsAccountId: string, @@ -27,14 +35,18 @@ export class AwsEKSClusterProcessor implements CatalogProcessor { constructor(options: { credentialsFactory?: AWSCredentialFactory; credentialsManager?: AwsCredentialsManager; + clusterEntityTransformer?: EksClusterEntityTransformer; }); // (undocumented) - static fromConfig(configRoot: Config): AwsEKSClusterProcessor; + static fromConfig( + configRoot: Config, + options?: { + clusterEntityTransformer?: EksClusterEntityTransformer; + }, + ): AwsEKSClusterProcessor; // (undocumented) getProcessorName(): string; // (undocumented) - normalizeName(name: string): string; - // (undocumented) readLocation( location: LocationSpec, _optional: boolean, @@ -93,4 +105,10 @@ export class AwsS3EntityProvider implements EntityProvider { // (undocumented) refresh(logger: Logger): Promise; } + +// @public +export type EksClusterEntityTransformer = ( + cluster: Cluster, + accountId: string, +) => Promise; ``` diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 246def8c94..a8999430fa 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.2.9-next.2", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-aws/src/constants.ts b/plugins/catalog-backend-module-aws/src/constants.ts new file mode 100644 index 0000000000..7756031ed7 --- /dev/null +++ b/plugins/catalog-backend-module-aws/src/constants.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Annotation for specifying AWS account id + * + * @public + */ +export const ANNOTATION_AWS_ACCOUNT_ID: string = 'amazonaws.com/account-id'; +/** + * Annotation for specifying AWS arn + * + * @public + */ +export const ANNOTATION_AWS_ARN: string = 'amazonaws.com/arn'; diff --git a/plugins/catalog-backend-module-aws/src/index.ts b/plugins/catalog-backend-module-aws/src/index.ts index 212308edaa..72ddc6386a 100644 --- a/plugins/catalog-backend-module-aws/src/index.ts +++ b/plugins/catalog-backend-module-aws/src/index.ts @@ -23,3 +23,4 @@ export * from './processors'; export * from './providers'; export * from './types'; +export * from './constants'; diff --git a/plugins/catalog-backend-module-aws/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-aws/src/lib/defaultTransformers.ts new file mode 100644 index 0000000000..9de79e9811 --- /dev/null +++ b/plugins/catalog-backend-module-aws/src/lib/defaultTransformers.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { type Cluster } from '@aws-sdk/client-eks'; +import { + ANNOTATION_KUBERNETES_API_SERVER, + ANNOTATION_KUBERNETES_API_SERVER_CA, + ANNOTATION_KUBERNETES_AUTH_PROVIDER, +} from '@backstage/plugin-kubernetes-common'; +import type { EksClusterEntityTransformer } from '../processors/types'; +import { ANNOTATION_AWS_ACCOUNT_ID, ANNOTATION_AWS_ARN } from '../constants'; + +/** + * Default transformer for EKS Cluster to Resource Entity + * @public + */ +export const defaultEksClusterEntityTransformer: EksClusterEntityTransformer = + async (cluster: Cluster, accountId: string) => { + const { arn, endpoint, certificateAuthority, name } = cluster; + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Resource', + metadata: { + annotations: { + [ANNOTATION_AWS_ACCOUNT_ID]: accountId, + [ANNOTATION_AWS_ARN]: arn || '', + [ANNOTATION_KUBERNETES_API_SERVER]: endpoint || '', + [ANNOTATION_KUBERNETES_API_SERVER_CA]: + certificateAuthority?.data || '', + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'aws', + }, + name: normalizeName(name as string), + namespace: 'default', + }, + spec: { + type: 'kubernetes-cluster', + owner: 'unknown', + }, + }; + }; + +function normalizeName(name: string): string { + return name + .trim() + .toLocaleLowerCase('en-US') + .replace(/[^a-zA-Z0-9\-]/g, '-'); +} diff --git a/plugins/catalog-backend-module-aws/src/lib/index.ts b/plugins/catalog-backend-module-aws/src/lib/index.ts new file mode 100644 index 0000000000..1dc70c98f3 --- /dev/null +++ b/plugins/catalog-backend-module-aws/src/lib/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './defaultTransformers'; diff --git a/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts index 4a19b9eb7f..a491dbab7d 100644 --- a/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts +++ b/plugins/catalog-backend-module-aws/src/processors/AwsEKSClusterProcessor.ts @@ -19,11 +19,6 @@ import { CatalogProcessorEmit, } from '@backstage/plugin-catalog-node'; import { LocationSpec } from '@backstage/plugin-catalog-common'; -import { - ANNOTATION_KUBERNETES_API_SERVER, - ANNOTATION_KUBERNETES_API_SERVER_CA, - ANNOTATION_KUBERNETES_AUTH_PROVIDER, -} from '@backstage/plugin-kubernetes-common'; import { EKS } from '@aws-sdk/client-eks'; import { AWSCredentialFactory } from '../types'; import { AwsCredentialIdentity, Provider } from '@aws-sdk/types'; @@ -33,8 +28,8 @@ import { } from '@backstage/integration-aws-node'; import { Config } from '@backstage/config'; -const ACCOUNTID_ANNOTATION: string = 'amazonaws.com/account-id'; -const ARN_ANNOTATION: string = 'amazonaws.com/arn'; +import type { EksClusterEntityTransformer } from './types'; +import { defaultEksClusterEntityTransformer } from '../lib'; /** * A processor for automatic discovery of resources from EKS clusters. Handles the @@ -46,34 +41,39 @@ const ARN_ANNOTATION: string = 'amazonaws.com/arn'; export class AwsEKSClusterProcessor implements CatalogProcessor { private credentialsFactory?: AWSCredentialFactory; private credentialsManager?: AwsCredentialsManager; + private readonly clusterEntityTransformer: EksClusterEntityTransformer; - static fromConfig(configRoot: Config): AwsEKSClusterProcessor { + static fromConfig( + configRoot: Config, + options?: { + clusterEntityTransformer?: EksClusterEntityTransformer; + }, + ): AwsEKSClusterProcessor { const awsCredentaislManager = DefaultAwsCredentialsManager.fromConfig(configRoot); return new AwsEKSClusterProcessor({ credentialsManager: awsCredentaislManager, + ...options, }); } constructor(options: { credentialsFactory?: AWSCredentialFactory; credentialsManager?: AwsCredentialsManager; + clusterEntityTransformer?: EksClusterEntityTransformer; }) { this.credentialsFactory = options.credentialsFactory; this.credentialsManager = options.credentialsManager; + + // If the callback function is not passed in, then default to the one upstream is using + this.clusterEntityTransformer = + options.clusterEntityTransformer || defaultEksClusterEntityTransformer; } getProcessorName(): string { return 'aws-eks'; } - normalizeName(name: string): string { - return name - .trim() - .toLocaleLowerCase('en-US') - .replace(/[^a-zA-Z0-9\-]/g, '-'); - } - async readLocation( location: LocationSpec, _optional: boolean, @@ -108,6 +108,7 @@ export class AwsEKSClusterProcessor implements CatalogProcessor { const eksClient = new EKS({ credentials, credentialDefaultProvider: providerFunction, + region, }); const clusters = await eksClient.listClusters({}); if (clusters.clusters === undefined) { @@ -119,27 +120,11 @@ export class AwsEKSClusterProcessor implements CatalogProcessor { .map(async describedClusterPromise => { const describedCluster = await describedClusterPromise; if (describedCluster.cluster) { - const entity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Resource', - metadata: { - annotations: { - [ACCOUNTID_ANNOTATION]: accountId, - [ARN_ANNOTATION]: describedCluster.cluster.arn || '', - [ANNOTATION_KUBERNETES_API_SERVER]: - describedCluster.cluster.endpoint || '', - [ANNOTATION_KUBERNETES_API_SERVER_CA]: - describedCluster.cluster.certificateAuthority?.data || '', - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'aws', - }, - name: this.normalizeName(describedCluster.cluster.name as string), - namespace: 'default', - }, - spec: { - type: 'kubernetes-cluster', - owner: 'unknown', - }, - }; + const entity = await this.clusterEntityTransformer( + describedCluster.cluster, + accountId, + ); + emit({ type: 'entity', entity, diff --git a/plugins/catalog-backend-module-aws/src/processors/index.ts b/plugins/catalog-backend-module-aws/src/processors/index.ts index 63b8a47139..e5bf93ceaf 100644 --- a/plugins/catalog-backend-module-aws/src/processors/index.ts +++ b/plugins/catalog-backend-module-aws/src/processors/index.ts @@ -17,3 +17,4 @@ export { AwsEKSClusterProcessor } from './AwsEKSClusterProcessor'; export { AwsOrganizationCloudAccountProcessor } from './AwsOrganizationCloudAccountProcessor'; export { AwsS3DiscoveryProcessor } from './AwsS3DiscoveryProcessor'; +export * from './types'; diff --git a/plugins/catalog-backend-module-aws/src/processors/types.ts b/plugins/catalog-backend-module-aws/src/processors/types.ts new file mode 100644 index 0000000000..22e9e4982d --- /dev/null +++ b/plugins/catalog-backend-module-aws/src/processors/types.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { Cluster } from '@aws-sdk/client-eks'; +import type { Entity } from '@backstage/catalog-model'; + +/** + * Options for the EKS cluster entity callback function + * + * @public + */ +export type EksClusterEntityTransformer = ( + cluster: Cluster, + accountId: string, +) => Promise; diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 57cfff7cb2..315d39baab 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.25 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.1.25-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index f7353a1f37..ef21110f7b 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.25-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index bfd363123a..7682992e01 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.21 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-bitbucket-cloud-common@0.2.13 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + ## 0.1.21-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 5f8acc82ca..ed10c8433e 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.21-next.2", + "version": "0.1.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 4501171eda..67ea880c96 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.19 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 1e937da6ea..e0f395a1a2 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.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index ffca76bddc..cf7e871bc5 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-bitbucket-cloud-common@0.2.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.21-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index a85596ea32..a68cb1e674 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.21-next.2", + "version": "0.2.21", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index e9509a5d02..c755f7a72b 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index cf297b186d..70bf6f7b88 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", "description": "A Backstage catalog backend module that helps integrate towards GCP", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index a6b8cb8167..e55d30ed12 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.22 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.1.22-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index d4baf186d0..576f772968 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.22-next.2", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 7dbac7fcc5..e0a24889c4 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.0 + +### Minor Changes + +- c101e683d5: Added `catalogModuleGithubOrgEntityProvider` to ingest users and teams from multiple Github organizations. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend-module-github@0.4.4 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index d970f3013a..7ad96c65e2 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", "description": "The github-org backend module for the catalog 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/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index b5d563617c..21e8ad0e1b 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-github +## 0.4.4 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- 0b55f773a7: Removed some unused dependencies +- 4f16e60e6d: Request slightly smaller pages of data from GitHub +- b4b1cbf9fa: Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` +- c101e683d5: Removed `catalogModuleGithubOrgEntityProvider`. Import from `@backstage/plugin-catalog-backend-module-github-org` instead. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + ## 0.4.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 0d3bc4191b..f2c321f84a 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.4.4-next.2", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 790320f5db..5378ba5448 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.3 + +### Patch Changes + +- 4f70fdfc93: fix: use REST API to get root group memberships for GitLab SaaS users listing + + This API is the only one that shows `email` field for enterprise users and + allows to filter out bot users not using a license using the `is_using_seat` + field. + + We also added the annotation `gitlab.com/saml-external-uid` taking the value + of `group_saml_identity.extern_uid` of the `groups/:group-id/members` endpoint + response. This is useful in case you want to create a `SignInResolver` that + references the user with the id of your identity provider (e.g. OneLogin). + + ref: + + https://docs.gitlab.com/ee/user/enterprise_user/#get-users-email-addresses-through-the-api + https://docs.gitlab.com/ee/api/members.html#limitations + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- 0b55f773a7: Removed some unused dependencies +- 6ae7f12abb: Make sure the archived projects are skipped with the Gitlab API +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index d5a8069460..2c5966bb68 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.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index cf18c6dddc..58e19beae8 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.10 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + ## 0.4.10-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 1aa470dcc3..a0df7f5449 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.4.10-next.2", + "version": "0.4.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index cb7b48d509..f9d38ee033 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.21 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.5.21-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index ac8693251f..36c1e6c46f 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.21-next.2", + "version": "0.5.21", "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 b759abb9ab..3cb7b30b3d 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.13 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.5.13-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index d02dddcaea..91459e847e 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.5.13-next.2", + "version": "0.5.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 90fe155927..65b55833ca 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.1.23-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 2230782402..1f85d0d844 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.23-next.2", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index 67e1696141..7ce2b70e20 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.11 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.1.11-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 381d1fcfb4..db267bc22e 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.11-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 2dc4e82d31..b077261f25 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index b49a308146..f20a772a30 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 21b25797bc..310f3b9b5f 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 5c45699175..5adc6e1f5f 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", "description": "Backstage Catalog module to view unprocessed entities", - "version": "0.3.3-next.2", + "version": "0.3.3", "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 ca34451992..f6dee7b12f 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-catalog-backend +## 1.14.0 + +### Minor Changes + +- 78af9433c8: Instrumenting some missing metrics with `OpenTelemetry` + +### Patch Changes + +- 7a2e2924c7: Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. +- 0b55f773a7: Removed some unused dependencies +- 348e8c1cdb: Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. +- b97e9790f0: Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-module-catalog@0.1.10 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-events-node@0.2.15 + - @backstage/plugin-permission-common@0.7.9 + ## 1.14.0-next.2 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 49f4d7a7b1..388f6b5ffc 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.14.0-next.2", + "version": "1.14.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/src/service/standaloneServer.ts b/plugins/catalog-backend/src/service/standaloneServer.ts index cff4fa1f94..995a607ab5 100644 --- a/plugins/catalog-backend/src/service/standaloneServer.ts +++ b/plugins/catalog-backend/src/service/standaloneServer.ts @@ -21,7 +21,6 @@ import { ServerTokenManager, HostDiscovery, UrlReaders, - useHotMemoize, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ServerPermissionClient } from '@backstage/plugin-permission-node'; @@ -43,16 +42,14 @@ export async function startStandaloneServer( const logger = options.logger.child({ service: 'catalog-backend' }); const config = await loadBackendConfig({ logger, argv: process.argv }); const reader = UrlReaders.default({ logger, config }); - const database = useHotMemoize(module, () => { - const manager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { client: 'better-sqlite3', connection: ':memory:' }, - }, - }), - ); - return manager.forPlugin('catalog'); - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('catalog'); const discovery = HostDiscovery.fromConfig(config); const tokenManager = ServerTokenManager.fromConfig(config, { logger, diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index e3ad0c858f..3dbde65433 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-common +## 1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 1.0.17-next.0 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 35529e2cd1..68ab60e7c3 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.17-next.0", + "version": "1.0.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 2dfa6dffe4..5d10ff94f3 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-graph +## 0.2.37 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + ## 0.2.37-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 909ed5329d..0afb6d92f7 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.37-next.2", + "version": "0.2.37", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,8 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0" }, "files": [ diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/useCatalogGraphPage.test.ts b/plugins/catalog-graph/src/components/CatalogGraphPage/useCatalogGraphPage.test.ts index 7a4d836365..a89fa353d6 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/useCatalogGraphPage.test.ts +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/useCatalogGraphPage.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { RELATION_MEMBER_OF } from '@backstage/catalog-model'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { useLocation as useLocationMocked } from 'react-router-dom'; import { Direction } from '../EntityRelationsGraph'; import { useCatalogGraphPage } from './useCatalogGraphPage'; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.test.ts index 7e0cd411ce..420af5345c 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationGraph.test.ts @@ -19,7 +19,7 @@ import { RELATION_OWNER_OF, RELATION_PART_OF, } from '@backstage/catalog-model'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { pick } from 'lodash'; import { useEntityRelationGraph } from './useEntityRelationGraph'; import { useEntityStore as useEntityStoreMocked } from './useEntityStore'; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts index c2ee918e5b..d17e8b1c9d 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityRelationNodesAndEdges.test.ts @@ -21,7 +21,7 @@ import { RELATION_PART_OF, stringifyEntityRef, } from '@backstage/catalog-model'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { filter, keyBy } from 'lodash'; import { useEntityRelationGraph as useEntityRelationGraphMocked } from './useEntityRelationGraph'; import { useEntityRelationNodesAndEdges } from './useEntityRelationNodesAndEdges'; @@ -163,7 +163,7 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should generate unidirectional graph with merged relations', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], unidirectional: true, @@ -171,9 +171,9 @@ describe('useEntityRelationNodesAndEdges', () => { }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -236,7 +236,7 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should generate unidirectional graph', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], unidirectional: true, @@ -244,9 +244,9 @@ describe('useEntityRelationNodesAndEdges', () => { }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -309,7 +309,7 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should generate bidirectional graph with merged relations', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], unidirectional: false, @@ -317,9 +317,9 @@ describe('useEntityRelationNodesAndEdges', () => { }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -412,7 +412,7 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should generate bidirectional graph with all relations', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], unidirectional: false, @@ -420,9 +420,9 @@ describe('useEntityRelationNodesAndEdges', () => { }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -515,15 +515,15 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should generate graph with multiple root nodes', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c', 'b:d/c2'], }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -586,16 +586,16 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should filter by relation', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], relations: [RELATION_OWNER_OF], }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; @@ -646,16 +646,16 @@ describe('useEntityRelationNodesAndEdges', () => { }); test('should filter by kind', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useEntityRelationNodesAndEdges({ rootEntityRefs: ['b:d/c'], kinds: ['b'], }), ); - await waitForValueToChange( - () => result.current.nodes && result.current.edges, - ); + await waitFor(() => { + expect(result.current.nodes && result.current.edges).toBeDefined(); + }); const { nodes, edges, loading, error } = result.current; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts index 802f993802..0d75fabc3b 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/useEntityStore.test.ts @@ -16,7 +16,7 @@ import { Entity } from '@backstage/catalog-model'; import { useApi as useApiMocked } from '@backstage/core-plugin-api'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import { useEntityStore } from './useEntityStore'; jest.mock('@backstage/core-plugin-api'); @@ -65,7 +65,7 @@ describe('useEntityStore', () => { catalogApi.getEntityByRef.mockResolvedValue(entity); - const { result, waitFor } = renderHook(() => useEntityStore()); + const { result } = renderHook(() => useEntityStore()); act(() => { result.current.requestEntities(['kind:namespace/name']); @@ -85,7 +85,7 @@ describe('useEntityStore', () => { const err = new Error('Hello World'); catalogApi.getEntityByRef.mockRejectedValue(err); - const { result, waitFor } = renderHook(() => useEntityStore()); + const { result } = renderHook(() => useEntityStore()); act(() => { result.current.requestEntities(['kind:namespace/name']); @@ -134,7 +134,7 @@ describe('useEntityStore', () => { catalogApi.getEntityByRef.mockResolvedValue(entity1); - const { result, waitFor } = renderHook(() => useEntityStore()); + const { result } = renderHook(() => useEntityStore()); act(() => { result.current.requestEntities(['kind:namespace/name1']); @@ -189,7 +189,7 @@ describe('useEntityStore', () => { catalogApi.getEntityByRef.mockResolvedValue(entity1); - const { result, waitFor } = renderHook(() => useEntityStore()); + const { result } = renderHook(() => useEntityStore()); act(() => { result.current.requestEntities(['kind:namespace/name1']); diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 867d52cb4b..0a08803e7d 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graphql +## 0.4.0 + +### Minor Changes + +- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.3.24-next.0 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 75f08a6bf9..d8869e2578 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "Deprecated, consider using @frontside/backstage-plugin-graphql-backend instead", - "version": "0.3.24-next.0", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "winston": "^3.2.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 2043cca0f4..8a84c211e5 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-import +## 0.10.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The `app.title` configuration is now properly required to be a string. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 0.10.1-next.2 ### Patch Changes diff --git a/plugins/catalog-import/alpha-api-report.md b/plugins/catalog-import/alpha-api-report.md new file mode 100644 index 0000000000..63e2cda339 --- /dev/null +++ b/plugins/catalog-import/alpha-api-report.md @@ -0,0 +1,19 @@ +## API Report File for "@backstage/plugin-catalog-import" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin< + { + importPage: RouteRef; + }, + {} +>; +export default _default; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 9c550ebee9..e892338dea 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.10.1-next.2", + "version": "0.10.1", "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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -39,6 +52,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", @@ -56,8 +70,8 @@ "yaml": "^2.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -67,8 +81,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx new file mode 100644 index 0000000000..bde1048f13 --- /dev/null +++ b/plugins/catalog-import/src/alpha.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + configApiRef, + createApiFactory, + discoveryApiRef, + identityApiRef, +} from '@backstage/core-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + createApiExtension, + createPageExtension, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { + scmAuthApiRef, + scmIntegrationsApiRef, +} from '@backstage/integration-react'; +import React from 'react'; +import { CatalogImportClient, catalogImportApiRef } from './api'; +import { rootRouteRef } from './plugin'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; + +// TODO: It's currently possible to override the import page with a custom one. We need to decide +// whether this type of override is typically done with an input or by overriding the entire extension. +const CatalogImportPageExtension = createPageExtension({ + id: 'plugin.catalog-import.page', + defaultPath: '/catalog-import', + routeRef: convertLegacyRouteRef(rootRouteRef), + loader: () => import('./components/ImportPage').then(m => ), +}); + +const CatalogImportService = createApiExtension({ + factory: createApiFactory({ + api: catalogImportApiRef, + deps: { + discoveryApi: discoveryApiRef, + scmAuthApi: scmAuthApiRef, + identityApi: identityApiRef, + scmIntegrationsApi: scmIntegrationsApiRef, + catalogApi: catalogApiRef, + configApi: configApiRef, + }, + factory: ({ + discoveryApi, + scmAuthApi, + identityApi, + scmIntegrationsApi, + catalogApi, + configApi, + }) => + new CatalogImportClient({ + discoveryApi, + scmAuthApi, + scmIntegrationsApi, + identityApi, + catalogApi, + configApi, + }), + }), +}); + +/** @alpha */ +export default createPlugin({ + id: 'catalog-import', + extensions: [CatalogImportService, CatalogImportPageExtension], + routes: { + importPage: convertLegacyRouteRef(rootRouteRef), + }, +}); diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx index 0a6960cdc7..4e737bd115 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewCatalogInfoComponent.test.tsx @@ -19,7 +19,7 @@ import { configApiRef } from '@backstage/core-plugin-api'; import { MockConfigApi, TestApiProvider } from '@backstage/test-utils'; import { makeStyles } from '@material-ui/core'; import { render, screen } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { PreviewCatalogInfoComponent } from './PreviewCatalogInfoComponent'; diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx index d983b6d359..53485bedb5 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/PreviewPullRequestComponent.test.tsx @@ -16,7 +16,7 @@ import { makeStyles } from '@material-ui/core'; import { render, screen } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { PreviewPullRequestComponent } from './PreviewPullRequestComponent'; diff --git a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx index 36f1217c37..079b010ec6 100644 --- a/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx +++ b/plugins/catalog-import/src/components/StepPrepareCreatePullRequest/StepPrepareCreatePullRequest.test.tsx @@ -18,7 +18,7 @@ import { configApiRef, errorApiRef } from '@backstage/core-plugin-api'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { TestApiProvider, MockConfigApi } from '@backstage/test-utils'; import { TextField } from '@material-ui/core'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { AnalyzeResult, catalogImportApiRef } from '../../api'; @@ -101,36 +101,34 @@ describe('', () => { it('renders without exploding', async () => { catalogApi.getEntities.mockReturnValue(Promise.resolve({ items: [] })); - await act(async () => { - render( - { - return ( - <> - - - - - - ); - }} - />, - { - wrapper: Wrapper, - }, - ); + render( + { + return ( + <> + + + + + + ); + }} + />, + { + wrapper: Wrapper, + }, + ); - const title = await screen.findByText('My title'); - const description = await screen.findByText('body', { - selector: 'strong', - }); - expect(title).toBeInTheDocument(); - expect(title).toBeVisible(); - expect(description).toBeInTheDocument(); - expect(description).toBeVisible(); + const title = await screen.findByText('My title'); + const description = await screen.findByText('body', { + selector: 'strong', }); + expect(title).toBeInTheDocument(); + expect(title).toBeVisible(); + expect(description).toBeInTheDocument(); + expect(description).toBeVisible(); }); it('should submit created PR', async () => { @@ -142,39 +140,37 @@ describe('', () => { }), ); - await act(async () => { - render( - { - return ( - <> - - - - - - ); - }} - />, - { - wrapper: Wrapper, - }, - ); + render( + { + return ( + <> + + + + + + ); + }} + />, + { + wrapper: Wrapper, + }, + ); - await userEvent.type(await screen.findByLabelText('name'), '-changed'); - await userEvent.type(await screen.findByLabelText('owner'), '-changed'); - await userEvent.click(screen.getByRole('button', { name: /Create PR/i })); - }); + await userEvent.type(await screen.findByLabelText('name'), '-changed'); + await userEvent.type(await screen.findByLabelText('owner'), '-changed'); + await userEvent.click(screen.getByRole('button', { name: /Create PR/i })); expect(catalogImportApi.submitPullRequest).toHaveBeenCalledTimes(1); expect(catalogImportApi.submitPullRequest.mock.calls[0]).toMatchObject([ @@ -226,31 +222,29 @@ spec: new Error('some error'), ); - await act(async () => { - render( - { - return ( - <> - - - - - - ); - }} - />, - { - wrapper: Wrapper, - }, - ); + render( + { + return ( + <> + + + + + + ); + }} + />, + { + wrapper: Wrapper, + }, + ); - await userEvent.click( - await screen.findByRole('button', { name: /Create PR/i }), - ); - }); + await userEvent.click( + await screen.findByRole('button', { name: /Create PR/i }), + ); expect(screen.getByText('some error')).toBeInTheDocument(); expect(catalogImportApi.submitPullRequest).toHaveBeenCalledTimes(1); @@ -273,30 +267,26 @@ spec: }), ); - await act(async () => { - render( - , - { - wrapper: Wrapper, - }, - ); + render( + , + { + wrapper: Wrapper, + }, + ); + + await waitFor(() => { + expect(catalogApi.getEntities).toHaveBeenCalledTimes(1); }); - expect(catalogApi.getEntities).toHaveBeenCalledTimes(1); expect(renderFormFieldsFn).toHaveBeenCalled(); expect(renderFormFieldsFn.mock.calls[0][0]).toMatchObject({ - groups: [], - groupsLoading: true, + groups: ['my-group'], + groupsLoading: false, }); - expect( - renderFormFieldsFn.mock.calls[ - renderFormFieldsFn.mock.calls.length - 1 - ][0], - ).toMatchObject({ groups: ['my-group'], groupsLoading: false }); }); describe('generateEntities', () => { diff --git a/plugins/catalog-import/src/components/useImportState.test.tsx b/plugins/catalog-import/src/components/useImportState.test.tsx index 155adb8290..dc2cb30f6f 100644 --- a/plugins/catalog-import/src/components/useImportState.test.tsx +++ b/plugins/catalog-import/src/components/useImportState.test.tsx @@ -16,7 +16,7 @@ import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; import { cleanup } from '@testing-library/react'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { AnalyzeResult } from '../api'; import { @@ -73,7 +73,6 @@ describe('useImportState', () => { describe('onAnalysis & onPrepare & onReview & onReset', () => { it('should work', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current).toMatchObject({ activeFlow: 'unknown', @@ -148,7 +147,6 @@ describe('useImportState', () => { it('should work skipped', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current).toMatchObject({ activeFlow: 'unknown', @@ -198,7 +196,6 @@ describe('useImportState', () => { it('should ignore on invalid state', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); // state 'analyze' act(() => { @@ -264,7 +261,6 @@ describe('useImportState', () => { describe('onGoBack', () => { it('should work', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current.activeStepNumber).toBe(0); expect(result.current.onGoBack).toBeUndefined(); @@ -303,7 +299,6 @@ describe('useImportState', () => { it('should work for skipped', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current.activeStepNumber).toBe(0); expect(result.current.onGoBack).toBeUndefined(); @@ -329,7 +324,6 @@ describe('useImportState', () => { describe('should consider prepareNotRepeatable', () => { it('as true', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current.onGoBack).toBeUndefined(); @@ -351,7 +345,6 @@ describe('useImportState', () => { it('as false', async () => { const { result } = renderHook(() => useImportState()); - await cleanup(); expect(result.current.onGoBack).toBeUndefined(); diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index a60a3e21aa..22a2319142 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-node +## 1.4.7 + +### Patch Changes + +- 7a2e2924c7: Added docs to `processingResult` +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + ## 1.4.7-next.2 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index cbc17219c5..2817703044 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.4.7-next.2", + "version": "1.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 3e65e4b55c..9d6dbd2840 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-catalog-react +## 1.8.5 + +### Patch Changes + +- a402e1dfb9: Fixed an issue causing `EntityPage` to show an error for entities containing special characters +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The `spec.type` field in entities will now always be rendered as a string. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + ## 1.8.5-next.2 ### Patch Changes diff --git a/plugins/catalog-react/alpha-api-report.md b/plugins/catalog-react/alpha-api-report.md index f9b740c07c..120e162c84 100644 --- a/plugins/catalog-react/alpha-api-report.md +++ b/plugins/catalog-react/alpha-api-report.md @@ -3,8 +3,73 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + +import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; +import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import { Extension } from '@backstage/frontend-plugin-api'; +import { ExtensionInputValues } from '@backstage/frontend-plugin-api'; +import { PortableSchema } from '@backstage/frontend-plugin-api'; import { ResourcePermission } from '@backstage/plugin-permission-common'; +import { RouteRef } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +export function createEntityCardExtension< + TConfig, + TInputs extends AnyExtensionInputMap, +>(options: { + id: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}): Extension; + +// @alpha (undocumented) +export function createEntityContentExtension< + TConfig extends { + path: string; + title: string; + }, + TInputs extends AnyExtensionInputMap, +>( + options: ( + | { + defaultPath: string; + defaultTitle: string; + } + | { + configSchema: PortableSchema; + } + ) & { + id: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + routeRef?: RouteRef; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; + }, +): Extension; + +// @alpha (undocumented) +export const entityContentTitleExtensionDataRef: ConfigurableExtensionDataRef< + string, + {} +>; // @alpha export function isOwnerOf(owner: Entity, entity: Entity): boolean; diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 4d52a96ccc..70fa5e9614 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.8.5-next.2", + "version": "1.8.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -10,13 +10,13 @@ }, "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", + "./alpha": "./src/alpha.tsx", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.ts" + "src/alpha.tsx" ], "package.json": [ "package.json" @@ -51,6 +51,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", @@ -72,8 +73,8 @@ "zen-observable": "^0.10.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -84,8 +85,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/zen-observable": "^0.8.0", "react-test-renderer": "^16.13.1" diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx new file mode 100644 index 0000000000..58762b1994 --- /dev/null +++ b/plugins/catalog-react/src/alpha.tsx @@ -0,0 +1,158 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { lazy } from 'react'; +import { + AnyExtensionInputMap, + Extension, + ExtensionBoundary, + ExtensionInputValues, + PortableSchema, + RouteRef, + coreExtensionData, + createExtension, + createExtensionDataRef, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { Expand } from '../../../packages/frontend-plugin-api/src/types'; + +export { isOwnerOf } from './utils'; +export { useEntityPermission } from './hooks/useEntityPermission'; + +/** @alpha */ +export const entityContentTitleExtensionDataRef = + createExtensionDataRef('plugin.catalog.entity.content.title'); + +/** @alpha */ +export function createEntityCardExtension< + TConfig, + TInputs extends AnyExtensionInputMap, +>(options: { + id: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; +}): Extension { + const id = `entity.cards.${options.id}`; + + return createExtension({ + id, + attachTo: options.attachTo ?? { + id: 'entity.content.overview', + input: 'cards', + }, + disabled: options.disabled ?? true, + output: { + element: coreExtensionData.reactElement, + }, + inputs: options.inputs, + configSchema: options.configSchema, + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .loader({ config, inputs }) + .then(element => ({ default: () => element })), + ); + + bind({ + element: ( + + + + ), + }); + }, + }); +} + +/** @alpha */ +export function createEntityContentExtension< + TConfig extends { path: string; title: string }, + TInputs extends AnyExtensionInputMap, +>( + options: ( + | { + defaultPath: string; + defaultTitle: string; + } + | { + configSchema: PortableSchema; + } + ) & { + id: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + routeRef?: RouteRef; + loader: (options: { + config: TConfig; + inputs: Expand>; + }) => Promise; + }, +): Extension { + const id = `entity.content.${options.id}`; + + const configSchema = + 'configSchema' in options + ? options.configSchema + : (createSchemaFromZod(z => + z.object({ + path: z.string().default(options.defaultPath), + title: z.string().default(options.defaultTitle), + }), + ) as PortableSchema); + + return createExtension({ + id, + attachTo: options.attachTo ?? { + id: 'plugin.catalog.page.entity', + input: 'contents', + }, + disabled: options.disabled ?? true, + output: { + element: coreExtensionData.reactElement, + path: coreExtensionData.routePath, + routeRef: coreExtensionData.routeRef.optional(), + title: entityContentTitleExtensionDataRef, + }, + inputs: options.inputs, + configSchema, + factory({ bind, config, inputs, source }) { + const ExtensionComponent = lazy(() => + options + .loader({ config, inputs }) + .then(element => ({ default: () => element })), + ); + + bind({ + path: config.path, + title: config.title, + routeRef: options.routeRef, + element: ( + + + + ), + }); + }, + }); +} diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx index 38edb9b064..32e66dc578 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx @@ -179,9 +179,7 @@ describe('', () => { , ); await waitFor(() => - expect(updateFilters).toHaveBeenLastCalledWith({ - options: undefined, - }), + expect(screen.getByTestId('options-picker-expand')).toBeInTheDocument(), ); fireEvent.click(screen.getByTestId('options-picker-expand')); diff --git a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx index 19554f18b7..de40f90c55 100644 --- a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.test.tsx @@ -74,9 +74,10 @@ describe('', () => { , ); - await waitFor(() => expect(catalogApi.getEntityFacets).toHaveBeenCalled()); - expect(updateFilters).toHaveBeenLastCalledWith({ - lifecycles: new EntityLifecycleFilter(['experimental']), + await waitFor(() => { + expect(updateFilters).toHaveBeenLastCalledWith({ + lifecycles: new EntityLifecycleFilter(['experimental']), + }); }); }); @@ -119,9 +120,10 @@ describe('', () => { , ); - await waitFor(() => expect(catalogApi.getEntityFacets).toHaveBeenCalled()); - expect(updateFilters).toHaveBeenLastCalledWith({ - lifecycles: new EntityLifecycleFilter(['production']), + await waitFor(() => { + expect(updateFilters).toHaveBeenLastCalledWith({ + lifecycles: new EntityLifecycleFilter(['production']), + }); }); fireEvent.click(screen.getByTestId('lifecycles-picker-expand')); expect(screen.getByLabelText('production')).toBeChecked(); @@ -147,9 +149,10 @@ describe('', () => { , ); - await waitFor(() => expect(catalogApi.getEntityFacets).toHaveBeenCalled()); - expect(updateFilters).toHaveBeenLastCalledWith({ - lifecycles: new EntityLifecycleFilter(['experimental']), + await waitFor(() => { + expect(updateFilters).toHaveBeenLastCalledWith({ + lifecycles: new EntityLifecycleFilter(['experimental']), + }); }); rendered.rerender( @@ -210,9 +213,10 @@ describe('', () => { , ); - await waitFor(() => expect(catalogApi.getEntityFacets).toHaveBeenCalled()); - expect(updateFilters).toHaveBeenLastCalledWith({ - lifecycles: new EntityLifecycleFilter(['production']), + await waitFor(() => { + expect(updateFilters).toHaveBeenLastCalledWith({ + lifecycles: new EntityLifecycleFilter(['production']), + }); }); }); }); diff --git a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx index 7dd13620c7..c4b5e64c9d 100644 --- a/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityNamespacePicker/EntityNamespacePicker.test.tsx @@ -113,9 +113,7 @@ describe('', () => { , ); await waitFor(() => - expect(updateFilters).toHaveBeenLastCalledWith({ - namespace: undefined, - }), + expect(screen.getByTestId('namespace-picker-expand')).toBeInTheDocument(), ); fireEvent.click(screen.getByTestId('namespace-picker-expand')); diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts index 6f6da43307..1d0d1130a6 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useFacetsEntities } from './useFacetsEntities'; import { CatalogApi } from '@backstage/catalog-client'; @@ -50,9 +50,7 @@ describe('useFacetsEntities', () => { }, }); - const { result, waitFor } = renderHook(() => - useFacetsEntities({ enabled: true }), - ); + const { result } = renderHook(() => useFacetsEntities({ enabled: true })); result.current[1]({ text: '' }); await waitFor(() => { @@ -91,9 +89,7 @@ describe('useFacetsEntities', () => { }, }); - const { result, waitFor } = renderHook(() => - useFacetsEntities({ enabled: true }), - ); + const { result } = renderHook(() => useFacetsEntities({ enabled: true })); result.current[1]({ text: '' }); await waitFor(() => { @@ -147,9 +143,7 @@ describe('useFacetsEntities', () => { }, }); - const { result, waitFor } = renderHook(() => - useFacetsEntities({ enabled: true }), - ); + const { result } = renderHook(() => useFacetsEntities({ enabled: true })); result.current[1]({ text: '' }, { limit: 2 }); await waitFor(() => { @@ -261,9 +255,7 @@ describe('useFacetsEntities', () => { }, }); - const { result, waitFor } = renderHook(() => - useFacetsEntities({ enabled: true }), - ); + const { result } = renderHook(() => useFacetsEntities({ enabled: true })); result.current[1]({ text: 'der ' }); await waitFor(() => { diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useQueryEntities.test.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useQueryEntities.test.ts index d974709d34..64cc7769a6 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useQueryEntities.test.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useQueryEntities.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { CatalogApi } from '@backstage/catalog-client'; import { useQueryEntities } from './useQueryEntities'; @@ -62,7 +62,7 @@ describe('useQueryEntities', () => { totalItems: 2, }); - const { result, waitFor } = renderHook(() => useQueryEntities()); + const { result } = renderHook(() => useQueryEntities()); const [, fetch] = result.current!; fetch({ text: 'text' }); diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx index f665ca6c00..85a477801a 100644 --- a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx +++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx @@ -49,7 +49,7 @@ const apis = TestApiRegistry.from([catalogApiRef, catalogApi]); describe('', () => { it('renders all owners', async () => { - renderInTestApp( + await renderInTestApp( diff --git a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx index bfaa689190..917ece047c 100644 --- a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.test.tsx @@ -14,7 +14,13 @@ * limitations under the License. */ -import { fireEvent, render, waitFor, screen } from '@testing-library/react'; +import { + fireEvent, + render, + waitFor, + screen, + act, +} from '@testing-library/react'; import React from 'react'; import { MockEntityListContextProvider } from '../../testUtils/providers'; import { EntityTagFilter } from '../../filters'; @@ -127,9 +133,7 @@ describe('', () => { , ); await waitFor(() => - expect(updateFilters).toHaveBeenLastCalledWith({ - tags: undefined, - }), + expect(screen.getByTestId('tags-picker-expand')).toBeInTheDocument(), ); fireEvent.click(screen.getByTestId('tags-picker-expand')); @@ -218,13 +222,16 @@ describe('', () => { , ); await waitFor(() => - expect(updateFilters).toHaveBeenLastCalledWith({ - tags: new EntityTagFilter(['tag1']), - }), + expect(screen.getByTestId('tags-picker-expand')).toBeInTheDocument(), ); - fireEvent.click(screen.getByTestId('tags-picker-expand')); - fireEvent.click(screen.getByLabelText('tag2')); - expect(screen.getByLabelText('tag2')).toBeChecked(); + + await act(async () => { + fireEvent.click(screen.getByTestId('tags-picker-expand')); + }); + await act(async () => { + fireEvent.click(screen.getByLabelText('tag2')); + }); + expect(updateFilters).toHaveBeenLastCalledWith({ tags: new EntityTagFilter(['tag1', 'tag2']), }); diff --git a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx index 8591cdad93..f0da550d0b 100644 --- a/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx +++ b/plugins/catalog-react/src/components/UnregisterEntityDialog/useUnregisterEntityDialogState.test.tsx @@ -17,16 +17,9 @@ import { CatalogApi, Location } from '@backstage/catalog-client'; import { Entity, ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model'; import { catalogApiRef } from '../../api'; -import { - act, - renderHook, - RenderHookResult, -} from '@testing-library/react-hooks'; -import React, { ReactNode } from 'react'; -import { - UseUnregisterEntityDialogState, - useUnregisterEntityDialogState, -} from './useUnregisterEntityDialogState'; +import { renderHook, waitFor } from '@testing-library/react'; +import React from 'react'; +import { useUnregisterEntityDialogState } from './useUnregisterEntityDialogState'; import { TestApiProvider } from '@backstage/test-utils'; function defer(): { promise: Promise; resolve: (value: T) => void } { @@ -85,31 +78,23 @@ describe('useUnregisterEntityDialogState', () => { }); it('goes through the happy unregister path', async () => { - let rendered: RenderHookResult< - { children?: ReactNode }, - UseUnregisterEntityDialogState - >; - act(() => { - rendered = renderHook(() => useUnregisterEntityDialogState(entity), { - wrapper: Wrapper, - }); + const rendered = renderHook(() => useUnregisterEntityDialogState(entity), { + wrapper: Wrapper, }); - expect(rendered!.result.current).toEqual({ type: 'loading' }); + expect(rendered.result.current).toEqual({ type: 'loading' }); resolveLocation({ type: 'url', target: 'https://example.com', id: 'x' }); resolveColocatedEntities([entity]); - await act(async () => { - await rendered!.waitForNextUpdate(); - }); - - expect(rendered!.result.current).toEqual({ - type: 'unregister', - location: 'url:https://example.com', - colocatedEntities: [{ kind: 'Component', namespace: 'ns', name: 'n' }], - unregisterLocation: expect.any(Function), - deleteEntity: expect.any(Function), + await waitFor(() => { + expect(rendered.result.current).toEqual({ + type: 'unregister', + location: 'url:https://example.com', + colocatedEntities: [{ kind: 'Component', namespace: 'ns', name: 'n' }], + unregisterLocation: expect.any(Function), + deleteEntity: expect.any(Function), + }); }); }); @@ -117,74 +102,53 @@ describe('useUnregisterEntityDialogState', () => { entity.metadata.annotations![ANNOTATION_ORIGIN_LOCATION] = 'bootstrap:bootstrap'; - let rendered: RenderHookResult< - { children?: ReactNode }, - UseUnregisterEntityDialogState - >; - act(() => { - rendered = renderHook(() => useUnregisterEntityDialogState(entity), { - wrapper: Wrapper, - }); + const rendered = renderHook(() => useUnregisterEntityDialogState(entity), { + wrapper: Wrapper, }); resolveLocation({ type: 'bootstrap', target: 'bootstrap', id: 'x' }); resolveColocatedEntities([]); - await act(async () => { - await rendered!.waitForNextUpdate(); - }); - expect(rendered!.result.current).toEqual({ - type: 'bootstrap', - location: 'bootstrap:bootstrap', - deleteEntity: expect.any(Function), + await waitFor(() => { + expect(rendered.result.current).toEqual({ + type: 'bootstrap', + location: 'bootstrap:bootstrap', + deleteEntity: expect.any(Function), + }); }); }); it('chooses only-delete when there was no location annotation', async () => { delete entity.metadata.annotations![ANNOTATION_ORIGIN_LOCATION]; - let rendered: RenderHookResult< - { children?: ReactNode }, - UseUnregisterEntityDialogState - >; - act(() => { - rendered = renderHook(() => useUnregisterEntityDialogState(entity), { - wrapper: Wrapper, - }); + const rendered = renderHook(() => useUnregisterEntityDialogState(entity), { + wrapper: Wrapper, }); resolveLocation(undefined); resolveColocatedEntities([]); - await act(async () => { - await rendered!.waitForNextUpdate(); - }); - expect(rendered!.result.current).toEqual({ - type: 'only-delete', - deleteEntity: expect.any(Function), + await waitFor(() => { + expect(rendered.result.current).toEqual({ + type: 'only-delete', + deleteEntity: expect.any(Function), + }); }); }); it('chooses only-delete when the location could not be found', async () => { - let rendered: RenderHookResult< - { children?: ReactNode }, - UseUnregisterEntityDialogState - >; - act(() => { - rendered = renderHook(() => useUnregisterEntityDialogState(entity), { - wrapper: Wrapper, - }); + const rendered = renderHook(() => useUnregisterEntityDialogState(entity), { + wrapper: Wrapper, }); resolveLocation(undefined); resolveColocatedEntities([]); - await act(async () => { - await rendered!.waitForNextUpdate(); - }); - expect(rendered!.result.current).toEqual({ - type: 'only-delete', - deleteEntity: expect.any(Function), + await waitFor(() => { + expect(rendered.result.current).toEqual({ + type: 'only-delete', + deleteEntity: expect.any(Function), + }); }); }); }); diff --git a/plugins/catalog-react/src/hooks/useEntity.test.tsx b/plugins/catalog-react/src/hooks/useEntity.test.tsx index 8fc388654a..3b1190de2b 100644 --- a/plugins/catalog-react/src/hooks/useEntity.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntity.test.tsx @@ -15,7 +15,7 @@ */ import React, { PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useEntity, useAsyncEntity, @@ -31,13 +31,13 @@ const entity = { metadata: { name: 'my-entity' }, kind: 'MyKind' } as Entity; describe('useEntity', () => { it('should throw if no entity is provided', async () => { - const { result } = renderHook(() => useEntity(), { - wrapper: ({ children }: React.PropsWithChildren<{}>) => ( - - ), - }); - - expect(result.error?.message).toMatch(/entity has not been loaded/); + expect(() => + renderHook(() => useEntity(), { + wrapper: ({ children }: React.PropsWithChildren<{}>) => ( + + ), + }), + ).toThrow(/entity has not been loaded/); }); it('should provide an entity', async () => { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index da27c61dcb..d77655ebcc 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -25,7 +25,7 @@ import { storageApiRef, } from '@backstage/core-plugin-api'; import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router-dom'; @@ -119,10 +119,14 @@ describe('', () => { }); it('resolves backend filters', async () => { - const { result, waitForValueToChange } = renderHook(() => useEntityList(), { + const { result } = renderHook(() => useEntityList(), { wrapper, }); - await waitForValueToChange(() => result.current.backendEntities); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); + expect(result.current.backendEntities.length).toBe(2); expect(mockCatalogApi.getEntities).toHaveBeenCalledWith({ filter: { kind: 'component' }, @@ -130,13 +134,16 @@ describe('', () => { }); it('resolves frontend filters', async () => { - const { result, waitFor } = renderHook(() => useEntityList(), { + const { result } = renderHook(() => useEntityList(), { wrapper, initialProps: { userFilter: 'all', }, }); - await waitFor(() => !!result.current.entities.length); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); expect(result.current.backendEntities.length).toBe(2); act(() => @@ -160,13 +167,14 @@ describe('', () => { const query = qs.stringify({ filters: { kind: 'component', type: 'service' }, }); - const { result, waitFor } = renderHook(() => useEntityList(), { - wrapper, - initialProps: { - location: `/catalog?${query}`, - }, + const { result } = renderHook(() => useEntityList(), { + wrapper: ({ children }) => + wrapper({ location: `/catalog?${query}`, children }), + }); + + await waitFor(() => { + expect(result.current.queryParameters).toBeTruthy(); }); - await act(() => waitFor(() => !!result.current.queryParameters)); expect(result.current.queryParameters).toEqual({ kind: 'component', type: 'service', @@ -174,7 +182,7 @@ describe('', () => { }); it('does not fetch when only frontend filters change', async () => { - const { result, waitFor } = renderHook(() => useEntityList(), { + const { result } = renderHook(() => useEntityList(), { wrapper, }); @@ -200,32 +208,34 @@ describe('', () => { }); it('debounces multiple filter changes', async () => { - const { result, waitForNextUpdate, waitForValueToChange } = renderHook( - () => useEntityList(), - { - wrapper, - }, - ); - await waitForValueToChange(() => result.current.backendEntities); + const { result } = renderHook(() => useEntityList(), { + wrapper, + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); expect(result.current.backendEntities.length).toBe(2); expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); - act(() => { + await act(async () => { result.current.updateFilters({ kind: new EntityKindFilter('component') }); result.current.updateFilters({ type: new EntityTypeFilter('service') }); }); - await waitForNextUpdate(); - expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(2); + + await waitFor(() => { + expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(2); + }); }); it('returns an error on catalogApi failure', async () => { - const { result, waitForValueToChange, waitFor } = renderHook( - () => useEntityList(), - { - wrapper, - }, - ); - await waitForValueToChange(() => result.current.backendEntities); + const { result } = renderHook(() => useEntityList(), { + wrapper, + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBeGreaterThan(0); + }); expect(result.current.backendEntities.length).toBe(2); mockCatalogApi.getEntities = jest.fn().mockRejectedValue('error'); diff --git a/plugins/catalog-react/src/hooks/useEntityOwnership.test.tsx b/plugins/catalog-react/src/hooks/useEntityOwnership.test.tsx index dc400b5c90..6c9519eb08 100644 --- a/plugins/catalog-react/src/hooks/useEntityOwnership.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityOwnership.test.tsx @@ -18,7 +18,7 @@ import { CatalogApi } from '@backstage/catalog-client'; import { ComponentEntity, RELATION_OWNED_BY } from '@backstage/catalog-model'; import { IdentityApi, identityApiRef } from '@backstage/core-plugin-api'; import { TestApiProvider } from '@backstage/test-utils'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import React from 'react'; import { catalogApiRef } from '../api'; import { useEntityOwnership } from './useEntityOwnership'; @@ -83,19 +83,15 @@ describe('useEntityOwnership', () => { }); mockCatalogApi.getEntityByRef.mockResolvedValue(undefined); - const { result, waitForValueToChange } = renderHook( - () => useEntityOwnership(), - { - wrapper: Wrapper, - }, - ); + const { result } = renderHook(() => useEntityOwnership(), { + wrapper: Wrapper, + }); expect(result.current.loading).toBe(true); expect(result.current.isOwnedEntity(ownedEntity)).toBe(false); - await waitForValueToChange(() => result.current.loading); + await waitFor(() => expect(result.current.loading).toBe(false)); - expect(result.current.loading).toBe(false); expect(result.current.isOwnedEntity(ownedEntity)).toBe(true); }); }); diff --git a/plugins/catalog-react/src/hooks/useEntityPermission.test.tsx b/plugins/catalog-react/src/hooks/useEntityPermission.test.tsx index aed6676838..0c389de747 100644 --- a/plugins/catalog-react/src/hooks/useEntityPermission.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityPermission.test.tsx @@ -15,7 +15,7 @@ */ import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common/alpha'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useEntityPermission } from './useEntityPermission'; import { useAsyncEntity } from './useEntity'; import { usePermission } from '@backstage/plugin-permission-react'; diff --git a/plugins/catalog-react/src/hooks/useRelatedEntities.test.tsx b/plugins/catalog-react/src/hooks/useRelatedEntities.test.tsx index 8de7822d59..092f8e164e 100644 --- a/plugins/catalog-react/src/hooks/useRelatedEntities.test.tsx +++ b/plugins/catalog-react/src/hooks/useRelatedEntities.test.tsx @@ -16,8 +16,8 @@ import { Entity } from '@backstage/catalog-model'; import { TestApiProvider } from '@backstage/test-utils'; -import { WrapperComponent, renderHook } from '@testing-library/react-hooks'; -import React, { PropsWithChildren } from 'react'; +import { renderHook, waitFor } from '@testing-library/react'; +import React, { ComponentType, PropsWithChildren } from 'react'; import { catalogApiRef } from '../api'; import { useRelatedEntities } from './useRelatedEntities'; @@ -50,7 +50,7 @@ describe('useRelatedEntities', () => { getEntitiesByRefs: jest.fn(), }; - const wrapper: WrapperComponent> = ({ children }) => { + const wrapper: ComponentType> = ({ children }) => { return ( {children} @@ -70,7 +70,9 @@ describe('useRelatedEntities', () => { expect(rendered.result.current).toEqual({ loading: true }); - await rendered.waitForValueToChange(() => rendered.result.current.loading); + await waitFor(() => { + expect(rendered.result.current.loading).toBe(false); + }); expect(catalogApi.getEntitiesByRefs).toHaveBeenCalledWith({ entityRefs: ['group:default/the-owners-1', 'group:default/the-owners-2'], diff --git a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx index f21b3cb710..e3010a0f4a 100644 --- a/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx +++ b/plugins/catalog-react/src/hooks/useStarredEntities.test.tsx @@ -16,7 +16,7 @@ import { Entity } from '@backstage/catalog-model'; import { TestApiProvider } from '@backstage/test-utils'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import React, { PropsWithChildren } from 'react'; import { starredEntitiesApiRef, @@ -56,14 +56,13 @@ describe('useStarredEntities', () => { }); it('should return an empty set', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntities(), - { wrapper }, - ); + const { result } = renderHook(() => useStarredEntities(), { + wrapper, + }); - await waitForNextUpdate(); - - expect(result.current.starredEntities.size).toBe(0); + await waitFor(() => { + expect(result.current.starredEntities.size).toBe(0); + }); }); it('should return a set with the current items', async () => { @@ -72,25 +71,21 @@ describe('useStarredEntities', () => { mockApi.toggleStarred(id); } - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntities(), - { wrapper }, - ); + const { result } = renderHook(() => useStarredEntities(), { + wrapper, + }); - await waitForNextUpdate(); - - for (const item of expectedIds) { - expect(result.current.starredEntities.has(item)).toBeTruthy(); - } + await waitFor(() => { + for (const item of expectedIds) { + expect(result.current.starredEntities.has(item)).toBeTruthy(); + } + }); }); it('should listen to changes when the storage is set elsewhere', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntities(), - { wrapper }, - ); - - await waitForNextUpdate(); + const { result } = renderHook(() => useStarredEntities(), { + wrapper, + }); expect(result.current.starredEntities.size).toBe(0); expect(result.current.isStarredEntity(mockEntity)).toBeFalsy(); @@ -99,42 +94,37 @@ describe('useStarredEntities', () => { // catch when the hook re-renders with the latest data setTimeout(() => result.current.toggleStarredEntity(mockEntity), 1); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.starredEntities.size).toBe(1); + }); - expect(result.current.starredEntities.size).toBe(1); expect(result.current.isStarredEntity(mockEntity)).toBeTruthy(); }); it('should write new entries to the local store when adding a toggling entity', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntities(), - { wrapper }, - ); - - act(() => { - result.current.toggleStarredEntity(mockEntity); + const { result } = renderHook(() => useStarredEntities(), { + wrapper, }); - await waitForNextUpdate(); + await act(async () => { + result.current.toggleStarredEntity(mockEntity); + }); expect(result.current.isStarredEntity(mockEntity)).toBeTruthy(); expect(result.current.isStarredEntity(secondMockEntity)).toBeFalsy(); }); it('should remove an existing entity when toggling entries', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntities(), - { wrapper }, - ); + const { result } = renderHook(() => useStarredEntities(), { + wrapper, + }); - act(() => { + await act(async () => { result.current.toggleStarredEntity(mockEntity); result.current.toggleStarredEntity(secondMockEntity); result.current.toggleStarredEntity(mockEntity); }); - await waitForNextUpdate(); - expect(result.current.isStarredEntity(mockEntity)).toBeFalsy(); expect(result.current.isStarredEntity(secondMockEntity)).toBeTruthy(); }); diff --git a/plugins/catalog-react/src/hooks/useStarredEntities.ts b/plugins/catalog-react/src/hooks/useStarredEntities.ts index 328a26e0f8..7e63aed10f 100644 --- a/plugins/catalog-react/src/hooks/useStarredEntities.ts +++ b/plugins/catalog-react/src/hooks/useStarredEntities.ts @@ -20,7 +20,7 @@ import { stringifyEntityRef, } from '@backstage/catalog-model'; import { useApi } from '@backstage/core-plugin-api'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { starredEntitiesApiRef } from '../apis'; @@ -45,7 +45,7 @@ export function useStarredEntities(): { const starredEntitiesApi = useApi(starredEntitiesApiRef); const starredEntities = useObservable( - starredEntitiesApi.starredEntitie$(), + useMemo(() => starredEntitiesApi.starredEntitie$(), [starredEntitiesApi]), new Set(), ); diff --git a/plugins/catalog-react/src/hooks/useStarredEntity.test.tsx b/plugins/catalog-react/src/hooks/useStarredEntity.test.tsx index d24b27f903..e64a9bbdf8 100644 --- a/plugins/catalog-react/src/hooks/useStarredEntity.test.tsx +++ b/plugins/catalog-react/src/hooks/useStarredEntity.test.tsx @@ -16,7 +16,7 @@ import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; import { TestApiProvider } from '@backstage/test-utils'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import React, { PropsWithChildren } from 'react'; import Observable from 'zen-observable'; import { StarredEntitiesApi, starredEntitiesApiRef } from '../apis'; @@ -83,18 +83,16 @@ describe('useStarredEntity', () => { ); mockStarredEntitiesApi.toggleStarred.mockResolvedValue(); - const { result, waitForNextUpdate } = renderHook( - () => useStarredEntity(entityOrRef), - { - wrapper, - }, - ); + const { result } = renderHook(() => useStarredEntity(entityOrRef), { + wrapper, + }); // the initial value will always be false because the observable triggers async expect(result.current.isStarredEntity).toBe(false); - await waitForNextUpdate(); - expect(result.current.isStarredEntity).toBe(true); + await waitFor(() => { + expect(result.current.isStarredEntity).toBe(true); + }); }); }); }); diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index f42483fc92..afd3890a12 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 822fffa343..b4d95ac20a 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.1.4-next.2", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,8 +41,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -51,7 +51,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 2286652eb8..6b5ba8b956 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-catalog +## 1.14.0 + +### Minor Changes + +- 28f1ab2e1a: The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: + + ```ts + import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + + const app = createApp({ + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, + }); + ``` + +- f3561a2935: include owner chip in catalog search result item + +### Patch Changes + +- 7c4a8e4d5f: Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- 0296f272b4: The `spec.lifecycle' field in entities will now always be rendered as a string. +- 0b55f773a7: Removed some unused dependencies +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- e5a2956dd2: Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + - @backstage/plugin-search-common@1.2.7 + ## 1.14.0-next.2 ### Patch Changes diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/alpha-api-report.md index 4582a13a5d..43e589bdc3 100644 --- a/plugins/catalog/alpha-api-report.md +++ b/plugins/catalog/alpha-api-report.md @@ -3,25 +3,56 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; +/// + +import { AnyExtensionInputMap } from '@backstage/frontend-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { PortableSchema } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -export const CatalogApi: Extension<{}>; +export function createCatalogFilterExtension< + TInputs extends AnyExtensionInputMap, + TConfig = never, +>(options: { + id: string; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: (options: { config: TConfig }) => Promise; +}): Extension; // @alpha (undocumented) -export const CatalogSearchResultListItemExtension: Extension<{ - noTrack?: boolean | undefined; -}>; - -// @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + catalogIndex: RouteRef; + catalogEntity: RouteRef<{ + name: string; + kind: string; + namespace: string; + }>; + }, + { + viewTechDoc: ExternalRouteRef< + { + name: string; + kind: string; + namespace: string; + }, + true + >; + createComponent: ExternalRouteRef; + createFromTemplate: ExternalRouteRef< + { + namespace: string; + templateName: string; + }, + true + >; + } +>; export default _default; -// @alpha (undocumented) -export const StarredEntitiesApi: Extension<{}>; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 67106a5d5e..9b879e3c50 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.14.0-next.2", + "version": "1.14.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -10,13 +10,13 @@ }, "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.tsx", + "./alpha": "./src/alpha.ts", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.tsx" + "src/alpha.ts" ], "package.json": [ "package.json" @@ -71,8 +71,8 @@ "zen-observable": "^0.10.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -83,7 +83,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0" }, "files": [ diff --git a/plugins/catalog-react/src/alpha.ts b/plugins/catalog/src/alpha.ts similarity index 85% rename from plugins/catalog-react/src/alpha.ts rename to plugins/catalog/src/alpha.ts index e8ff21609e..e80f131817 100644 --- a/plugins/catalog-react/src/alpha.ts +++ b/plugins/catalog/src/alpha.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { isOwnerOf } from './utils'; -export { useEntityPermission } from './hooks/useEntityPermission'; +export * from './alpha/index'; +export { default } from './alpha/index'; diff --git a/plugins/catalog/src/alpha.tsx b/plugins/catalog/src/alpha.tsx deleted file mode 100644 index 5e78a52f9b..0000000000 --- a/plugins/catalog/src/alpha.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - createApiFactory, - discoveryApiRef, - fetchApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; -import { CatalogClient } from '@backstage/catalog-client'; -import { - createApiExtension, - createPlugin, -} from '@backstage/frontend-plugin-api'; -import { - catalogApiRef, - starredEntitiesApiRef, -} from '@backstage/plugin-catalog-react'; -import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; -import { DefaultStarredEntitiesApi } from './apis'; - -/** @alpha */ -export const CatalogApi = createApiExtension({ - factory: createApiFactory({ - api: catalogApiRef, - deps: { - discoveryApi: discoveryApiRef, - fetchApi: fetchApiRef, - }, - factory: ({ discoveryApi, fetchApi }) => - new CatalogClient({ discoveryApi, fetchApi }), - }), -}); - -/** @alpha */ -export const StarredEntitiesApi = createApiExtension({ - factory: createApiFactory({ - api: starredEntitiesApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), - }), -}); - -/** @alpha */ -export const CatalogSearchResultListItemExtension = - createSearchResultListItemExtension({ - id: 'catalog', - predicate: result => result.type === 'software-catalog', - component: () => - import('./components/CatalogSearchResultListItem').then( - m => m.CatalogSearchResultListItem, - ), - }); - -/** @alpha */ -export default createPlugin({ - id: 'catalog', - extensions: [ - CatalogApi, - StarredEntitiesApi, - CatalogSearchResultListItemExtension, - ], -}); diff --git a/plugins/catalog/src/alpha/builtInFilterExtensions.tsx b/plugins/catalog/src/alpha/builtInFilterExtensions.tsx new file mode 100644 index 0000000000..5a7575c4f5 --- /dev/null +++ b/plugins/catalog/src/alpha/builtInFilterExtensions.tsx @@ -0,0 +1,121 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { createCatalogFilterExtension } from './createCatalogFilterExtension'; +import { createSchemaFromZod } from '@backstage/frontend-plugin-api'; + +const CatalogEntityTagFilter = createCatalogFilterExtension({ + id: 'entity.tag', + loader: async () => { + const { EntityTagPicker } = await import('@backstage/plugin-catalog-react'); + return ; + }, +}); + +const CatalogEntityKindFilter = createCatalogFilterExtension({ + id: 'entity.kind', + configSchema: createSchemaFromZod(z => + z.object({ + initialFilter: z.string().default('component'), + }), + ), + loader: async ({ config }) => { + const { EntityKindPicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogEntityTypeFilter = createCatalogFilterExtension({ + id: 'entity.type', + loader: async () => { + const { EntityTypePicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogEntityOwnerFilter = createCatalogFilterExtension({ + id: 'entity.mode', + configSchema: createSchemaFromZod(z => + z.object({ + mode: z.enum(['owners-only', 'all']).optional(), + }), + ), + loader: async ({ config }) => { + const { EntityOwnerPicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogEntityNamespaceFilter = createCatalogFilterExtension({ + id: 'entity.namespace', + loader: async () => { + const { EntityNamespacePicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogEntityLifecycleFilter = createCatalogFilterExtension({ + id: 'entity.lifecycle', + loader: async () => { + const { EntityLifecyclePicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogEntityProcessingStatusFilter = createCatalogFilterExtension({ + id: 'entity.processing.status', + loader: async () => { + const { EntityProcessingStatusPicker } = await import( + '@backstage/plugin-catalog-react' + ); + return ; + }, +}); + +const CatalogUserListFilter = createCatalogFilterExtension({ + id: 'user.list', + configSchema: createSchemaFromZod(z => + z.object({ + initialFilter: z.enum(['owned', 'starred', 'all']).default('owned'), + }), + ), + loader: async ({ config }) => { + const { UserListPicker } = await import('@backstage/plugin-catalog-react'); + return ; + }, +}); + +export const builtInFilterExtensions = [ + CatalogEntityTagFilter, + CatalogEntityKindFilter, + CatalogEntityTypeFilter, + CatalogEntityOwnerFilter, + CatalogEntityNamespaceFilter, + CatalogEntityLifecycleFilter, + CatalogEntityProcessingStatusFilter, + CatalogUserListFilter, +]; diff --git a/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx new file mode 100644 index 0000000000..5a6328078c --- /dev/null +++ b/plugins/catalog/src/alpha/createCatalogFilterExtension.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { lazy } from 'react'; +import { + AnyExtensionInputMap, + ExtensionBoundary, + PortableSchema, + coreExtensionData, + createExtension, +} from '@backstage/frontend-plugin-api'; + +/** @alpha */ +export function createCatalogFilterExtension< + TInputs extends AnyExtensionInputMap, + TConfig = never, +>(options: { + id: string; + inputs?: TInputs; + configSchema?: PortableSchema; + loader: (options: { config: TConfig }) => Promise; +}) { + const id = `catalog.filter.${options.id}`; + + return createExtension({ + id, + attachTo: { id: 'plugin.catalog.page.index', input: 'filters' }, + inputs: options.inputs ?? {}, + configSchema: options.configSchema, + output: { + element: coreExtensionData.reactElement, + }, + factory({ bind, config, source }) { + const ExtensionComponent = lazy(() => + options + .loader({ config }) + .then(element => ({ default: () => element })), + ); + + bind({ + element: ( + + + + ), + }); + }, + }); +} diff --git a/plugins/catalog/src/alpha/index.ts b/plugins/catalog/src/alpha/index.ts new file mode 100644 index 0000000000..06a78ec6ea --- /dev/null +++ b/plugins/catalog/src/alpha/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './plugin'; +export { createCatalogFilterExtension } from './createCatalogFilterExtension'; diff --git a/plugins/catalog/src/alpha/plugin.tsx b/plugins/catalog/src/alpha/plugin.tsx new file mode 100644 index 0000000000..d9d2878213 --- /dev/null +++ b/plugins/catalog/src/alpha/plugin.tsx @@ -0,0 +1,201 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import HomeIcon from '@material-ui/icons/Home'; +import { + createApiFactory, + discoveryApiRef, + fetchApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { CatalogClient } from '@backstage/catalog-client'; +import { + createApiExtension, + createPageExtension, + createPlugin, + createNavItemExtension, + coreExtensionData, + createExtensionInput, +} from '@backstage/frontend-plugin-api'; +import { + AsyncEntityProvider, + catalogApiRef, + entityRouteRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; +import { + createEntityContentExtension, + createEntityCardExtension, + entityContentTitleExtensionDataRef, +} from '@backstage/plugin-catalog-react/alpha'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; +import { DefaultStarredEntitiesApi } from '../apis'; +import { + createComponentRouteRef, + createFromTemplateRouteRef, + rootRouteRef, + viewTechDocRouteRef, +} from '../routes'; +import { builtInFilterExtensions } from './builtInFilterExtensions'; +import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; +import Grid from '@material-ui/core/Grid'; + +/** @alpha */ +export const CatalogApi = createApiExtension({ + factory: createApiFactory({ + api: catalogApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new CatalogClient({ discoveryApi, fetchApi }), + }), +}); + +/** @alpha */ +export const StarredEntitiesApi = createApiExtension({ + factory: createApiFactory({ + api: starredEntitiesApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), + }), +}); + +/** @alpha */ +export const CatalogSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'catalog', + predicate: result => result.type === 'software-catalog', + component: () => + import('../components/CatalogSearchResultListItem').then( + m => m.CatalogSearchResultListItem, + ), + }); + +const CatalogIndexPage = createPageExtension({ + id: 'plugin.catalog.page.index', + defaultPath: '/catalog', + routeRef: convertLegacyRouteRef(rootRouteRef), + inputs: { + filters: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + loader: async ({ inputs }) => { + const { BaseCatalogPage } = await import('../components/CatalogPage'); + const filters = inputs.filters.map(filter => filter.element); + return {filters}} />; + }, +}); + +const CatalogEntityPage = createPageExtension({ + id: 'plugin.catalog.page.entity', + defaultPath: '/catalog/:namespace/:kind/:name', + routeRef: convertLegacyRouteRef(entityRouteRef), + inputs: { + contents: createExtensionInput({ + element: coreExtensionData.reactElement, + path: coreExtensionData.routePath, + routeRef: coreExtensionData.routeRef.optional(), + title: entityContentTitleExtensionDataRef, + }), + }, + loader: async ({ inputs }) => { + const { EntityLayout } = await import('../components/EntityLayout'); + const Component = () => { + return ( + + + {inputs.contents.map(content => ( + + {content.element} + + ))} + + + ); + }; + return ; + }, +}); + +const EntityAboutCard = createEntityCardExtension({ + id: 'about', + loader: async () => + import('../components/AboutCard').then(m => ( + + )), +}); + +const OverviewEntityContent = createEntityContentExtension({ + id: 'overview', + defaultPath: '/', + defaultTitle: 'Overview', + disabled: false, + inputs: { + cards: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + loader: async ({ inputs }) => ( + + {inputs.cards.map(card => ( + + {card.element} + + ))} + + ), +}); + +const CatalogNavItem = createNavItemExtension({ + id: 'catalog.nav.index', + routeRef: convertLegacyRouteRef(rootRouteRef), + title: 'Catalog', + icon: HomeIcon, +}); + +/** @alpha */ +export default createPlugin({ + id: 'catalog', + routes: { + catalogIndex: convertLegacyRouteRef(rootRouteRef), + catalogEntity: convertLegacyRouteRef(entityRouteRef), + }, + externalRoutes: { + viewTechDoc: convertLegacyRouteRef(viewTechDocRouteRef), + createComponent: convertLegacyRouteRef(createComponentRouteRef), + createFromTemplate: convertLegacyRouteRef(createFromTemplateRouteRef), + }, + extensions: [ + CatalogApi, + StarredEntitiesApi, + CatalogSearchResultListItemExtension, + CatalogIndexPage, + CatalogEntityPage, + CatalogNavItem, + OverviewEntityContent, + EntityAboutCard, + ...builtInFilterExtensions, + ], +}); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index fb9b282d57..e50c69b8ec 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -44,6 +44,41 @@ import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { catalogTranslationRef } from '../../translation'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +/** @internal */ +export interface BaseCatalogPageProps { + filters: ReactNode; + content?: ReactNode; +} + +/** @internal */ +export function BaseCatalogPage(props: BaseCatalogPageProps) { + const { filters, content = } = props; + const orgName = + useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; + const createComponentLink = useRouteRef(createComponentRouteRef); + const { t } = useTranslationRef(catalogTranslationRef); + + return ( + + + + + All your software catalog entities + + + + {filters} + {content} + + + + + ); +} + /** * Props for root catalog pages. * @@ -69,44 +104,29 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { emptyContent, ownerPickerMode, } = props; - const orgName = - useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; - const createComponentLink = useRouteRef(createComponentRouteRef); - const { t } = useTranslationRef(catalogTranslationRef); return ( - - - - - All your software catalog entities - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + } + content={ + + } + /> ); } diff --git a/plugins/catalog/src/components/CatalogPage/index.ts b/plugins/catalog/src/components/CatalogPage/index.ts index 9a3d083f41..258fedf15c 100644 --- a/plugins/catalog/src/components/CatalogPage/index.ts +++ b/plugins/catalog/src/components/CatalogPage/index.ts @@ -15,5 +15,8 @@ */ export { CatalogPage } from './CatalogPage'; -export { DefaultCatalogPage } from './DefaultCatalogPage'; -export type { DefaultCatalogPageProps } from './DefaultCatalogPage'; +export { BaseCatalogPage, DefaultCatalogPage } from './DefaultCatalogPage'; +export type { + BaseCatalogPageProps, + DefaultCatalogPageProps, +} from './DefaultCatalogPage'; diff --git a/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx b/plugins/catalog/src/components/EntitySwitch/EntitySwitch.test.tsx index d9998b0ca5..aebdd6b9c2 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, screen, waitFor } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React, { useEffect } from 'react'; import { isKind } from './conditions'; import { EntitySwitch } from './EntitySwitch'; @@ -517,9 +517,7 @@ describe('EntitySwitch', () => { , ); - await waitFor(() => expect(shouldRender).toHaveBeenCalled()); - - expect(screen.getByText('C')).toBeInTheDocument(); + await expect(screen.findByText('C')).resolves.toBeInTheDocument(); expect(screen.queryByText('A')).not.toBeInTheDocument(); expect(screen.queryByText('B')).not.toBeInTheDocument(); }); diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index 8821eeab83..b0cb0fb020 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/plugin-cicd-statistics@0.1.27 + - @backstage/catalog-model@1.4.3 + ## 0.1.21-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index d2997056fc..6c7f3c150f 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.21-next.2", + "version": "0.1.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "p-limit": "^4.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 7d07199028..9fe1717192 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-cicd-statistics +## 0.1.27 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + ## 0.1.27-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics/catalog-info.yaml b/plugins/cicd-statistics/catalog-info.yaml index 83021cc033..eab84c1283 100644 --- a/plugins/cicd-statistics/catalog-info.yaml +++ b/plugins/cicd-statistics/catalog-info.yaml @@ -7,4 +7,4 @@ metadata: spec: lifecycle: experimental type: backstage-frontend-plugin - owner: maintainers + owner: sharks diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 744963d55c..fb8b736035 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.27-next.2", + "version": "0.1.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,8 +54,8 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "files": [ diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 7a25c01f56..c8ba1ae27f 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-circleci +## 0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.3.25-next.2 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 752e908374..ddec70c2de 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.25-next.2", + "version": "0.3.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,8 +50,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.25.1", "cross-fetch": "^3.1.5", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index c1ac4d0747..a322da009c 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-cloudbuild +## 0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.3.25-next.2 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 055fb5bb62..8b64387aa8 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.25-next.2", + "version": "0.3.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,7 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 5f97316244..65dda2e3f5 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-code-climate +## 0.1.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.1.25-next.2 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 4b2bfcd9b3..dc01c52a13 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.25-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -53,7 +53,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.27.1", "@types/luxon": "^3.0.0", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index c7fb955e9f..2cc9d85f3b 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-code-coverage-backend +## 0.2.20 + +### Patch Changes + +- 4aa27aa200: Added option to set body size limit +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + ## 0.2.20-next.2 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 3c07f28eb8..9ee98d52ad 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.20-next.2", + "version": "0.2.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage-backend/src/service/standaloneServer.ts b/plugins/code-coverage-backend/src/service/standaloneServer.ts index 23eaf981c1..a2207b86d9 100644 --- a/plugins/code-coverage-backend/src/service/standaloneServer.ts +++ b/plugins/code-coverage-backend/src/service/standaloneServer.ts @@ -16,17 +16,17 @@ import { createServiceBuilder, + DatabaseManager, HostDiscovery, loadBackendConfig, UrlReaders, - useHotMemoize, } from '@backstage/backend-common'; import { CatalogApi } from '@backstage/catalog-client'; import { CompoundEntityRef, parseEntityRef } from '@backstage/catalog-model'; import { Server } from 'http'; -import knexFactory from 'knex'; import { Logger } from 'winston'; import { createRouter } from './router'; +import { ConfigReader } from '@backstage/config'; export interface ServerOptions { port: number; @@ -40,19 +40,14 @@ export async function startStandaloneServer( const logger = options.logger.child({ service: 'code-coverage-backend' }); const config = await loadBackendConfig({ logger, argv: process.argv }); - const db = useHotMemoize(module, () => { - const knex = knexFactory({ - client: 'better-sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - - knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - - return knex; - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('code-coverage'); const catalogApi = { async getEntityByRef(entityRef: string | CompoundEntityRef) { @@ -69,7 +64,7 @@ export async function startStandaloneServer( logger.debug('Starting application server...'); const router = await createRouter({ - database: { getClient: async () => db }, + database, config, discovery: HostDiscovery.fromConfig(config), urlReader: UrlReaders.default({ logger, config }), diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 06a29ca4cc..f5ba60eeb4 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-code-coverage +## 0.2.18 + +### Patch Changes + +- 88b0b32547: Fixed the coverage history statistics to compare newest with oldest record +- 0296f272b4: The warning for missing code coverage will now render the entity as a reference. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- a468544fa9: Updated layout to improve contrasts and consistency with other plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index c2c16f69b6..15343a8212 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.18-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,7 +58,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/highlightjs": "^10.1.0", "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index aed76f3c8b..29f0700e65 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-codescene +## 0.1.18 + +### Patch Changes + +- 9c9a9100b0: Internal refactor to avoid using the deprecated `.icon.svg` extension. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.1.18-next.2 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index 4d3e5ab597..e36c8e5575 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.18-next.2", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,8 +42,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -53,7 +53,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 0b1a03c5e5..3e09c6dd98 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-config-schema +## 0.1.46 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.1.46-next.2 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 6b97abc91d..387921650b 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.46-next.2", + "version": "0.1.46", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "zen-observable": "^0.10.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 08dc64071e..a60e531966 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-cost-insights +## 0.12.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- ba4820883c: Updated dependency `@types/pluralize` to `^0.0.31`. +- 959aa2a09f: The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-cost-insights-common@0.1.2 + ## 0.12.14-next.2 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index a66fde70ad..5cd7c3458b 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.14-next.2", + "version": "0.12.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,8 +57,8 @@ "yup": "^0.32.9" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -68,7 +68,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/pluralize": "^0.0.31", "@types/recharts": "^1.8.14", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 16de7b7e6f..fd9108d28d 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-devtools-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/config-loader@1.5.1 + - @backstage/errors@1.2.3 + - @backstage/cli-common@0.1.13 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.5 + - @backstage/plugin-permission-common@0.7.9 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 865bbae714..acf7788d8c 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.2.3-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 48688e77de..4a95434b3d 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-devtools-common +## 0.1.5 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 7f1aa0f93f..703ad2a5e3 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-devtools-common", "description": "Common functionalities for the devtools plugin", - "version": "0.1.5-next.0", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index a585b7bde7..b200af4d82 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-devtools +## 0.1.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.5 + ## 0.1.5-next.2 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 7dffd4fdc4..41ea821dea 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.5-next.2", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -54,7 +54,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 71b6670ab6..2de9b4555b 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-dynatrace +## 7.0.5 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 7.0.5-next.2 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index bfea48cc90..f8b35eafaa 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "7.0.5-next.2", + "version": "7.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,8 +41,8 @@ }, "peerDependencies": { "@backstage/plugin-catalog-react": "workspace:^", - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -52,7 +52,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "express": "^4.18.1", "msw": "^1.0.0" diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index 3f7cac2902..acfdaf360f 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-entity-feedback-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index 8fe5048e4b..c493be7075 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.2.3-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-backend/src/service/standaloneServer.ts b/plugins/entity-feedback-backend/src/service/standaloneServer.ts index f230cc1463..27c48ebb1e 100644 --- a/plugins/entity-feedback-backend/src/service/standaloneServer.ts +++ b/plugins/entity-feedback-backend/src/service/standaloneServer.ts @@ -19,7 +19,6 @@ import { DatabaseManager, loadBackendConfig, HostDiscovery, - useHotMemoize, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; @@ -40,16 +39,14 @@ export async function startStandaloneServer( const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = HostDiscovery.fromConfig(config); - const database = useHotMemoize(module, () => { - const manager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { client: 'better-sqlite3', connection: ':memory:' }, - }, - }), - ); - return manager.forPlugin('entity-feedback'); - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('entity-feedback'); const identity = DefaultIdentityClient.create({ discovery, diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index a88d2edb3f..469ff16ca2 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-entity-feedback +## 0.2.8 + +### Patch Changes + +- 48c8b93e98: Added tooltip to like dislike buttons +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index fb2d03d6c4..f2a4697454 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.2.8-next.2", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -54,8 +54,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/entity-feedback/src/components/LikeDislikeButtons/LikeDislikeButtons.tsx b/plugins/entity-feedback/src/components/LikeDislikeButtons/LikeDislikeButtons.tsx index 2d38e60ac2..6c634deefb 100644 --- a/plugins/entity-feedback/src/components/LikeDislikeButtons/LikeDislikeButtons.tsx +++ b/plugins/entity-feedback/src/components/LikeDislikeButtons/LikeDislikeButtons.tsx @@ -24,6 +24,7 @@ import { } from '@backstage/core-plugin-api'; import { useAsyncEntity } from '@backstage/plugin-catalog-react'; import { IconButton } from '@material-ui/core'; +import Tooltip from '@material-ui/core/Tooltip'; import ThumbDownIcon from '@material-ui/icons/ThumbDown'; import ThumbUpIcon from '@material-ui/icons/ThumbUp'; import ThumbDownOutlinedIcon from '@material-ui/icons/ThumbDownOutlined'; @@ -127,9 +128,13 @@ export const LikeDislikeButtons = (props: LikeDislikeButtonsProps) => { onClick={() => applyRating(FeedbackRatings.like)} > {rating === FeedbackRatings.like ? ( - + + + ) : ( - + + + )} { onClick={() => applyRating(FeedbackRatings.dislike)} > {rating === FeedbackRatings.dislike ? ( - + + + ) : ( - + + + )} Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin<{}, {}>; export default _default; // @alpha (undocumented) diff --git a/plugins/explore/package.json b/plugins/explore/package.json index e9967fda71..435c5df84d 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.4.11-next.2", + "version": "0.4.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -66,8 +66,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -78,7 +78,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 8bb37cc531..ef28aa04c6 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-firehydrant +## 0.2.9 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.2.9-next.2 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 5ea154d32f..ed723f71cf 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.2.9-next.2", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -54,7 +54,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index e22cf6629c..099ab5f5a4 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-fossa +## 0.2.57 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.2.57-next.2 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index cb79e48325..6c08f3d4fd 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.57-next.2", + "version": "0.2.57", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,8 +50,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index 0a64fd7019..f9ac25d7f6 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-gcalendar +## 0.3.19 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.3.19-next.2 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index b871d49729..d84850677b 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.19-next.2", + "version": "0.3.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,7 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/dompurify": "^2.3.3", "@types/sanitize-html": "^2.6.2", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index c5c8d88264..5a2c289a94 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-gcp-projects +## 0.3.42 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.3.42-next.2 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 4c365e4a33..24bb9a99fa 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.42-next.2", + "version": "0.3.42", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -55,7 +55,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 7471d15867..a91f49bbe1 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-git-release-manager +## 0.3.38 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.3.38-next.2 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 3a49aee327..2c0ce60f6a 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.38-next.2", + "version": "0.3.38", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,8 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/recharts": "^1.8.15", "msw": "^1.0.0" diff --git a/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx b/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx index 25a987df2a..c5490103cb 100644 --- a/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx +++ b/plugins/git-release-manager/src/features/CreateReleaseCandidate/hooks/useCreateReleaseCandidate.test.tsx @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { renderHook, act } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; +import { renderHook, act } from '@testing-library/react'; import { mockCalverProject, @@ -48,10 +47,9 @@ describe('useCreateReleaseCandidate', () => { ); await act(async () => { - await waitFor(() => result.current.run()); + await result.current.run(); }); - expect(result.error).toEqual(undefined); expect(result.current.responseSteps).toHaveLength(6); }); @@ -67,7 +65,7 @@ describe('useCreateReleaseCandidate', () => { ); await act(async () => { - await waitFor(() => result.current.run()); + await result.current.run(); }); expect(result.current.responseSteps).toHaveLength(7); diff --git a/plugins/git-release-manager/src/features/Features.test.tsx b/plugins/git-release-manager/src/features/Features.test.tsx index f3a70c2bda..abde878648 100644 --- a/plugins/git-release-manager/src/features/Features.test.tsx +++ b/plugins/git-release-manager/src/features/Features.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { render, act, waitFor } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import { Features } from './Features'; import { mockCalverProject } from '../test-helpers/test-helpers'; @@ -49,9 +49,7 @@ describe('Features', () => { />, ); - await act(async () => { - await waitFor(() => getByTestId(TEST_IDS.info.info)); - }); + await waitFor(() => getByTestId(TEST_IDS.info.info)); expect(getByTestId(TEST_IDS.info.info)).toMatchInlineSnapshot(`
{ ); await act(async () => { - await waitFor(() => result.current.run(mockSelectedPatchCommit)); + await result.current.run(mockSelectedPatchCommit); }); - expect(result.error).toEqual(undefined); expect(result.current.responseSteps).toHaveLength(18); }); @@ -69,10 +67,9 @@ describe('patch', () => { ); await act(async () => { - await waitFor(() => result.current.run(mockSelectedPatchCommit)); + await result.current.run(mockSelectedPatchCommit); }); - expect(result.error).toEqual(undefined); expect(result.current.responseSteps).toHaveLength(19); expect(result.current).toMatchInlineSnapshot(` { diff --git a/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts b/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts index f4e0fcb081..1b1bb54df0 100644 --- a/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts +++ b/plugins/git-release-manager/src/features/PromoteRc/hooks/usePromoteRc.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { renderHook, act } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; - +import { renderHook, act } from '@testing-library/react'; import { mockCalverProject, mockReleaseCandidateCalver, @@ -50,10 +48,9 @@ describe('usePromoteRc', () => { ); await act(async () => { - await waitFor(() => result.current.run()); + await result.current.run(); }); - expect(result.error).toEqual(undefined); expect(result.current.responseSteps).toHaveLength(4); }); @@ -67,7 +64,7 @@ describe('usePromoteRc', () => { ); await act(async () => { - await waitFor(() => result.current.run()); + await result.current.run(); }); expect(result.current.responseSteps).toHaveLength(5); diff --git a/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts b/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts index 8e89add810..d1bf28bccb 100644 --- a/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts +++ b/plugins/git-release-manager/src/hooks/useGetGitBatchInfo.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { waitFor } from '@testing-library/react'; import { mockApiClient } from '../test-helpers/mock-api-client'; diff --git a/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts b/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts index 513c51758d..c406a353b2 100644 --- a/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts +++ b/plugins/git-release-manager/src/hooks/useResponseSteps.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useResponseSteps } from './useResponseSteps'; diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 9c57b8914b..f5e9f1bc4c 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-github-actions +## 0.6.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.6.6-next.2 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 446b7434c5..ec0d9a03db 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.6.6-next.2", + "version": "0.6.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,8 +52,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -63,7 +63,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx index 2d006b32c2..772a33c4fe 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx @@ -75,7 +75,7 @@ describe('', () => { }); const renderSubject = async (props: any = {}) => { - renderInTestApp( + await renderInTestApp( Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; import { GraphQLEndpoint } from '@backstage/plugin-graphiql'; import { PortableSchema } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) export function createEndpointExtension(options: { @@ -21,7 +20,12 @@ export function createEndpointExtension(options: { }): Extension; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + root: RouteRef; + }, + {} +>; export default _default; // @alpha (undocumented) diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 36e55b8c66..52cff1fdb7 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.55-next.2", + "version": "0.2.55", "publishConfig": { "access": "public" }, @@ -60,8 +60,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -71,7 +71,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/codemirror": "^5.0.0", "cross-fetch": "^3.1.5", diff --git a/plugins/graphiql/src/alpha.tsx b/plugins/graphiql/src/alpha.tsx index 0a27f6151b..58b6686daa 100644 --- a/plugins/graphiql/src/alpha.tsx +++ b/plugins/graphiql/src/alpha.tsx @@ -32,19 +32,15 @@ import { GraphQLEndpoint, GraphiQLIcon, } from '@backstage/plugin-graphiql'; -import { - createApiFactory, - createRouteRef, - IconComponent, -} from '@backstage/core-plugin-api'; - -const graphiqlRouteRef = createRouteRef({ id: 'plugin.graphiql.page' }); +import { createApiFactory, IconComponent } from '@backstage/core-plugin-api'; +import { graphiQLRouteRef } from './route-refs'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; /** @alpha */ export const GraphiqlPage = createPageExtension({ id: 'plugin.graphiql.page', defaultPath: '/graphiql', - routeRef: graphiqlRouteRef, + routeRef: convertLegacyRouteRef(graphiQLRouteRef), loader: () => import('./components').then(m => ), }); @@ -53,7 +49,7 @@ export const graphiqlPageSidebarItem = createNavItemExtension({ id: 'plugin.graphiql.nav.index', title: 'GraphiQL', icon: GraphiQLIcon as IconComponent, - routeRef: graphiqlRouteRef, + routeRef: convertLegacyRouteRef(graphiQLRouteRef), }); /** @internal */ @@ -125,4 +121,7 @@ export default createPlugin({ gitlabGraphiQLBrowseExtension, graphiqlPageSidebarItem, ], + routes: { + root: convertLegacyRouteRef(graphiQLRouteRef), + }, }); diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index 182d8840b0..dcf6b8f243 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-graphql-backend +## 0.2.0 + +### Minor Changes + +- 9def1e95ab: This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-graphql@0.4.0 + - @backstage/config@1.1.1 + ## 0.1.44-next.2 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index d07cd29a3d..c0b89ef0ce 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-backend", "description": "Deprecated, consider using @frontside/backstage-plugin-graphql-backend instead", - "version": "0.1.44-next.2", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index 85b1cf7dae..20130f64dd 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-graphql-voyager +## 0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.1.8-next.2 ### Patch Changes diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 7d8a07c2ac..51b7020154 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.8-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,8 +41,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -52,7 +52,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 63f73232fe..8124f70308 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-home-react +## 0.1.4 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 9708367ae4..5c56caf71b 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home-react", "description": "A Backstage plugin that contains react components helps you build a home page", - "version": "0.1.4-next.2", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,8 +42,8 @@ "@types/react": "^16.13.1 || ^17.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -53,7 +53,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/react-grid-layout": "^1.3.2", "cross-fetch": "^3.1.5", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 1f0a83c1c9..cd27145f6c 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-home +## 0.5.9 + +### Patch Changes + +- f997f771da: Adds Top/Recently Visited components to homepage +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.5.9-next.2 ### Patch Changes diff --git a/plugins/home/alpha-api-report.md b/plugins/home/alpha-api-report.md new file mode 100644 index 0000000000..35ce0bb86c --- /dev/null +++ b/plugins/home/alpha-api-report.md @@ -0,0 +1,17 @@ +## API Report File for "@backstage/plugin-home" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin<{}, {}>; +export default _default; + +// @alpha (undocumented) +export const titleExtensionDataRef: ConfigurableExtensionDataRef; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/home/package.json b/plugins/home/package.json index 017f78be57..edb7e6542d 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,14 +1,12 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.5.9-next.2", + "version": "0.5.9", "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" + "access": "public" }, "backstage": { "role": "frontend-plugin" @@ -23,6 +21,21 @@ "backstage", "homepage" ], + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } + }, "sideEffects": false, "scripts": { "build": "backstage-cli package build", @@ -39,6 +52,7 @@ "@backstage/core-app-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-home-react": "workspace:^", "@backstage/theme": "workspace:^", @@ -46,8 +60,8 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@rjsf/core-v5": "npm:@rjsf/core@5.13.0", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0", + "@rjsf/core": "5.13.0", + "@rjsf/material-ui": "5.13.0", "@rjsf/utils": "5.13.0", "@rjsf/validator-ajv8": "5.13.0", "@types/react": "^16.13.1 || ^17.0.0", @@ -59,8 +73,8 @@ "zod": "^3.21.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -69,8 +83,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/react-grid-layout": "^1.3.2", "msw": "^1.0.0" diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx new file mode 100644 index 0000000000..c8308f7c0a --- /dev/null +++ b/plugins/home/src/alpha.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +import { + coreExtensionData, + createExtensionDataRef, + createExtensionInput, + createPageExtension, + createPlugin, + createRouteRef, +} from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); + +/** + * @alpha + */ +export const titleExtensionDataRef = createExtensionDataRef('title'); + +const HomepageCompositionRootExtension = createPageExtension({ + id: 'home', + defaultPath: '/home', + routeRef: rootRouteRef, + inputs: { + props: createExtensionInput( + { + children: coreExtensionData.reactElement.optional(), + title: titleExtensionDataRef.optional(), + }, + + { + singleton: true, + optional: true, + }, + ), + }, + loader: ({ inputs }) => + import('./components/').then(m => ( + + )), +}); + +/** + * @alpha + */ +export default createPlugin({ + id: 'home', + extensions: [HomepageCompositionRootExtension], +}); diff --git a/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx b/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx index 2c3a1d9ab9..aec4b3dcf2 100644 --- a/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx +++ b/plugins/home/src/components/CustomHomepage/WidgetSettingsOverlay.tsx @@ -27,10 +27,11 @@ import SettingsIcon from '@material-ui/icons/Settings'; import DeleteIcon from '@material-ui/icons/Delete'; import React from 'react'; import { Widget } from './types'; -import { withTheme } from '@rjsf/core-v5'; +import { withTheme } from '@rjsf/core'; +import { Theme as MuiTheme } from '@rjsf/material-ui'; import validator from '@rjsf/validator-ajv8'; -const Form = withTheme(require('@rjsf/material-ui-v5').Theme); +const Form = withTheme(MuiTheme); const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 1960cff7b1..8e07fa787f 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-ilert +## 0.2.14 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- 9c9a9100b0: Internal refactor to avoid using the deprecated `.icon.svg` extension. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.2.14-next.2 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index da4161cc91..42d6a33ab1 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.14-next.2", + "version": "0.2.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,7 +58,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index e93668b500..27af4041da 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-jenkins-backend +## 0.3.0 + +### Minor Changes + +- 411896faf9: Added JobRunTable Component. + Added new Route and extended Api to get buildJobs. + Actions column has a new icon button, clicking on which takes us to page where we + can see all the job runs. + +### Patch Changes + +- 930ac236d8: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-jenkins-common@0.1.20 + - @backstage/plugin-permission-common@0.7.9 + ## 0.2.9-next.2 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 02c9c8bf21..740ef8710a 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.2.9-next.2", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index 816bc32b02..f91ea5074c 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-jenkins-common +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + ## 0.1.20-next.0 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index bf9dd8f344..0856d27ad0 100644 --- a/plugins/jenkins-common/package.json +++ b/plugins/jenkins-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins-common", - "version": "0.1.20-next.0", + "version": "0.1.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 9874ab8bfc..5878d16f47 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-jenkins +## 0.9.0 + +### Minor Changes + +- 411896faf9: Added JobRunTable Component. + Added new Route and extended Api to get buildJobs. + Actions column has a new icon button, clicking on which takes us to page where we + can see all the job runs. + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 1a05cf34f6: Extend EntityJenkinsContent to receive columns as prop +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-jenkins-common@0.1.20 + ## 0.8.7-next.2 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 7d4e60f19b..8be847f002 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.8.7-next.2", + "version": "0.9.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,8 +49,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -60,7 +60,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/testing-library__jest-dom": "^5.9.1", "cross-fetch": "^3.1.5", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 79183bce97..573be0062f 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 64aa68be19..68060f254c 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index d3f967dc0c..d24a6db0e2 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kafka +## 0.3.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.3.25-next.2 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 7b03465504..1580caa124 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.25-next.2", + "version": "0.3.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -55,8 +55,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "jest-when": "^3.1.0", "msw": "^1.0.0" diff --git a/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsForEntity.test.tsx b/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsForEntity.test.tsx index e2393d0598..026331c7d9 100644 --- a/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsForEntity.test.tsx +++ b/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsForEntity.test.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React, { PropsWithChildren } from 'react'; import { useConsumerGroupsForEntity } from './useConsumerGroupsForEntity'; import { TestApiProvider } from '@backstage/test-utils'; @@ -165,12 +165,8 @@ describe('useConsumerGroupOffsets', () => { lifecycle: 'development', }, }; - const { result } = subject(); - expect(() => result.current).toThrow(); - expect(result.error).toStrictEqual( - new Error( - `Failed to parse kafka consumer group annotation: got "dev/another,consumer"`, - ), + expect(() => subject()).toThrow( + `Failed to parse kafka consumer group annotation: got "dev/another,consumer"`, ); }); }); diff --git a/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsOffsetsForEntity.test.tsx b/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsOffsetsForEntity.test.tsx index 8a7f28d69b..2f3fc21f93 100644 --- a/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsOffsetsForEntity.test.tsx +++ b/plugins/kafka/src/components/ConsumerGroupOffsets/useConsumerGroupsOffsetsForEntity.test.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { when } from 'jest-when'; import React, { PropsWithChildren } from 'react'; import { @@ -96,27 +96,28 @@ describe('useConsumerGroupOffsets', () => { .mockResolvedValue(consumerGroupOffsets); when(mockKafkaDashboardApi.getDashboardUrl).mockReturnValue({}); - const { result, waitForNextUpdate } = subject(); - await waitForNextUpdate(); - const [tableProps] = result.current; + const { result } = subject(); - expect(tableProps.consumerGroupsTopics).toStrictEqual([ - { - clusterId: 'prod', - consumerGroup: consumerGroupOffsets.consumerId, - dashboardUrl: undefined, - topics: consumerGroupOffsets.offsets, - }, - ]); + await waitFor(() => { + expect(result.current[0].consumerGroupsTopics).toStrictEqual([ + { + clusterId: 'prod', + consumerGroup: consumerGroupOffsets.consumerId, + dashboardUrl: undefined, + topics: consumerGroupOffsets.offsets, + }, + ]); + }); }); it('posts an error to the error api', async () => { const error = new Error('error!'); mockKafkaApi.getConsumerGroupOffsets.mockRejectedValueOnce(error); - const { waitForNextUpdate } = subject(); - await waitForNextUpdate(); + subject(); - expect(mockErrorApi.post).toHaveBeenCalledWith(error); + await waitFor(() => { + expect(mockErrorApi.post).toHaveBeenCalledWith(error); + }); }); }); diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 1f3532632b..138b47b345 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-kubernetes-backend +## 0.13.0 + +### Minor Changes + +- ae943c3bb1: **BREAKING** Allow passing undefined `labelSelector` to `KubernetesFetcher` + + `KubernetesFetch` no longer auto-adds `labelSelector` when empty string was passed. + This is only applicable if you have custom ObjectProvider implementation, as build-in `KubernetesFanOutHandler` already does this + +### Patch Changes + +- cbb0e3c3f4: A new plugin has been introduced to house the extension points for Kubernetes backend plugin; at the moment only the `KubernetesObjectsProviderExtensionPoint` is present. The `kubernetes-backend` plugin was modified to use this new extension point. +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-node@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.12.3-next.2 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 32bc958286..cc0b5016e4 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.12.3-next.2", + "version": "0.13.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 9e0961f3f7..fbb762282e 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-react@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.0.1-next.0 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 8d0509b448..1949941d47 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-cluster", "description": "A Backstage plugin that shows details of Kubernetes clusters", - "version": "0.0.1-next.0", + "version": "0.0.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,8 +57,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -68,8 +68,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "msw": "^1.0.0" diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index c95c8afa61..4db1264d6b 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-kubernetes-common +## 0.7.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.7.0-next.1 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 3a68e07495..9fe232e68f 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.7.0-next.1", + "version": "0.7.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 6aa0b7be7f..cc128fcd7f 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-kubernetes-node +## 0.1.0 + +### Minor Changes + +- cbb0e3c3f4: A new plugin has been introduced to house the extension points for Kubernetes backend plugin; at the moment only the `KubernetesObjectsProviderExtensionPoint` is present. The `kubernetes-backend` plugin was modified to use this new extension point. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/backend-plugin-api@0.6.6 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 433fadf2f2..6f63ba1364 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-node", "description": "Node.js library for the kubernetes 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/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index bd2c4759de..13c23a75bf 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-react +## 0.1.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 4262e12921: Handle mixed decimals and bigint when calculating k8s resource usage +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- 5dac12e435: The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/types@1.1.1 + ## 0.1.0-next.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 2463f0bb62..03f647cfb2 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-react", "description": "Web library for the kubernetes-react plugin", - "version": "0.1.0-next.1", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,15 +48,14 @@ "xterm-addon-fit": "^0.8.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0" + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "^14.0.0", "jest-websocket-mock": "^2.5.0", "msw": "^1.3.1" }, diff --git a/plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx b/plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx index 15da221f64..f98e4f5e6e 100644 --- a/plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx +++ b/plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { useApi } from '@backstage/core-plugin-api'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useEvents } from './useEvents'; import { DateTime } from 'luxon'; @@ -49,7 +49,7 @@ describe('Events', () => { mockGetEventsByInvolvedObjectName.mockResolvedValue(response), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useEvents({ involvedObjectName: 'some-objecgt', namespace: 'some-namespace', @@ -59,7 +59,9 @@ describe('Events', () => { expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.loading).toEqual(false); + }); expect(result.current.error).toBeUndefined(); expect(result.current.loading).toEqual(false); diff --git a/plugins/kubernetes-react/src/hooks/useCustomResources.test.ts b/plugins/kubernetes-react/src/hooks/useCustomResources.test.ts index abd8fc392c..40ab619180 100644 --- a/plugins/kubernetes-react/src/hooks/useCustomResources.test.ts +++ b/plugins/kubernetes-react/src/hooks/useCustomResources.test.ts @@ -16,7 +16,7 @@ import { useCustomResources } from './useCustomResources'; import { Entity } from '@backstage/catalog-model'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useApi } from '@backstage/core-plugin-api'; import { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; import { generateAuth } from './auth'; @@ -97,17 +97,17 @@ describe('useCustomResources', () => { getCustomObjectsByEntity: mockGetCustomObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers), ); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); + }); expectMocksCalledCorrectly(); }); @@ -117,20 +117,17 @@ describe('useCustomResources', () => { getCustomObjectsByEntity: mockGetCustomObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers, 100), ); - await waitForNextUpdate(); - expect(result.current.error).toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); - - expectMocksCalledCorrectly(2); + expectMocksCalledCorrectly(2); + }); }); it('should return error when getObjectsByEntity throws', async () => { mockGenerateAuth.mockResolvedValue(entityWithAuthToken.auth); @@ -139,17 +136,17 @@ describe('useCustomResources', () => { message: 'some error', }), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers), ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('some error'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); - expect(result.current.error).toBe('some error'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - expectMocksCalledCorrectly(); + expectMocksCalledCorrectly(); + }); }); describe('when retrying', () => { @@ -162,21 +159,21 @@ describe('useCustomResources', () => { mockGetCustomObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers, 100), ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('generateAuth failed'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); - expect(result.current.error).toBe('generateAuth failed'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); }); it('should reset error after getCustomObjectsByEntity has failed and then succeeded', async () => { @@ -186,21 +183,21 @@ describe('useCustomResources', () => { .mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers, 100), ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('failed to fetch'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); - expect(result.current.error).toBe('failed to fetch'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); }); it('should reset data after generateAuth succeeded then failed', async () => { @@ -212,21 +209,21 @@ describe('useCustomResources', () => { mockGetCustomObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers, 100), ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBe('generateAuth failed'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBe('generateAuth failed'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); }); it('should reset data after getCustomObjectsByEntity succeeded then failed', async () => { @@ -236,21 +233,21 @@ describe('useCustomResources', () => { .mockRejectedValue({ message: 'failed to fetch' }), }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useCustomResources(entity, customResourceMatchers, 100), ); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBe('failed to fetch'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBe('failed to fetch'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); }); }); }); diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts index 1772e0d4f2..93bfb6dd4d 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { useApi } from '@backstage/core-plugin-api'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useIsPodExecTerminalSupported } from './useIsPodExecTerminalSupported'; @@ -68,15 +68,14 @@ describe('useIsClusterShellEnabled', () => { async ({ testClusters, returnValue }) => { clusters = testClusters; - const { result, waitForNextUpdate } = renderHook(() => - useIsPodExecTerminalSupported(), - ); + const { result } = renderHook(() => useIsPodExecTerminalSupported()); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.loading).toEqual(false); + }); - expect(result.current.loading).toEqual(false); expect(result.current.value).toBe(returnValue); }, ); diff --git a/plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts b/plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts index 5c4db4db14..e88432f980 100644 --- a/plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts +++ b/plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts @@ -16,7 +16,7 @@ import { useKubernetesObjects } from './useKubernetesObjects'; import { Entity } from '@backstage/catalog-model'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useApi } from '@backstage/core-plugin-api'; import { generateAuth } from './auth'; @@ -87,19 +87,17 @@ describe('useKubernetesObjects', () => { getObjectsByEntity: mockGetObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity), - ); + const { result } = renderHook(() => useKubernetesObjects(entity)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); - - expectMocksCalledCorrectly(); + expectMocksCalledCorrectly(); + }); }); it('should update on an interval', async () => { mockGenerateAuth.mockResolvedValue(entityWithAuthToken.auth); @@ -107,20 +105,17 @@ describe('useKubernetesObjects', () => { getObjectsByEntity: mockGetObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity, 100), - ); - - await waitForNextUpdate(); - expect(result.current.error).toBeUndefined(); - - await waitForNextUpdate(); + const { result } = renderHook(() => useKubernetesObjects(entity, 100)); expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); - expectMocksCalledCorrectly(2); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toStrictEqual(mockResponse); + + expectMocksCalledCorrectly(2); + }); }); it('should return error when getObjectsByEntity throws', async () => { mockGenerateAuth.mockResolvedValue(entityWithAuthToken.auth); @@ -129,17 +124,15 @@ describe('useKubernetesObjects', () => { message: 'some error', }), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity), - ); + const { result } = renderHook(() => useKubernetesObjects(entity)); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('some error'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); - expect(result.current.error).toBe('some error'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - expectMocksCalledCorrectly(); + expectMocksCalledCorrectly(); + }); }); describe('when retrying', () => { @@ -152,21 +145,19 @@ describe('useKubernetesObjects', () => { mockGetObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity, 100), - ); + const { result } = renderHook(() => useKubernetesObjects(entity, 100)); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('generateAuth failed'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); - expect(result.current.error).toBe('generateAuth failed'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); }); it('should reset error after getObjectsByEntity has failed and then succeeded', async () => { @@ -176,21 +167,19 @@ describe('useKubernetesObjects', () => { .mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity, 100), - ); + const { result } = renderHook(() => useKubernetesObjects(entity, 100)); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBe('failed to fetch'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); - expect(result.current.error).toBe('failed to fetch'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); }); it('should reset data after generateAuth succeeded then failed', async () => { @@ -202,21 +191,19 @@ describe('useKubernetesObjects', () => { mockGetObjectsByEntity.mockResolvedValue(mockResponse), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity, 100), - ); + const { result } = renderHook(() => useKubernetesObjects(entity, 100)); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBe('generateAuth failed'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBe('generateAuth failed'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); }); it('should reset data after getObjectsByEntity succeeded then failed', async () => { @@ -226,21 +213,19 @@ describe('useKubernetesObjects', () => { .mockRejectedValue({ message: 'failed to fetch' }), }); - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesObjects(entity, 100), - ); + const { result } = renderHook(() => useKubernetesObjects(entity, 100)); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.error).toBeUndefined(); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).not.toBeUndefined(); + }); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).not.toBeUndefined(); - - await waitForNextUpdate(); - - expect(result.current.error).toBe('failed to fetch'); - expect(result.current.loading).toEqual(false); - expect(result.current.kubernetesObjects).toBeUndefined(); + await waitFor(() => { + expect(result.current.error).toBe('failed to fetch'); + expect(result.current.loading).toEqual(false); + expect(result.current.kubernetesObjects).toBeUndefined(); + }); }); }); }); diff --git a/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx b/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx index 4d817e838d..f8312eac4e 100644 --- a/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx +++ b/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { DetectedErrorsContext, useMatchingErrors } from './useMatchingErrors'; import { DetectedError, diff --git a/plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx b/plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx index be74448abd..45c53e822d 100644 --- a/plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx +++ b/plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { PodMetricsContext, usePodMetrics } from './usePodMetrics'; import { ClientPodStatus } from '@backstage/plugin-kubernetes-common'; diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 58016d750a..e208c83b06 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-kubernetes +## 0.11.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- 9101c0d1b6: Updated dependency `@kubernetes/client-node` to `0.19.0`. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- b0aca1a798: Updated dependency `xterm-addon-attach` to `^0.9.0`. + Updated dependency `xterm-addon-fit` to `^0.8.0`. +- 95518765ee: Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-kubernetes-react@0.1.0 + - @backstage/plugin-kubernetes-common@0.7.0 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.11.0-next.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 6075687478..ed2dfd35ec 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.11.0-next.2", + "version": "0.11.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,8 +62,8 @@ "xterm-addon-fit": "^0.8.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -73,8 +73,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "jest-websocket-mock": "^2.4.1", "msw": "^1.0.0" diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index ae3bc3ec7b..76b12fb1f4 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-lighthouse-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 9f7c582060..e5306695cc 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse-common/CHANGELOG.md b/plugins/lighthouse-common/CHANGELOG.md index 16133e9d52..ded0273147 100644 --- a/plugins/lighthouse-common/CHANGELOG.md +++ b/plugins/lighthouse-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-lighthouse-common +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.1 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/lighthouse-common/package.json b/plugins/lighthouse-common/package.json index e3cab60d5e..e03436fd88 100644 --- a/plugins/lighthouse-common/package.json +++ b/plugins/lighthouse-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-common", "description": "Common functionalities for lighthouse, to be shared between lighthouse and lighthouse-backend plugin", - "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/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index a462393423..0b9130363f 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-lighthouse +## 0.4.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.4.10-next.2 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 25735b9a31..c039ae6b30 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.4.10-next.2", + "version": "0.4.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,8 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx b/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx index 199ede3049..69acd34dc3 100644 --- a/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx +++ b/plugins/lighthouse/src/hooks/useWebsiteForEntity.test.tsx @@ -15,7 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import React, { PropsWithChildren } from 'react'; import { WebsiteListResponse } from '@backstage/plugin-lighthouse-common'; import { lighthouseApiRef } from '../api'; @@ -77,9 +77,10 @@ describe('useWebsiteForEntity', () => { }); it('returns the lighthouse information for the website url in annotations', async () => { - const { result, waitForNextUpdate } = subject(); - await waitForNextUpdate(); - expect(result.current?.value).toBe(website); + const { result } = subject(); + await waitFor(() => { + expect(result.current?.value).toBe(website); + }); }); describe('where there is an error', () => { @@ -92,10 +93,11 @@ describe('useWebsiteForEntity', () => { }); it('posts the error to the error api and returns the error to the caller', async () => { - const { result, waitForNextUpdate } = subject(); - await waitForNextUpdate(); - expect(result.current?.error).toBe(error); - expect(mockErrorApi.post).toHaveBeenCalledWith(error); + const { result } = subject(); + await waitFor(() => { + expect(result.current?.error).toBe(error); + expect(mockErrorApi.post).toHaveBeenCalledWith(error); + }); }); }); @@ -109,10 +111,11 @@ describe('useWebsiteForEntity', () => { }); it('does not post the error to the error api and returns the error to the caller', async () => { - const { result, waitForNextUpdate } = subject(); - await waitForNextUpdate(); - expect(result.current?.error).toBe(error); - expect(mockErrorApi.post).not.toHaveBeenCalledWith(error); + const { result } = subject(); + await waitFor(() => { + expect(result.current?.error).toBe(error); + expect(mockErrorApi.post).not.toHaveBeenCalledWith(error); + }); }); }); }); diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index ccdcf24842..74a4eb35a6 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-linguist-backend +## 0.5.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.5.3-next.2 ### Patch Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index 954eb5c634..78aa0868d4 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.5.3-next.2", + "version": "0.5.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist-backend/src/service/standaloneServer.ts b/plugins/linguist-backend/src/service/standaloneServer.ts index 61f75d4827..518efed6a0 100644 --- a/plugins/linguist-backend/src/service/standaloneServer.ts +++ b/plugins/linguist-backend/src/service/standaloneServer.ts @@ -19,14 +19,14 @@ import { loadBackendConfig, HostDiscovery, UrlReaders, - useHotMemoize, ServerTokenManager, + DatabaseManager, } from '@backstage/backend-common'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; -import knexFactory from 'knex'; import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { ConfigReader } from '@backstage/config'; export interface ServerOptions { port: number; @@ -39,19 +39,14 @@ export async function startStandaloneServer( ): Promise { const logger = options.logger.child({ service: 'linguist-backend' }); const config = await loadBackendConfig({ logger, argv: process.argv }); - const db = useHotMemoize(module, () => { - const knex = knexFactory({ - client: 'sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - - knex.client.pool.on('createSuccess', (_eventId: any, resource: any) => { - resource.run('PRAGMA foreign_keys = ON', () => {}); - }); - - return knex; - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('linguist'); const schedule: TaskScheduleDefinition = { frequency: { minutes: 2 }, @@ -63,7 +58,7 @@ export async function startStandaloneServer( const router = await createRouter( { schedule: schedule, age: { days: 30 }, useSourceLocation: false }, { - database: { getClient: async () => db }, + database, discovery: HostDiscovery.fromConfig(config), reader: UrlReaders.default({ logger, config }), logger, diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index 003e1b6d80..85db830a62 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-linguist +## 0.1.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.1.10-next.2 ### Patch Changes diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index b3f3fedafe..3d101548a2 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.10-next.2", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "slugify": "^1.6.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index fc3a2c86b1..9e8f04b435 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-microsoft-calendar +## 0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.8-next.2 ### Patch Changes diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index 610940977c..57c4a75c39 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.8-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -65,8 +65,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -76,7 +76,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 8b9e3b4555..1c1a8bc5bf 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-newrelic-dashboard +## 0.3.0 + +### Minor Changes + +- d7eba6cab4: Changes in `newrelic-dashboard` plugin: + + - Make DashboardSnapshotList component public + - Settle discrepancies in the exported API + - Deprecate DashboardSnapshotComponent + +- e605ea4906: Add storybook for newrelic-dashboard plugin. + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 61d55942ae: Fix the styles for NewRelicDashboard, add more responsiveness +- 5194a51a1c: Fixed React Warning: "Each child in a list should have a unique 'key' prop" during the rendering of `EntityNewRelicDashboardCard` +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.3.0-next.2 ### Minor Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index d4d40c8e26..15f25d6cc7 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.3.0-next.2", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,8 +41,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 5274857950..65d2aad766 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-newrelic +## 0.3.41 + +### Patch Changes + +- ce50a15506: Fixed sorting and searching in the NewRelic table. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.3.41-next.2 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 1499839493..c4da950dee 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.41-next.2", + "version": "0.3.41", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -57,7 +57,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/parse-link-header": "^2.0.1", "cross-fetch": "^3.1.5", diff --git a/plugins/nomad-backend/CHANGELOG.md b/plugins/nomad-backend/CHANGELOG.md index f5ceaf5b9e..b5661c4b40 100644 --- a/plugins/nomad-backend/CHANGELOG.md +++ b/plugins/nomad-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-nomad-backend +## 0.1.8 + +### Patch Changes + +- 6822918c50: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.1.8-next.2 ### Patch Changes diff --git a/plugins/nomad-backend/package.json b/plugins/nomad-backend/package.json index caff96aa11..60ba974467 100644 --- a/plugins/nomad-backend/package.json +++ b/plugins/nomad-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad-backend", - "version": "0.1.8-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad/CHANGELOG.md b/plugins/nomad/CHANGELOG.md index e16f5ea02c..b6dff83c44 100644 --- a/plugins/nomad/CHANGELOG.md +++ b/plugins/nomad/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-nomad +## 0.1.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json index a500250507..617c8e2c5a 100644 --- a/plugins/nomad/package.json +++ b/plugins/nomad/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -53,7 +53,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 9ac914a653..64b61be538 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-octopus-deploy +## 0.2.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.2.7-next.2 ### Patch Changes diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index fd375d59f5..3da25dc2c3 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.2.7-next.2", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,8 +41,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -52,7 +52,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/opencost/CHANGELOG.md b/plugins/opencost/CHANGELOG.md index 24625e7f2d..b20b34b9c4 100644 --- a/plugins/opencost/CHANGELOG.md +++ b/plugins/opencost/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-opencost +## 0.2.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- 777b9a16a4: Fix for broken image reference. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.2.1-next.2 ### Patch Changes diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json index a2f8aa2ed7..f751ed3ba5 100644 --- a/plugins/opencost/package.json +++ b/plugins/opencost/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-opencost", - "version": "0.2.1-next.2", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "*" }, "devDependencies": { @@ -49,7 +49,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 8f1a3bcaf0..1b39333288 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-org-react +## 0.1.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 1877d025fe..2097c7658a 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.14-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index ff34eae200..1faaf20dbb 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-org +## 0.6.15 + +### Patch Changes + +- dc5b6b971b: Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. + This allows the already existing recursive method to work properly when children of entity have children themselves. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.6.15-next.2 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 8289db0805..b9bf7f0c02 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.6.15-next.2", + "version": "0.6.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,8 +46,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,8 +61,7 @@ "@backstage/types": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index 587dc689e3..eac5a171ba 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -16,7 +16,7 @@ import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; import { useGetEntities } from './useGetEntities'; import { CatalogApi } from '@backstage/catalog-client'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { getEntityRelations } from '@backstage/plugin-catalog-react'; const givenParentGroup = 'team.squad1'; @@ -66,14 +66,14 @@ describe('useGetEntities', () => { describe('given aggregated relationsType', () => { const whenHookIsCalledWith = async (_entity: Entity) => { - const hook = renderHook( + const { result } = renderHook( ({ entity }) => useGetEntities(entity, 'aggregated'), { initialProps: { entity: _entity }, }, ); - await hook.waitForNextUpdate(); + await waitFor(() => expect(result.current.loading).toBe(false)); }; beforeEach(() => { @@ -207,14 +207,14 @@ describe('useGetEntities', () => { describe('given direct relationsType', () => { const whenHookIsCalledWith = async (_entity: Entity) => { - const hook = renderHook( + const { result } = renderHook( ({ entity }) => useGetEntities(entity, 'direct'), { initialProps: { entity: _entity }, }, ); - await hook.waitForNextUpdate(); + await waitFor(() => expect(result.current.loading).toBe(false)); }; it('given group entity should return directly owned entities', async () => { diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index 92721d7cc8..457905f993 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-pagerduty +## 0.6.6 + +### Patch Changes + +- b9ce306814: Minor fix to avoid usage of deprecated prop +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + ## 0.6.6-next.2 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 92337a3ae5..0130724cfa 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.6.6-next.2", + "version": "0.6.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,8 +50,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index d0653d6836..03f74fb422 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-periskop-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index 91a7ee4ebd..1ef6c62431 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.2.3-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 32cccbb745..26c40e8b97 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-periskop +## 0.1.23 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.23-next.2 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 2bf9bab4b8..9ec13e9ce1 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.23-next.2", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,8 +43,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -54,7 +54,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/luxon": "^3.0.0", "msw": "^1.0.0" diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index ad8d765829..63e6e54cc2 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-permission-common@0.7.9 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 0dc2e20689..6ae8cc459d 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", "description": "Allow all policy backend module for the permission plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 679e235598..a26b60baaf 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-backend +## 0.5.29 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.5.29-next.2 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index a3bd75e6db..f222d51451 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.29-next.2", + "version": "0.5.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index 56af3e310e..c017cd00fc 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-common +## 0.7.9 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.7.9-next.0 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index c08d962e4a..0c8292a24d 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.9-next.0", + "version": "0.7.9", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 05af5694ca..222399e878 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-node +## 0.7.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.7.17-next.2 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 6aee34ad50..4ed3ceb7ae 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.17-next.2", + "version": "0.7.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 6db19085fb..493ee440b6 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-react +## 0.4.16 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 0.4.16-next.1 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index b21d3fc6fb..9a9650e762 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.16-next.1", + "version": "0.4.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,15 +41,15 @@ "swr": "^2.0.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3" + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 503f4a1796..2fa8f35268 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist-backend +## 0.3.10 + +### Patch Changes + +- 9e46f5ff49: Added support to the playlist plugin for the new backend +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-playlist-common@0.1.11 + ## 0.3.10-next.2 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 193ecd3fe0..d5b6a5bdaf 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.3.10-next.2", + "version": "0.3.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-backend/src/service/standaloneServer.ts b/plugins/playlist-backend/src/service/standaloneServer.ts index 02a375229c..26a601822a 100644 --- a/plugins/playlist-backend/src/service/standaloneServer.ts +++ b/plugins/playlist-backend/src/service/standaloneServer.ts @@ -20,7 +20,6 @@ import { loadBackendConfig, ServerTokenManager, HostDiscovery, - useHotMemoize, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; @@ -42,16 +41,14 @@ export async function startStandaloneServer( const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = HostDiscovery.fromConfig(config); - const database = useHotMemoize(module, () => { - const manager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { client: 'better-sqlite3', connection: ':memory:' }, - }, - }), - ); - return manager.forPlugin('playlist'); - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('playlist'); const identity = DefaultIdentityClient.create({ discovery, diff --git a/plugins/playlist-common/CHANGELOG.md b/plugins/playlist-common/CHANGELOG.md index cc3cd85cb8..5916ed33e8 100644 --- a/plugins/playlist-common/CHANGELOG.md +++ b/plugins/playlist-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-playlist-common +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.9 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/playlist-common/package.json b/plugins/playlist-common/package.json index 08b0b8bb32..e08afb8392 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.11-next.0", + "version": "0.1.11", "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 9682635f51..16c0f02912 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-playlist +## 0.1.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 65498193e8: Updated Playlist read me with additional screenshots +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/theme@0.4.3 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-playlist-common@0.1.11 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index a479c2946d..de53e9fafe 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.17-next.2", + "version": "0.1.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,8 +51,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -63,8 +63,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0", "swr": "^2.0.0" diff --git a/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx index ef8ca57b69..c21283bcce 100644 --- a/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx +++ b/plugins/playlist/src/components/CreatePlaylistButton/CreatePlaylistButton.test.tsx @@ -22,8 +22,7 @@ import { } from '@backstage/plugin-permission-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { Button } from '@material-ui/core'; -import { fireEvent, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, waitFor, act } from '@testing-library/react'; import React from 'react'; import { SWRConfig } from 'swr'; import { PlaylistApi, playlistApiRef } from '../../api'; @@ -111,6 +110,8 @@ describe('', () => { act(() => { fireEvent.click(rendered.getByRole('button')); + }); + act(() => { fireEvent.click(rendered.getByTestId('mock-playlist-edit-dialog')); }); @@ -129,6 +130,8 @@ describe('', () => { act(() => { fireEvent.click(rendered.getByRole('button')); + }); + act(() => { fireEvent.click(rendered.getByTestId('mock-playlist-edit-dialog')); }); diff --git a/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx b/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx index 828485bc3d..68e00b6b96 100644 --- a/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx +++ b/plugins/playlist/src/components/EntityPlaylistDialog/EntityPlaylistDialog.test.tsx @@ -24,8 +24,7 @@ import { permissionApiRef, } from '@backstage/plugin-permission-react'; import { Button } from '@material-ui/core'; -import { fireEvent, getByRole, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, getByRole, waitFor, act } from '@testing-library/react'; import React from 'react'; import { SWRConfig } from 'swr'; import { PlaylistApi, playlistApiRef } from '../../api'; diff --git a/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx index b01b5acbf2..eaf00cbde1 100644 --- a/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx +++ b/plugins/playlist/src/components/PlaylistEditDialog/PlaylistEditDialog.test.tsx @@ -16,8 +16,7 @@ import { IdentityApi, identityApiRef } from '@backstage/core-plugin-api'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { fireEvent, getByRole, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, getByRole, waitFor, act } from '@testing-library/react'; import { PlaylistApi, playlistApiRef } from '../../api'; import React from 'react'; @@ -79,7 +78,9 @@ describe('', () => { }, }, ); + }); + act(() => { fireEvent.input( getByRole( rendered.getByTestId('edit-dialog-description-input'), @@ -91,17 +92,25 @@ describe('', () => { }, }, ); + }); + act(() => { fireEvent.mouseDown( getByRole(rendered.getByTestId('edit-dialog-owner-select'), 'button'), ); + }); + act(() => { fireEvent.click(rendered.getByText('test-owner')); + }); + act(() => { fireEvent.click( getByRole(rendered.getByTestId('edit-dialog-public-option'), 'radio'), ); + }); + act(() => { fireEvent.click(rendered.getByTestId('edit-dialog-save-button')); }); diff --git a/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx index d1bdf1d46a..96ec5677e7 100644 --- a/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx +++ b/plugins/playlist/src/components/PlaylistPage/AddEntitiesDrawer.test.tsx @@ -21,8 +21,7 @@ import { } from '@backstage/plugin-catalog-react'; import { SearchApi, searchApiRef } from '@backstage/plugin-search-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { fireEvent, getByText } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, getByText, act } from '@testing-library/react'; import React from 'react'; import { AddEntitiesDrawer } from './AddEntitiesDrawer'; diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx index 21658ef36e..ba6f94e945 100644 --- a/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistEntitiesTable.test.tsx @@ -23,8 +23,7 @@ import { } from '@backstage/plugin-permission-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { Button } from '@material-ui/core'; -import { fireEvent, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, waitFor, act } from '@testing-library/react'; import React from 'react'; import { SWRConfig } from 'swr'; import { PlaylistApi, playlistApiRef } from '../../api'; diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistHeader.test.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistHeader.test.tsx index 4594a43a88..480ac038f2 100644 --- a/plugins/playlist/src/components/PlaylistPage/PlaylistHeader.test.tsx +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistHeader.test.tsx @@ -27,8 +27,7 @@ import { import { permissions, Playlist } from '@backstage/plugin-playlist-common'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { Button } from '@material-ui/core'; -import { fireEvent, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, waitFor, act } from '@testing-library/react'; import React from 'react'; import { SWRConfig } from 'swr'; import { PlaylistApi, playlistApiRef } from '../../api'; @@ -193,6 +192,8 @@ describe('PlaylistHeader', () => { act(() => { fireEvent.click(rendered.getByTestId('header-action-menu')); + }); + act(() => { fireEvent.click( rendered .getAllByTestId('header-action-item') @@ -225,11 +226,15 @@ describe('PlaylistHeader', () => { act(() => { fireEvent.click(rendered.getByTestId('header-action-menu')); + }); + act(() => { fireEvent.click( rendered .getAllByTestId('header-action-item') .find(e => e.innerHTML.includes('Delete Playlist'))!, ); + }); + act(() => { fireEvent.click(rendered.getByTestId('delete-playlist-dialog-button')); }); diff --git a/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx index 65d3d79be6..ef9b6d060b 100644 --- a/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx +++ b/plugins/playlist/src/components/PlaylistPage/PlaylistPage.test.tsx @@ -21,8 +21,7 @@ import { permissionApiRef, } from '@backstage/plugin-permission-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { fireEvent, getByText, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, getByText, waitFor, act } from '@testing-library/react'; import React from 'react'; import { SWRConfig } from 'swr'; @@ -110,8 +109,8 @@ describe('PlaylistPage', () => { act(() => { fireEvent.click(rendered.getByTestId('playlist-page-follow-button')); - testPlaylist.isFollowing = true; }); + testPlaylist.isFollowing = true; await waitFor(() => { expect(playlistApi.followPlaylist).toHaveBeenCalledWith('id1'); @@ -125,8 +124,8 @@ describe('PlaylistPage', () => { act(() => { fireEvent.click(rendered.getByTestId('playlist-page-follow-button')); - testPlaylist.isFollowing = false; }); + testPlaylist.isFollowing = false; await waitFor(() => { expect(playlistApi.unfollowPlaylist).toHaveBeenCalledWith('id1'); diff --git a/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx index 9317bfd4c1..6c86b7b34d 100644 --- a/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx +++ b/plugins/playlist/src/components/PlaylistSortPicker/PlaylistSortPicker.test.tsx @@ -14,8 +14,13 @@ * limitations under the License. */ -import { fireEvent, getByRole, render, waitFor } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { + fireEvent, + getByRole, + render, + waitFor, + act, +} from '@testing-library/react'; import React from 'react'; import { MockPlaylistListProvider } from '../../testUtils'; diff --git a/plugins/playlist/src/hooks/PlaylistListProvider.test.tsx b/plugins/playlist/src/hooks/PlaylistListProvider.test.tsx index 26e162ebf7..ce0d49802b 100644 --- a/plugins/playlist/src/hooks/PlaylistListProvider.test.tsx +++ b/plugins/playlist/src/hooks/PlaylistListProvider.test.tsx @@ -22,7 +22,7 @@ import { } from '@backstage/core-plugin-api'; import { Playlist } from '@backstage/plugin-playlist-common'; import { TestApiProvider } from '@backstage/test-utils'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router-dom'; @@ -114,23 +114,22 @@ describe('', () => { }); it('resolves backend filters', async () => { - const { result, waitForValueToChange } = renderHook( - () => usePlaylistList(), - { - wrapper, - }, - ); - await waitForValueToChange(() => result.current.backendPlaylists); - expect(result.current.backendPlaylists.length).toBe(2); - expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalled(); + const { result } = renderHook(() => usePlaylistList(), { + wrapper, + }); + await waitFor(() => { + expect(result.current.backendPlaylists.length).toBe(2); + expect(mockPlaylistApi.getAllPlaylists).toHaveBeenCalled(); + }); }); it('resolves frontend filters', async () => { - const { result, waitFor } = renderHook(() => usePlaylistList(), { + const { result } = renderHook(() => usePlaylistList(), { wrapper, }); - await waitFor(() => !!result.current.playlists.length); - expect(result.current.backendPlaylists.length).toBe(2); + await waitFor(() => { + expect(result.current.backendPlaylists.length).toBe(2); + }); act(() => result.current.updateFilters({ @@ -152,21 +151,21 @@ describe('', () => { const query = qs.stringify({ filters: { personal: 'all', owners: ['user:default/guest'] }, }); - const { result, waitFor } = renderHook(() => usePlaylistList(), { - wrapper, - initialProps: { - location: `/playlist?${query}`, - }, + const { result } = renderHook(() => usePlaylistList(), { + wrapper: ({ children }) => + wrapper({ location: `/playlist?${query}`, children }), }); - await waitFor(() => !!result.current.queryParameters); - expect(result.current.queryParameters).toEqual({ - personal: 'all', - owners: ['user:default/guest'], + + await waitFor(() => { + expect(result.current.queryParameters).toEqual({ + personal: 'all', + owners: ['user:default/guest'], + }); }); }); it('does not fetch when only frontend filters change', async () => { - const { result, waitFor } = renderHook(() => usePlaylistList(), { + const { result } = renderHook(() => usePlaylistList(), { wrapper, }); @@ -191,7 +190,7 @@ describe('', () => { }); it('applies custom sorting', async () => { - const { result, waitFor } = renderHook(() => usePlaylistList(), { + const { result } = renderHook(() => usePlaylistList(), { wrapper, }); @@ -216,7 +215,7 @@ describe('', () => { it('returns an error on playlistApi failure', async () => { mockPlaylistApi.getAllPlaylists = jest.fn().mockRejectedValue('error'); - const { result, waitFor } = renderHook(() => usePlaylistList(), { + const { result } = renderHook(() => usePlaylistList(), { wrapper, }); await waitFor(() => { diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index a4059a1828..6137545f06 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.4.3-next.2 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 28f8d3ea5f..adbfe9fce9 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.4.3-next.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/puppetdb/CHANGELOG.md b/plugins/puppetdb/CHANGELOG.md index 98680eed03..2d184e7a48 100644 --- a/plugins/puppetdb/CHANGELOG.md +++ b/plugins/puppetdb/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-puppetdb +## 0.1.8 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.8-next.2 ### Patch Changes diff --git a/plugins/puppetdb/package.json b/plugins/puppetdb/package.json index b493b78d71..89cd83fcde 100644 --- a/plugins/puppetdb/package.json +++ b/plugins/puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-puppetdb", "description": "Backstage plugin to visualize resource information and Puppet facts from PuppetDB.", - "version": "0.1.8-next.2", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,7 +58,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.1" }, diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index b6a0bb6a79..dd2df54811 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-rollbar-backend +## 0.1.51 + +### Patch Changes + +- 407f4284be: ensure rollbar token is hidden +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + ## 0.1.51-next.2 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index b58241b5e2..e5dbd3a997 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.51-next.2", + "version": "0.1.51", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index cc3f2e564d..46d27e8bad 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-rollbar +## 0.4.25 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.4.25-next.2 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 2444240a78..d82402c03e 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.25-next.2", + "version": "0.4.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,8 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 7344084491..2b931dd7da 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.7-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index dcdfc51f93..9d506d824b 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", - "version": "0.2.7-next.2", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 4373cf9a1a..9c68b53d40 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.30 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.30-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 68bbd40294..60d9f19a70 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.30-next.2", + "version": "0.2.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,11 +41,10 @@ "yn": "^4.0.0" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", - "@types/mock-fs": "^4.13.0", - "mock-fs": "^5.2.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.test.ts b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.test.ts index f944b6e598..af63ca0e48 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.test.ts +++ b/plugins/scaffolder-backend-module-cookiecutter/src/actions/fetch/cookiecutter.test.ts @@ -22,8 +22,7 @@ import { import { ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; import { ScmIntegrations } from '@backstage/integration'; -import mockFs from 'mock-fs'; -import os from 'os'; +import { createMockDirectory } from '@backstage/backend-test-utils'; import { PassThrough } from 'stream'; import { createFetchCookiecutterAction } from './cookiecutter'; import { join } from 'path'; @@ -47,6 +46,7 @@ jest.mock( ); describe('fetch:cookiecutter', () => { + const mockDir = createMockDirectory({ mockOsTmpDir: true }); const integrations = ScmIntegrations.fromConfig( new ConfigReader({ integrations: { @@ -58,7 +58,7 @@ describe('fetch:cookiecutter', () => { }), ); - const mockTmpDir = os.tmpdir(); + const mockTmpDir = mockDir.path; let mockContext: ActionContext<{ url: string; @@ -106,36 +106,25 @@ describe('fetch:cookiecutter', () => { output: jest.fn(), createTemporaryDirectory: jest.fn().mockResolvedValue(mockTmpDir), }; - - // mock the temp directory - mockFs({ [mockTmpDir]: {} }); - mockFs({ [`${join(mockTmpDir, 'template')}`]: {} }); + mockDir.setContent({ template: {} }); commandExists.mockResolvedValue(null); // Mock when run container is called it creates some new files in the mock filesystem containerRunner.runContainer.mockImplementation(async () => { - mockFs({ - [`${join(mockTmpDir, 'intermediate')}`]: { - 'testfile.json': '{}', - }, + mockDir.setContent({ + 'intermediate/testfile.json': '{}', }); }); // Mock when executeShellCommand is called it creates some new files in the mock filesystem executeShellCommand.mockImplementation(async () => { - mockFs({ - [`${join(mockTmpDir, 'intermediate')}`]: { - 'testfile.json': '{}', - }, + mockDir.setContent({ + 'intermediate/testfile.json': '{}', }); }); }); - afterEach(() => { - mockFs.restore(); - }); - it('should throw an error when copyWithoutRender is not an array', async () => { (mockContext.input as any).copyWithoutRender = 'not an array'; diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 950fd2edb5..2582ed3227 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.2.9 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + ## 0.2.9-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index aa57094af4..99c84ed4b9 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.2.9-next.2", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index e8ee3e7d35..70af7932b8 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.23 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.4.23-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index fad98d5216..0763690d7c 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.23-next.2", + "version": "0.4.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,13 +39,12 @@ "fs-extra": "^10.0.1" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", - "@types/mock-fs": "^4.13.0", "@types/node": "^18.17.8", - "jest-when": "^3.1.0", - "mock-fs": "^5.2.0" + "jest-when": "^3.1.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts index 2a93644f57..7548ddd21d 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts @@ -34,14 +34,14 @@ import { } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import mockFs from 'mock-fs'; -import os from 'os'; import { resolve as resolvePath } from 'path'; import { PassThrough } from 'stream'; import { createFetchRailsAction } from './index'; import { fetchContents } from '@backstage/plugin-scaffolder-node'; +import { createMockDirectory } from '@backstage/backend-test-utils'; describe('fetch:rails', () => { + const mockDir = createMockDirectory(); const integrations = ScmIntegrations.fromConfig( new ConfigReader({ integrations: { @@ -53,7 +53,7 @@ describe('fetch:rails', () => { }), ); - const mockTmpDir = os.tmpdir(); + const mockTmpDir = mockDir.path; const mockContext = { input: { url: 'https://rubyonrails.org/generator', @@ -90,14 +90,12 @@ describe('fetch:rails', () => { }); beforeEach(() => { - mockFs({ [`${mockContext.workspacePath}/result`]: {} }); + mockDir.setContent({ + result: '{}', + }); jest.clearAllMocks(); }); - afterEach(() => { - mockFs.restore(); - }); - it('should call fetchContents with the correct values', async () => { await action.handler(mockContext); diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 55de9576e5..9e0bd8734b 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.3 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 53613c14b6..ce1b8247f8 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.14-next.2", + "version": "0.1.14", "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 41522939e6..fa7774558a 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.2.27-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 8f17f30e7c..36b8c4e76b 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.27-next.2", + "version": "0.2.27", "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 f468e42f72..f2258517a6 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-scaffolder-backend +## 1.18.0 + +### Minor Changes + +- dea0aafda7: Updated `publish:gitlab` action properties to support additional Gitlab project settings: + + - general project settings provided by gitlab project create API (new `settings` property) + - branch level settings to create additional branches and make them protected (new `branches` property) + - project level environment variables settings (new `projectVariables` property) + + Marked existed properties `repoVisibility` and `topics` as deprecated, as they are covered by `settings` property. + +- f41099bb31: Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. + +### Patch Changes + +- 7dd82cc07e: Add examples for `github:issues:label` scaffolder action & improve related tests +- 733ddf7130: Add examples for `publish:Azure` scaffolder action. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-backend@1.14.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.3 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/plugin-scaffolder-node@0.2.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-scaffolder-common@1.4.2 + ## 1.18.0-next.2 ### Minor Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 1c87b1f289..20c56e9a8d 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.18.0-next.2", + "version": "1.18.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/gitHubEnvironment.examples.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/gitHubEnvironment.examples.ts new file mode 100644 index 0000000000..606424bef0 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/gitHubEnvironment.examples.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: + 'Create a GitHub Environment (No Policies, No Variables, No Secrets)', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Protected Branch Policy', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: true, + custom_branch_policies: false, + }, + }, + }, + ], + }), + }, + { + description: 'Create a GitHub Environment with Custom Branch Policies', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + deploymentBranchPolicy: { + protected_branches: false, + custom_branch_policies: true, + }, + customBranchPolicyNames: ['main', '*.*.*'], + }, + }, + ], + }), + }, + { + description: + 'Create a GitHub Environment with Environment Variables and Secrets', + example: yaml.stringify({ + steps: [ + { + action: 'github:environment:create', + name: 'Create Environment', + input: { + repoUrl: 'github.com?repo=repository&owner=owner', + name: 'envname', + environmentVariables: { + key1: 'val1', + key2: 'val2', + }, + secrets: { + secret1: 'supersecret1', + secret2: 'supersecret2', + }, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts new file mode 100644 index 0000000000..5e3da2fcec --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.examples.test.ts @@ -0,0 +1,260 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { PassThrough } from 'stream'; +import { createGithubEnvironmentAction } from './githubEnvironment'; +import { getVoidLogger } from '@backstage/backend-common'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import yaml from 'yaml'; +import { examples } from './gitHubEnvironment.examples'; + +const mockOctokit = { + rest: { + actions: { + getRepoPublicKey: jest.fn(), + createEnvironmentVariable: jest.fn(), + createOrUpdateEnvironmentSecret: jest.fn(), + }, + repos: { + createDeploymentBranchPolicy: jest.fn(), + createOrUpdateEnvironment: jest.fn(), + get: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; + +describe('github:environment:create examples', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + let action: TemplateAction; + + const mockContext = { + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + beforeEach(() => { + mockOctokit.rest.actions.getRepoPublicKey.mockResolvedValue({ + data: { + key: publicKey, + key_id: 'keyid', + }, + }); + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + id: 'repoid', + }, + }); + + action = createGithubEnvironmentAction({ + integrations, + }); + }); + + afterEach(jest.resetAllMocks); + + it('Create a GitHub Environment (No Policies, No Variables, No Secrets)', async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + expect(mockOctokit.rest.actions.getRepoPublicKey).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it('Create a GitHub Environment with Protected Branch Policy', async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + protected_branches: true, + custom_branch_policies: false, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + expect(mockOctokit.rest.actions.getRepoPublicKey).not.toHaveBeenCalled(); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it('Create a GitHub Environment with Custom Branch Policies', async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: { + protected_branches: false, + custom_branch_policies: true, + }, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + name: 'main', + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + name: '*.*.*', + }); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).not.toHaveBeenCalled(); + }); + + it('Create a GitHub Environment with Environment Variables and Secrets', async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect( + mockOctokit.rest.repos.createOrUpdateEnvironment, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repository', + environment_name: 'envname', + deployment_branch_policy: null, + }); + + expect( + mockOctokit.rest.repos.createDeploymentBranchPolicy, + ).not.toHaveBeenCalled(); + + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + repository_id: 'repoid', + environment_name: 'envname', + name: 'key1', + value: 'val1', + }); + expect( + mockOctokit.rest.actions.createEnvironmentVariable, + ).toHaveBeenCalledWith({ + repository_id: 'repoid', + environment_name: 'envname', + name: 'key2', + value: 'val2', + }); + + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledTimes(2); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + repository_id: 'repoid', + environment_name: 'envname', + secret_name: 'secret1', + key_id: 'keyid', + encrypted_value: expect.any(String), + }); + expect( + mockOctokit.rest.actions.createOrUpdateEnvironmentSecret, + ).toHaveBeenCalledWith({ + repository_id: 'repoid', + environment_name: 'envname', + secret_name: 'secret2', + key_id: 'keyid', + encrypted_value: expect.any(String), + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts index 04b33ed259..874798e4df 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubEnvironment.ts @@ -21,6 +21,7 @@ import { parseRepoUrl } from '../publish/util'; import { getOctokitOptions } from './helpers'; import { Octokit } from 'octokit'; import Sodium from 'libsodium-wrappers'; +import { examples } from './gitHubEnvironment.examples'; /** * Creates an `github:environment:create` Scaffolder action that creates a Github Environment. @@ -47,6 +48,7 @@ export function createGithubEnvironmentAction(options: { }>({ id: 'github:environment:create', description: 'Creates Deployment Environments', + examples, schema: { input: { type: 'object', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.test.ts new file mode 100644 index 0000000000..ce1fe76c53 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.test.ts @@ -0,0 +1,209 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { PassThrough } from 'stream'; +import { createGithubWebhookAction } from './githubWebhook'; +import yaml from 'yaml'; +import { examples } from './githubWebhook.examples'; + +const mockOctokit = { + rest: { + repos: { + createWebhook: jest.fn(), + }, + }, +}; +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('github:webhook examples', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const defaultWebhookSecret = 'aafdfdivierernfdk23f'; + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const mockContext = { + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubWebhookAction({ + integrations, + defaultWebhookSecret, + githubCredentialsProvider, + }); + }); + + it('Create a GitHub webhook for a repository', async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: input.webhookUrl, + content_type: input.contentType, + secret: input.webhookSecret, + insecure_ssl: '0', + }, + events: input.events, + active: input.active, + }); + }); + + it('Create a GitHub webhook with minimal configuration', async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: 'https://example.com/my-webhook', + content_type: 'form', + secret: defaultWebhookSecret, + insecure_ssl: '0', + }, + events: ['push'], + active: true, + }); + }); + + it('Create a GitHub webhook with custom events', async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: 'https://example.com/my-webhook', + content_type: 'form', + secret: defaultWebhookSecret, + insecure_ssl: '0', + }, + events: ['push', 'pull_request'], + active: true, + }); + }); + + it('Create a GitHub webhook with JSON content type', async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: 'https://example.com/my-webhook', + content_type: 'json', + secret: defaultWebhookSecret, + insecure_ssl: '0', + }, + events: ['push'], + active: true, + }); + }); + + it('Create a GitHub webhook with insecure SSL', async () => { + const input = yaml.parse(examples[4].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: 'https://example.com/my-webhook', + content_type: 'form', + secret: defaultWebhookSecret, + insecure_ssl: '1', + }, + events: ['push'], + active: true, + }); + }); + + it('Create an inactive GitHub webhook', async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + + await action.handler({ + ...mockContext, + input, + }); + + expect(mockOctokit.rest.repos.createWebhook).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + config: { + url: 'https://example.com/my-webhook', + content_type: 'form', + secret: defaultWebhookSecret, + insecure_ssl: '0', + }, + events: ['push'], + active: false, + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.ts new file mode 100644 index 0000000000..b6d4a8f80e --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.examples.ts @@ -0,0 +1,120 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Create a GitHub webhook for a repository', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + webhookSecret: 'mysecret', + events: ['push'], + active: true, + contentType: 'json', + insecureSsl: false, + token: 'my-github-token', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub webhook with minimal configuration', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub webhook with custom events', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + events: ['push', 'pull_request'], + }, + }, + ], + }), + }, + { + description: 'Create a GitHub webhook with JSON content type', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + contentType: 'json', + }, + }, + ], + }), + }, + { + description: 'Create a GitHub webhook with insecure SSL', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + insecureSsl: true, + }, + }, + ], + }), + }, + { + description: 'Create an inactive GitHub webhook', + example: yaml.stringify({ + steps: [ + { + action: 'github:webhook', + name: 'Create GitHub Webhook', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + webhookUrl: 'https://example.com/my-webhook', + active: false, + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts index 4d487befc7..5589c951a5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubWebhook.ts @@ -24,6 +24,7 @@ import { assertError, InputError } from '@backstage/errors'; import { Octokit } from 'octokit'; import { getOctokitOptions } from './helpers'; import { parseRepoUrl } from '../publish/util'; +import { examples } from './githubWebhook.examples'; /** * Creates new action that creates a webhook for a repository on GitHub. @@ -51,6 +52,7 @@ export function createGithubWebhookAction(options: { }>({ id: 'github:webhook', description: 'Creates webhook for a repository on GitHub.', + examples, schema: { input: { type: 'object', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts new file mode 100644 index 0000000000..3f13f2ab67 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.test.ts @@ -0,0 +1,552 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + DefaultGithubCredentialsProvider, + GithubCredentialsProvider, + ScmIntegrations, +} from '@backstage/integration'; +import { PassThrough } from 'stream'; +import { + OctokitWithPullRequestPluginClient, + createPublishGithubPullRequestAction, +} from './githubPullRequest'; +import yaml from 'yaml'; +import { examples } from './githubPullRequest.examples'; +import { createMockDirectory } from '@backstage/backend-test-utils'; + +const mockOctokit = { + rest: { + pulls: { + requestReviewers: jest.fn(), + }, + }, +}; + +jest.mock('octokit', () => ({ + Octokit: class { + constructor() { + return mockOctokit; + } + }, +})); + +describe('publish:github:pull-request examples', () => { + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + let githubCredentialsProvider: GithubCredentialsProvider; + let action: TemplateAction; + + const mockContext = { + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + let fakeClient: { + createPullRequest: jest.Mock; + rest: { + pulls: { requestReviewers: jest.Mock }; + }; + }; + const mockDir = createMockDirectory(); + const workspacePath = mockDir.resolve('workspace'); + + beforeEach(() => { + mockDir.clear(); + jest.resetAllMocks(); + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + fakeClient = { + createPullRequest: jest.fn(async (_: any) => { + return { + url: 'https://api.github.com/myorg/myrepo/pull/123', + headers: {}, + status: 201, + data: { + html_url: 'https://github.com/myorg/myrepo/pull/123', + number: 123, + base: { + ref: 'main', + }, + }, + }; + }), + rest: { + pulls: { + requestReviewers: jest.fn(async (_: any) => ({ data: {} })), + }, + }, + }; + + const clientFactory = jest.fn( + async () => fakeClient as unknown as OctokitWithPullRequestPluginClient, + ); + + mockDir.setContent({ + [workspacePath]: { 'file.txt': 'Hello there!' }, + }); + + action = createPublishGithubPullRequestAction({ + integrations, + githubCredentialsProvider, + clientFactory, + }); + }); + + afterEach(jest.resetAllMocks); + + it('Create a pull request', async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with target branch name', async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + base: 'test', + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request as draft', async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: true, + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with target path', async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'targetPath/file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with source path', async () => { + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + const input = yaml.parse(examples[4].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'foo.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with token', async () => { + const input = yaml.parse(examples[5].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with reviewers', async () => { + const input = yaml.parse(examples[6].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + pull_number: 123, + reviewers: ['foobar'], + }); + + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with team reviewers', async () => { + const input = yaml.parse(examples[7].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Create my new app', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + pull_number: 123, + team_reviewers: ['team-foo'], + }); + + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with commit message', async () => { + const input = yaml.parse(examples[8].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: undefined, + changes: [ + { + commit: 'Custom commit message', + files: { + 'file.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled(); + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); + + it('Create a pull request with all parameters', async () => { + mockDir.setContent({ + [workspacePath]: { + source: { 'foo.txt': 'Hello there!' }, + irrelevant: { 'bar.txt': 'Nothing to see here' }, + }, + }); + const input = yaml.parse(examples[9].example).steps[0].input; + + await action.handler({ + ...mockContext, + workspacePath, + input, + }); + + expect(fakeClient.createPullRequest).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + title: 'Create my new app', + body: 'This PR is really good', + head: 'new-app', + draft: true, + base: 'test', + changes: [ + { + commit: 'Commit for foo changes', + files: { + 'targetPath/foo.txt': { + content: Buffer.from('Hello there!').toString('base64'), + encoding: 'base64', + mode: '100644', + }, + }, + }, + ], + }); + + expect(fakeClient.rest.pulls.requestReviewers).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + pull_number: 123, + reviewers: ['foobar'], + team_reviewers: ['team-foo'], + }); + + expect(mockContext.output).toHaveBeenCalledTimes(3); + expect(mockContext.output).toHaveBeenCalledWith('targetBranchName', 'main'); + expect(mockContext.output).toHaveBeenCalledWith( + 'remoteUrl', + 'https://github.com/myorg/myrepo/pull/123', + ); + expect(mockContext.output).toHaveBeenCalledWith('pullRequestNumber', 123); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.ts new file mode 100644 index 0000000000..d6138b262b --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.examples.ts @@ -0,0 +1,206 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Create a pull request', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + }, + }, + ], + }), + }, + { + description: 'Create a pull request with target branch name', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest with target branch name', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + targetBranchName: 'test', + }, + }, + ], + }), + }, + { + description: 'Create a pull request as draft', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest as draft', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + draft: true, + }, + }, + ], + }), + }, + { + description: 'Create a pull request with target path', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest with target path', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + targetPath: 'targetPath', + }, + }, + ], + }), + }, + { + description: 'Create a pull request with source path', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest with source path', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + sourcePath: 'source', + }, + }, + ], + }), + }, + { + description: 'Create a pull request with token', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + token: 'gph_YourGitHubToken', + }, + }, + ], + }), + }, + { + description: 'Create a pull request with reviewers', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest with reviewers', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + reviewers: ['foobar'], + }, + }, + ], + }), + }, + { + description: 'Create a pull request with team reviewers', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest with team reviewers', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + teamReviewers: ['team-foo'], + }, + }, + ], + }), + }, + { + description: 'Create a pull request with commit message', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + commitMessage: 'Custom commit message', + }, + }, + ], + }), + }, + { + description: 'Create a pull request with all parameters', + example: yaml.stringify({ + steps: [ + { + action: 'publish:github:pull-request', + name: 'Create a pull reuqest', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + branchName: 'new-app', + title: 'Create my new app', + description: 'This PR is really good', + targetBranchName: 'test', + draft: true, + targetPath: 'targetPath', + sourcePath: 'source', + token: 'gph_YourGitHubToken', + reviewers: ['foobar'], + teamReviewers: ['team-foo'], + commitMessage: 'Commit for foo changes', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts index 167fedc88e..a02f21cfc2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/githubPullRequest.ts @@ -31,6 +31,7 @@ import { serializeDirectoryContents, } from '../../../../lib/files'; import { Logger } from 'winston'; +import { examples } from './githubPullRequest.examples'; export type Encoding = 'utf-8' | 'base64'; @@ -143,6 +144,7 @@ export const createPublishGithubPullRequestAction = ( commitMessage?: string; }>({ id: 'publish:github:pull-request', + examples, schema: { input: { required: ['repoUrl', 'title', 'description', 'branchName'], diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 523ce514d6..6e81966514 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-common +## 1.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 1.4.2-next.0 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 5fe72348c1..0d9ef37999 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.4.2-next.0", + "version": "1.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index 1de68205b2..d4be9b7538 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -14,6 +14,7 @@ }, "spec": { "owner": "artist-relations-team", + "type": "website", "parameters": { "required": ["name", "description", "repoUrl"], "backstage:permissions": { diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 0d95cd77cc..33bf8dd380 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.2 + ## 0.2.6-next.2 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index fd49db0371..3194f0c0d6 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.2.6-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index eb20d79d2a..2aed192d7d 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-react +## 1.5.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.2 + ## 1.5.6-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/alpha-api-report.md index 3c9a4df26b..282edf6457 100644 --- a/plugins/scaffolder-react/alpha-api-report.md +++ b/plugins/scaffolder-react/alpha-api-report.md @@ -6,13 +6,15 @@ /// import { ApiHolder } from '@backstage/core-plugin-api'; +import { ComponentType } from 'react'; import { CustomFieldExtensionSchema } from '@backstage/plugin-scaffolder-react'; +import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; import { Dispatch } from 'react'; import { Extension } from '@backstage/core-plugin-api'; import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react'; -import { FieldProps } from '@rjsf/utils'; +import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FieldValidation } from '@rjsf/utils'; -import { FormProps as FormProps_2 } from '@rjsf/core-v5'; +import { FormProps } from '@backstage/plugin-scaffolder-react'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; @@ -21,25 +23,40 @@ import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactElement } from 'react'; import { ReactNode } from 'react'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderRJSFFieldProps } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderRJSFFormProps } from '@backstage/plugin-scaffolder-react'; import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; import { SetStateAction } from 'react'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; -import { UIOptionsType } from '@rjsf/utils'; import { UiSchema } from '@rjsf/utils'; +// @alpha (undocumented) +export const createAsyncValidators: ( + rootSchema: JsonObject, + validators: Record< + string, + undefined | CustomFieldValidator + >, + context: { + apiHolder: ApiHolder; + }, +) => (formData: JsonObject) => Promise; + // @alpha export const createFieldValidation: () => FieldValidation; // @alpha -export function createNextScaffolderFieldExtension< +export function createLegacyScaffolderFieldExtension< TReturnValue = unknown, - TInputProps extends UIOptionsType = {}, + TInputProps = unknown, >( - options: NextFieldExtensionOptions, + options: LegacyFieldExtensionOptions, ): Extension>; // @alpha @@ -58,59 +75,47 @@ export const extractSchemaFromStep: (inputStep: JsonObject) => { // @alpha export const Form: ( - props: PropsWithChildren, + props: PropsWithChildren, ) => React_2.JSX.Element; -// @alpha -export type FormProps = Pick< - FormProps_2, - 'transformErrors' | 'noHtml5Validate' ->; +// @alpha (undocumented) +export type FormValidation = { + [name: string]: FieldValidation | FormValidation; +}; // @alpha -export type NextCustomFieldValidator< - TFieldReturnValue, - TUiOptions = unknown, -> = ( +export type LegacyCustomFieldValidator = ( data: TFieldReturnValue, field: FieldValidation, context: { apiHolder: ApiHolder; - formData: JsonObject; - schema: JsonObject; - uiSchema?: NextFieldExtensionUiSchema; }, ) => void | Promise; // @alpha -export interface NextFieldExtensionComponentProps< +export interface LegacyFieldExtensionComponentProps< TFieldReturnValue, - TUiOptions = {}, -> extends PropsWithChildren> { + TUiOptions = unknown, +> extends ScaffolderRJSFFieldProps { // (undocumented) - uiSchema?: NextFieldExtensionUiSchema; + uiSchema: ScaffolderRJSFFieldProps['uiSchema'] & { + 'ui:options'?: TUiOptions; + }; } // @alpha -export type NextFieldExtensionOptions< +export type LegacyFieldExtensionOptions< TFieldReturnValue = unknown, - TUiOptions = unknown, + TInputProps = unknown, > = { name: string; component: ( - props: NextFieldExtensionComponentProps, + props: LegacyFieldExtensionComponentProps, ) => JSX.Element | null; - validation?: NextCustomFieldValidator; + validation?: LegacyCustomFieldValidator; schema?: CustomFieldExtensionSchema; }; -// @alpha -export interface NextFieldExtensionUiSchema - extends UiSchema { - // (undocumented) - 'ui:options'?: TUiOptions & UIOptionsType; -} - // @alpha export interface ParsedTemplateSchema { // (undocumented) @@ -177,12 +182,13 @@ export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; // @alpha export type StepperProps = { manifest: TemplateParameterSchema; - extensions: NextFieldExtensionOptions[]; + extensions: FieldExtensionOptions[]; templateName?: string; - FormProps?: FormProps; + formProps?: FormProps; initialState?: Record; onCreate: (values: Record) => Promise; components?: { + ReviewStepComponent?: ComponentType; ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; backButtonText?: ReactNode; createButtonText?: ReactNode; @@ -238,12 +244,6 @@ export const TemplateGroup: ( props: TemplateGroupProps, ) => React_2.JSX.Element | null; -// @alpha (undocumented) -export type TemplateGroupFilter = { - title?: React_2.ReactNode; - filter: (entity: TemplateEntityV1beta3) => boolean; -}; - // @alpha export interface TemplateGroupProps { // (undocumented) @@ -317,11 +317,14 @@ export type WorkflowProps = { description?: string; namespace: string; templateName: string; + components?: { + ReviewStepComponent?: React_2.ComponentType; + }; onError(error: Error | undefined): JSX.Element | null; } & Pick< StepperProps, | 'extensions' - | 'FormProps' + | 'formProps' | 'components' | 'onCreate' | 'initialState' diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index 5df7aa3b85..6acc2f9812 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -7,19 +7,42 @@ import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; +import { ComponentType } from 'react'; +import { CustomValidator } from '@rjsf/utils'; +import { ElementType } from 'react'; +import { ErrorSchema } from '@rjsf/utils'; +import { ErrorTransformer } from '@rjsf/utils'; +import { Experimental_DefaultFormStateBehavior } from '@rjsf/utils'; import { Extension } from '@backstage/core-plugin-api'; -import { FieldProps } from '@rjsf/core'; -import { FieldValidation } from '@rjsf/core'; -import type { FormProps } from '@rjsf/core-v5'; +import { FieldValidation } from '@rjsf/utils'; +import Form from '@rjsf/core'; +import { FormContextType } from '@rjsf/utils'; +import { FormEvent } from 'react'; +import type { FormProps as FormProps_2 } from '@rjsf/core'; +import { GenericObjectType } from '@rjsf/utils'; +import { HTMLAttributes } from 'react'; +import { IChangeEvent } from '@rjsf/core'; +import { IdSchema } from '@rjsf/utils'; import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; import { JsonValue } from '@backstage/types'; import { Observable } from '@backstage/types'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; +import { ReactNode } from 'react'; +import { Ref } from 'react'; +import { Registry } from '@rjsf/utils'; +import { RegistryWidgetsType } from '@rjsf/utils'; +import { RJSFSchema } from '@rjsf/utils'; +import { RJSFValidationError } from '@rjsf/utils'; +import { StrictRJSFSchema } from '@rjsf/utils'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; -import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatesType } from '@rjsf/utils'; +import { UIOptionsType } from '@rjsf/utils'; +import { UiSchema } from '@rjsf/utils'; +import { ValidatorType } from '@rjsf/utils'; // @public export type Action = { @@ -41,7 +64,7 @@ export type ActionExample = { // @public export function createScaffolderFieldExtension< TReturnValue = unknown, - TInputProps = unknown, + TInputProps extends UIOptionsType = {}, >( options: FieldExtensionOptions, ): Extension>; @@ -58,11 +81,14 @@ export type CustomFieldExtensionSchema = { }; // @public -export type CustomFieldValidator = ( +export type CustomFieldValidator = ( data: TFieldReturnValue, field: FieldValidation, context: { apiHolder: ApiHolder; + formData: JsonObject; + schema: JsonObject; + uiSchema?: FieldExtensionUiSchema; }, ) => void | Promise; @@ -72,27 +98,38 @@ export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; // @public export interface FieldExtensionComponentProps< TFieldReturnValue, - TUiOptions = unknown, -> extends FieldProps { + TUiOptions = {}, +> extends PropsWithChildren> { // (undocumented) - uiSchema: FieldProps['uiSchema'] & { - 'ui:options'?: TUiOptions; - }; + uiSchema: FieldExtensionUiSchema; } // @public export type FieldExtensionOptions< TFieldReturnValue = unknown, - TInputProps = unknown, + TUiOptions = unknown, > = { name: string; component: ( - props: FieldExtensionComponentProps, + props: FieldExtensionComponentProps, ) => JSX.Element | null; - validation?: CustomFieldValidator; + validation?: CustomFieldValidator; schema?: CustomFieldExtensionSchema; }; +// @public +export interface FieldExtensionUiSchema + extends UiSchema { + // (undocumented) + 'ui:options'?: TUiOptions & UIOptionsType; +} + +// @public +export type FormProps = Pick< + FormProps_2, + 'transformErrors' | 'noHtml5Validate' +>; + // @public export type LayoutComponent<_TInputProps> = () => null; @@ -106,7 +143,7 @@ export interface LayoutOptions

{ // @public export type LayoutTemplate = NonNullable< - FormProps['uiSchema'] + FormProps_2['uiSchema'] >['ui:ObjectFieldTemplate']; // @public @@ -125,6 +162,20 @@ export type LogEvent = { taskId: string; }; +// @public +export type ReviewStepProps = { + disableButtons: boolean; + formData: JsonObject; + handleBack: () => void; + handleReset: () => void; + handleCreate: () => void; + steps: { + uiSchema: UiSchema; + mergedSchema: JsonObject; + schema: JsonObject; + }[]; +}; + // @public export interface ScaffolderApi { cancelTask(taskId: string): Promise; @@ -187,8 +238,8 @@ export interface ScaffolderDryRunResponse { } // @public -export const ScaffolderFieldExtensions: React_2.ComponentType< - React_2.PropsWithChildren<{}> +export const ScaffolderFieldExtensions: React.ComponentType< + React.PropsWithChildren<{}> >; // @public @@ -227,6 +278,113 @@ export type ScaffolderOutputText = { content?: string; }; +// @public +export type ScaffolderRJSFField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = ComponentType>; + +// @public +export interface ScaffolderRJSFFieldProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> extends GenericObjectType, + Pick< + HTMLAttributes, + Exclude< + keyof HTMLAttributes, + 'onBlur' | 'onFocus' | 'onChange' + > + > { + autofocus?: boolean; + disabled: boolean; + errorSchema?: ErrorSchema; + formContext?: F; + formData: T; + hideError?: boolean; + idPrefix?: string; + idSchema: IdSchema; + idSeparator?: string; + name: string; + onBlur: (id: string, value: any) => void; + onChange: ( + newFormData: T | undefined, + es?: ErrorSchema, + id?: string, + ) => any; + onFocus: (id: string, value: any) => void; + rawErrors: string[]; + readonly: boolean; + registry: Registry; + required?: boolean; + schema: S; + uiSchema: UiSchema; +} + +// @public +export interface ScaffolderRJSFFormProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> { + acceptcharset?: string; + action?: string; + autoComplete?: string; + children?: ReactNode; + className?: string; + customValidate?: CustomValidator; + disabled?: boolean; + enctype?: string; + experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior; + extraErrors?: ErrorSchema; + fields?: ScaffolderRJSFRegistryFieldsType; + focusOnFirstError?: boolean | ((error: RJSFValidationError) => void); + formContext?: F; + formData?: T; + id?: string; + idPrefix?: string; + idSeparator?: string; + _internalFormWrapper?: ElementType; + liveOmit?: boolean; + liveValidate?: boolean; + method?: string; + name?: string; + noHtml5Validate?: boolean; + // @deprecated + noValidate?: boolean; + omitExtraData?: boolean; + onBlur?: (id: string, data: any) => void; + onChange?: (data: IChangeEvent, id?: string) => void; + onError?: (errors: RJSFValidationError[]) => void; + onFocus?: (id: string, data: any) => void; + onSubmit?: (data: IChangeEvent, event: FormEvent) => void; + readonly?: boolean; + ref?: Ref>; + schema: S; + showErrorList?: false | 'top' | 'bottom'; + tagName?: ElementType; + target?: string; + templates?: Partial, 'ButtonTemplates'>> & { + ButtonTemplates?: Partial['ButtonTemplates']>; + }; + transformErrors?: ErrorTransformer; + translateString?: Registry['translateString']; + uiSchema?: UiSchema; + validator: ValidatorType; + widgets?: RegistryWidgetsType; +} + +// @public +export type ScaffolderRJSFRegistryFieldsType< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = { + [name: string]: ScaffolderRJSFField; +}; + // @public export interface ScaffolderScaffoldOptions { // (undocumented) @@ -314,11 +472,16 @@ export type TaskStream = { output?: ScaffolderTaskOutput; }; +// @public (undocumented) +export type TemplateGroupFilter = { + title?: React.ReactNode; + filter: (entity: TemplateEntityV1beta3) => boolean; +}; + // @public export type TemplateParameterSchema = { title: string; description?: string; - configurations?: TemplateConfigurationsV1beta3; steps: Array<{ title: string; description?: string; diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 7a5aa49a01..5f29f96946 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.5.6-next.2", + "version": "1.5.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,10 +60,8 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", - "@rjsf/core": "^3.2.1", - "@rjsf/core-v5": "npm:@rjsf/core@5.13.0", - "@rjsf/material-ui": "^3.2.1", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0", + "@rjsf/core": "5.13.0", + "@rjsf/material-ui": "5.13.0", "@rjsf/utils": "5.13.0", "@rjsf/validator-ajv8": "5.13.0", "@types/json-schema": "^7.0.9", @@ -83,8 +81,8 @@ "zod-to-json-schema": "^3.20.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -95,8 +93,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.18.1", "@types/luxon": "^3.0.0" diff --git a/plugins/scaffolder-react/src/alpha.ts b/plugins/scaffolder-react/src/alpha.ts index 731b8e07d9..224ee97c06 100644 --- a/plugins/scaffolder-react/src/alpha.ts +++ b/plugins/scaffolder-react/src/alpha.ts @@ -15,4 +15,4 @@ */ export * from './next'; -export type { FormProps } from './next'; +export * from './legacy'; diff --git a/plugins/scaffolder-react/src/components/index.ts b/plugins/scaffolder-react/src/components/index.ts new file mode 100644 index 0000000000..92cb965d75 --- /dev/null +++ b/plugins/scaffolder-react/src/components/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './types'; diff --git a/plugins/scaffolder-react/src/components/types.ts b/plugins/scaffolder-react/src/components/types.ts new file mode 100644 index 0000000000..597998bac4 --- /dev/null +++ b/plugins/scaffolder-react/src/components/types.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import type { FormProps as SchemaFormProps } from '@rjsf/core'; +import { UiSchema } from '@rjsf/utils'; +import { JsonObject } from '@backstage/types'; + +/** @public */ +export type TemplateGroupFilter = { + title?: React.ReactNode; + filter: (entity: TemplateEntityV1beta3) => boolean; +}; + +/** + * Any `@rjsf/core` form properties that are publicly exposed to the `ScaffolderPage` + * + * @public + */ +export type FormProps = Pick< + SchemaFormProps, + 'transformErrors' | 'noHtml5Validate' +>; + +/** + * The props for the Last Step in scaffolder template form. + * Which represents the summary of the input provided by the end user. + * + * @public + */ +export type ReviewStepProps = { + disableButtons: boolean; + formData: JsonObject; + handleBack: () => void; + handleReset: () => void; + handleCreate: () => void; + steps: { + uiSchema: UiSchema; + mergedSchema: JsonObject; + schema: JsonObject; + }[]; +}; diff --git a/plugins/scaffolder-react/src/extensions/index.tsx b/plugins/scaffolder-react/src/extensions/index.tsx index d70f5e36c5..5372a8cf7e 100644 --- a/plugins/scaffolder-react/src/extensions/index.tsx +++ b/plugins/scaffolder-react/src/extensions/index.tsx @@ -14,23 +14,17 @@ * limitations under the License. */ -import React from 'react'; import { - CustomFieldExtensionSchema, CustomFieldValidator, FieldExtensionOptions, FieldExtensionComponentProps, + FieldExtensionUiSchema, + CustomFieldExtensionSchema, } from './types'; import { Extension, attachComponentData } from '@backstage/core-plugin-api'; +import { UIOptionsType } from '@rjsf/utils'; import { FIELD_EXTENSION_KEY, FIELD_EXTENSION_WRAPPER_KEY } from './keys'; -/** - * The type used to wrap up the Layout and embed the input props - * - * @public - */ -export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; - /** * Method for creating field extensions that can be used in the scaffolder * frontend form. @@ -38,7 +32,7 @@ export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; */ export function createScaffolderFieldExtension< TReturnValue = unknown, - TInputProps = unknown, + TInputProps extends UIOptionsType = {}, >( options: FieldExtensionOptions, ): Extension> { @@ -72,9 +66,19 @@ attachComponentData( true, ); +/** + * The type used to wrap up the Layout and embed the input props + * + * @public + */ +export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; + export type { - CustomFieldExtensionSchema, CustomFieldValidator, FieldExtensionOptions, FieldExtensionComponentProps, + FieldExtensionUiSchema, + CustomFieldExtensionSchema, }; + +export * from './rjsf'; diff --git a/plugins/scaffolder-react/src/extensions/rjsf.ts b/plugins/scaffolder-react/src/extensions/rjsf.ts new file mode 100644 index 0000000000..cacedad080 --- /dev/null +++ b/plugins/scaffolder-react/src/extensions/rjsf.ts @@ -0,0 +1,292 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentType, ElementType, FormEvent, ReactNode, Ref } from 'react'; +import { + ErrorSchema, + FormContextType, + GenericObjectType, + IdSchema, + Registry, + RJSFSchema, + StrictRJSFSchema, + UiSchema, + ValidatorType, + TemplatesType, + RegistryWidgetsType, + RJSFValidationError, + CustomValidator, + Experimental_DefaultFormStateBehavior, + ErrorTransformer, +} from '@rjsf/utils'; +import { HTMLAttributes } from 'react'; +import Form, { IChangeEvent } from '@rjsf/core'; + +/** + * The props for the `Field` components + * @public + */ +export interface ScaffolderRJSFFieldProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> extends GenericObjectType, + Pick< + HTMLAttributes, + Exclude< + keyof HTMLAttributes, + 'onBlur' | 'onFocus' | 'onChange' + > + > { + /** The JSON subschema object for this field */ + schema: S; + /** The uiSchema for this field */ + uiSchema: UiSchema; + /** The tree of unique ids for every child field */ + idSchema: IdSchema; + /** The data for this field */ + formData: T; + /** The tree of errors for this field and its children */ + errorSchema?: ErrorSchema; + /** The field change event handler; called with the updated form data and an optional `ErrorSchema` */ + onChange: ( + newFormData: T | undefined, + es?: ErrorSchema, + id?: string, + ) => any; + /** The input blur event handler; call it with the field id and value */ + onBlur: (id: string, value: any) => void; + /** The input focus event handler; call it with the field id and value */ + onFocus: (id: string, value: any) => void; + /** The `formContext` object that you passed to `Form` */ + formContext?: F; + /** A boolean value stating if the field should autofocus */ + autofocus?: boolean; + /** A boolean value stating if the field is disabled */ + disabled: boolean; + /** A boolean value stating if the field is hiding its errors */ + hideError?: boolean; + /** A boolean value stating if the field is read-only */ + readonly: boolean; + /** The required status of this field */ + required?: boolean; + /** The unique name of the field, usually derived from the name of the property in the JSONSchema */ + name: string; + /** To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids; + * Default is `root` + */ + idPrefix?: string; + /** To avoid using a path separator that is present in field names, it is possible to change the separator used for + * ids (Default is `_`) + */ + idSeparator?: string; + /** An array of strings listing all generated error messages from encountered errors for this field */ + rawErrors: string[]; + /** The `registry` object */ + registry: Registry; +} + +/** + * The properties that are passed to the `Form` + * @public + */ +export interface ScaffolderRJSFFormProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> { + /** The JSON schema object for the form */ + schema: S; + /** An implementation of the `ValidatorType` interface that is needed for form validation to work */ + validator: ValidatorType; + /** The optional children for the form, if provided, it will replace the default `SubmitButton` */ + children?: ReactNode; + /** The uiSchema for the form */ + uiSchema?: UiSchema; + /** The data for the form, used to prefill a form with existing data */ + formData?: T; + /** You can provide a `formContext` object to the form, which is passed down to all fields and widgets. Useful for + * implementing context aware fields and widgets. + * + * NOTE: Setting `{readonlyAsDisabled: false}` on the formContext will make the antd theme treat readOnly fields as + * disabled. + */ + formContext?: F; + /** To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids; + * Default is `root` + */ + idPrefix?: string; + /** To avoid using a path separator that is present in field names, it is possible to change the separator used for + * ids (Default is `_`) + */ + idSeparator?: string; + /** It's possible to disable the whole form by setting the `disabled` prop. The `disabled` prop is then forwarded down + * to each field of the form. If you just want to disable some fields, see the `ui:disabled` parameter in `uiSchema` + */ + disabled?: boolean; + /** It's possible to make the whole form read-only by setting the `readonly` prop. The `readonly` prop is then + * forwarded down to each field of the form. If you just want to make some fields read-only, see the `ui:readonly` + * parameter in `uiSchema` + */ + readonly?: boolean; + /** The dictionary of registered fields in the form */ + fields?: ScaffolderRJSFRegistryFieldsType; + /** The dictionary of registered templates in the form; Partial allows a subset to be provided beyond the defaults */ + templates?: Partial, 'ButtonTemplates'>> & { + ButtonTemplates?: Partial['ButtonTemplates']>; + }; + /** The dictionary of registered widgets in the form */ + widgets?: RegistryWidgetsType; + /** If you plan on being notified every time the form data are updated, you can pass an `onChange` handler, which will + * receive the same args as `onSubmit` any time a value is updated in the form. Can also return the `id` of the field + * that caused the change + */ + onChange?: (data: IChangeEvent, id?: string) => void; + /** To react when submitted form data are invalid, pass an `onError` handler. It will be passed the list of + * encountered errors + */ + onError?: (errors: RJSFValidationError[]) => void; + /** You can pass a function as the `onSubmit` prop of your `Form` component to listen to when the form is submitted + * and its data are valid. It will be passed a result object having a `formData` attribute, which is the valid form + * data you're usually after. The original event will also be passed as a second parameter + */ + onSubmit?: (data: IChangeEvent, event: FormEvent) => void; + /** Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass + * an `onBlur` handler, which will receive the id of the input that was blurred and the field value + */ + onBlur?: (id: string, data: any) => void; + /** Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass + * an `onFocus` handler, which will receive the id of the input that is focused and the field value + */ + onFocus?: (id: string, data: any) => void; + /** The value of this prop will be passed to the `accept-charset` HTML attribute on the form */ + acceptcharset?: string; + /** The value of this prop will be passed to the `action` HTML attribute on the form + * + * NOTE: this just renders the `action` attribute in the HTML markup. There is no real network request being sent to + * this `action` on submit. Instead, react-jsonschema-form catches the submit event with `event.preventDefault()` + * and then calls the `onSubmit` function, where you could send a request programmatically with `fetch` or similar. + */ + action?: string; + /** The value of this prop will be passed to the `autocomplete` HTML attribute on the form */ + autoComplete?: string; + /** The value of this prop will be passed to the `class` HTML attribute on the form */ + className?: string; + /** The value of this prop will be passed to the `enctype` HTML attribute on the form */ + enctype?: string; + /** The value of this prop will be passed to the `id` HTML attribute on the form */ + id?: string; + /** The value of this prop will be passed to the `name` HTML attribute on the form */ + name?: string; + /** The value of this prop will be passed to the `method` HTML attribute on the form */ + method?: string; + /** It's possible to change the default `form` tag name to a different HTML tag, which can be helpful if you are + * nesting forms. However, native browser form behaviour, such as submitting when the `Enter` key is pressed, may no + * longer work + */ + tagName?: ElementType; + /** The value of this prop will be passed to the `target` HTML attribute on the form */ + target?: string; + /** Formerly the `validate` prop; Takes a function that specifies custom validation rules for the form */ + customValidate?: CustomValidator; + /** This prop allows passing in custom errors that are augmented with the existing JSON Schema errors on the form; it + * can be used to implement asynchronous validation + */ + extraErrors?: ErrorSchema; + /** If set to true, turns off HTML5 validation on the form; Set to `false` by default */ + noHtml5Validate?: boolean; + /** If set to true, turns off all validation. Set to `false` by default + * + * @deprecated - In a future release, this switch may be replaced by making `validator` prop optional + */ + noValidate?: boolean; + /** If set to true, the form will perform validation and show any validation errors whenever the form data is changed, + * rather than just on submit + */ + liveValidate?: boolean; + /** If `omitExtraData` and `liveOmit` are both set to true, then extra form data values that are not in any form field + * will be removed whenever `onChange` is called. Set to `false` by default + */ + liveOmit?: boolean; + /** If set to true, then extra form data values that are not in any form field will be removed whenever `onSubmit` is + * called. Set to `false` by default. + */ + omitExtraData?: boolean; + /** When this prop is set to `top` or 'bottom', a list of errors (or the custom error list defined in the `ErrorList`) will also + * show. When set to false, only inline input validation errors will be shown. Set to `top` by default + */ + showErrorList?: false | 'top' | 'bottom'; + /** A function can be passed to this prop in order to make modifications to the default errors resulting from JSON + * Schema validation + */ + transformErrors?: ErrorTransformer; + /** If set to true, then the first field with an error will receive the focus when the form is submitted with errors + */ + focusOnFirstError?: boolean | ((error: RJSFValidationError) => void); + /** Optional string translation function, if provided, allows users to change the translation of the RJSF internal + * strings. Some strings contain replaceable parameter values as indicated by `%1`, `%2`, etc. The number after the + * `%` indicates the order of the parameter. The ordering of parameters is important because some languages may choose + * to put the second parameter before the first in its translation. + */ + translateString?: Registry['translateString']; + /** Optional configuration object with flags, if provided, allows users to override default form state behavior + * Currently only affecting minItems on array fields and handling of setting defaults based on the value of + * `emptyObjectFields` + */ + experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior; + /** + * _internalFormWrapper is currently used by the semantic-ui theme to provide a custom wrapper around `

` + * that supports the proper rendering of those themes. To use this prop, one must pass a component that takes two + * props: `children` and `as`. That component, at minimum, should render the `children` inside of a tag + * unless `as` is provided, in which case, use the `as` prop in place of ``. + * i.e.: + * ``` + * export default function InternalForm({ children, as }) { + * const FormTag = as || 'form'; + * return {children}; + * } + * ``` + * + * Use at your own risk as this prop is private and may change at any time without notice. + */ + _internalFormWrapper?: ElementType; + /** Support receiving a React ref to the Form + */ + ref?: Ref>; +} + +/** + * The set of `Fields` stored in the `Registry` + * @public + */ +export type ScaffolderRJSFRegistryFieldsType< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = { + /** A `Field` indexed by `name` */ + [name: string]: ScaffolderRJSFField; +}; + +/** + * The `Field` type for Field Extensions + * @public + */ +export type ScaffolderRJSFField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = ComponentType>; diff --git a/plugins/scaffolder-react/src/extensions/types.ts b/plugins/scaffolder-react/src/extensions/types.ts index 5d560a20bc..b77dc39c73 100644 --- a/plugins/scaffolder-react/src/extensions/types.ts +++ b/plugins/scaffolder-react/src/extensions/types.ts @@ -14,19 +14,23 @@ * limitations under the License. */ import { ApiHolder } from '@backstage/core-plugin-api'; -import { FieldValidation, FieldProps } from '@rjsf/core'; +import { PropsWithChildren } from 'react'; +import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; +import { UiSchema, UIOptionsType, FieldValidation } from '@rjsf/utils'; +import { ScaffolderRJSFFieldProps } from './rjsf'; /** - * Field validation type for Custom Field Extensions. + * Type for Field Extension Props for RJSF v5 * * @public */ -export type CustomFieldValidator = ( - data: TFieldReturnValue, - field: FieldValidation, - context: { apiHolder: ApiHolder }, -) => void | Promise; +export interface FieldExtensionComponentProps< + TFieldReturnValue, + TUiOptions = {}, +> extends PropsWithChildren> { + uiSchema: FieldExtensionUiSchema; +} /** * Type for the Custom Field Extension schema. @@ -38,6 +42,32 @@ export type CustomFieldExtensionSchema = { uiOptions?: JSONSchema7; }; +/** + * Type for Field Extension UiSchema + * + * @public + */ +export interface FieldExtensionUiSchema + extends UiSchema { + 'ui:options'?: TUiOptions & UIOptionsType; +} + +/** + * Field validation type for Custom Field Extensions. + * + * @public + */ +export type CustomFieldValidator = ( + data: TFieldReturnValue, + field: FieldValidation, + context: { + apiHolder: ApiHolder; + formData: JsonObject; + schema: JsonObject; + uiSchema?: FieldExtensionUiSchema; + }, +) => void | Promise; + /** * Type for the Custom Field Extension with the * name and components and validation function. @@ -46,27 +76,12 @@ export type CustomFieldExtensionSchema = { */ export type FieldExtensionOptions< TFieldReturnValue = unknown, - TInputProps = unknown, + TUiOptions = unknown, > = { name: string; component: ( - props: FieldExtensionComponentProps, + props: FieldExtensionComponentProps, ) => JSX.Element | null; - validation?: CustomFieldValidator; + validation?: CustomFieldValidator; schema?: CustomFieldExtensionSchema; }; - -/** - * Type for field extensions and being able to type - * incoming props easier. - * - * @public - */ -export interface FieldExtensionComponentProps< - TFieldReturnValue, - TUiOptions = unknown, -> extends FieldProps { - uiSchema: FieldProps['uiSchema'] & { - 'ui:options'?: TUiOptions; - }; -} diff --git a/plugins/scaffolder-react/src/index.ts b/plugins/scaffolder-react/src/index.ts index 1b20c19414..70560cc694 100644 --- a/plugins/scaffolder-react/src/index.ts +++ b/plugins/scaffolder-react/src/index.ts @@ -15,6 +15,7 @@ */ export * from './extensions'; +export * from './components'; export * from './types'; export * from './secrets'; export * from './api'; diff --git a/plugins/scaffolder-react/src/layouts/createScaffolderLayout.ts b/plugins/scaffolder-react/src/layouts/createScaffolderLayout.ts index 6b2ae1b33b..d950285a7d 100644 --- a/plugins/scaffolder-react/src/layouts/createScaffolderLayout.ts +++ b/plugins/scaffolder-react/src/layouts/createScaffolderLayout.ts @@ -16,7 +16,7 @@ import { LAYOUTS_KEY, LAYOUTS_WRAPPER_KEY } from './keys'; import { attachComponentData, Extension } from '@backstage/core-plugin-api'; -import type { FormProps as SchemaFormProps } from '@rjsf/core-v5'; +import type { FormProps as SchemaFormProps } from '@rjsf/core'; import React from 'react'; /** diff --git a/plugins/scaffolder-react/src/next/extensions/index.tsx b/plugins/scaffolder-react/src/legacy/extensions/index.tsx similarity index 74% rename from plugins/scaffolder-react/src/next/extensions/index.tsx rename to plugins/scaffolder-react/src/legacy/extensions/index.tsx index 70751936c5..870d797fc4 100644 --- a/plugins/scaffolder-react/src/next/extensions/index.tsx +++ b/plugins/scaffolder-react/src/legacy/extensions/index.tsx @@ -15,13 +15,11 @@ */ import { - NextCustomFieldValidator, - NextFieldExtensionOptions, - NextFieldExtensionComponentProps, - NextFieldExtensionUiSchema, + LegacyCustomFieldValidator, + LegacyFieldExtensionOptions, + LegacyFieldExtensionComponentProps, } from './types'; import { Extension, attachComponentData } from '@backstage/core-plugin-api'; -import { UIOptionsType } from '@rjsf/utils'; import { FIELD_EXTENSION_KEY } from '../../extensions/keys'; import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react'; @@ -30,11 +28,11 @@ import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react'; * frontend form. * @alpha */ -export function createNextScaffolderFieldExtension< +export function createLegacyScaffolderFieldExtension< TReturnValue = unknown, - TInputProps extends UIOptionsType = {}, + TInputProps = unknown, >( - options: NextFieldExtensionOptions, + options: LegacyFieldExtensionOptions, ): Extension> { return { expose() { @@ -52,8 +50,7 @@ export function createNextScaffolderFieldExtension< } export type { - NextCustomFieldValidator, - NextFieldExtensionOptions, - NextFieldExtensionComponentProps, - NextFieldExtensionUiSchema, + LegacyCustomFieldValidator, + LegacyFieldExtensionOptions, + LegacyFieldExtensionComponentProps, }; diff --git a/plugins/scaffolder-react/src/legacy/extensions/types.ts b/plugins/scaffolder-react/src/legacy/extensions/types.ts new file mode 100644 index 0000000000..54c38ad2cd --- /dev/null +++ b/plugins/scaffolder-react/src/legacy/extensions/types.ts @@ -0,0 +1,65 @@ +/* + * 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 { ApiHolder } from '@backstage/core-plugin-api'; +import { FieldValidation } from '@rjsf/utils'; +import { + CustomFieldExtensionSchema, + ScaffolderRJSFFieldProps, +} from '@backstage/plugin-scaffolder-react'; + +/** + * Field validation type for Custom Field Extensions. + * + * @alpha + */ +export type LegacyCustomFieldValidator = ( + data: TFieldReturnValue, + field: FieldValidation, + context: { apiHolder: ApiHolder }, +) => void | Promise; + +/** + * Type for the Custom Field Extension with the + * name and components and validation function. + * + * @alpha + */ +export type LegacyFieldExtensionOptions< + TFieldReturnValue = unknown, + TInputProps = unknown, +> = { + name: string; + component: ( + props: LegacyFieldExtensionComponentProps, + ) => JSX.Element | null; + validation?: LegacyCustomFieldValidator; + schema?: CustomFieldExtensionSchema; +}; + +/** + * Type for field extensions and being able to type + * incoming props easier. + * + * @alpha + */ +export interface LegacyFieldExtensionComponentProps< + TFieldReturnValue, + TUiOptions = unknown, +> extends ScaffolderRJSFFieldProps { + uiSchema: ScaffolderRJSFFieldProps['uiSchema'] & { + 'ui:options'?: TUiOptions; + }; +} diff --git a/plugins/scaffolder-react/src/legacy/index.ts b/plugins/scaffolder-react/src/legacy/index.ts new file mode 100644 index 0000000000..c539a8ba60 --- /dev/null +++ b/plugins/scaffolder-react/src/legacy/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './extensions'; diff --git a/plugins/scaffolder-react/src/next/components/Form/Form.tsx b/plugins/scaffolder-react/src/next/components/Form/Form.tsx index 790c9027fe..85e75e2c0d 100644 --- a/plugins/scaffolder-react/src/next/components/Form/Form.tsx +++ b/plugins/scaffolder-react/src/next/components/Form/Form.tsx @@ -14,26 +14,47 @@ * limitations under the License. */ -import { FormProps, withTheme } from '@rjsf/core-v5'; +import { withTheme } from '@rjsf/core'; import React from 'react'; import { PropsWithChildren } from 'react'; import { FieldTemplate } from './FieldTemplate'; import { DescriptionFieldTemplate } from './DescriptionFieldTemplate'; +import { FieldProps } from '@rjsf/utils'; +import { ScaffolderRJSFFormProps } from '@backstage/plugin-scaffolder-react'; +import { Theme as MuiTheme } from '@rjsf/material-ui'; -// TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly -// which is what we're using here as the default types, it needs to depend on @rjsf/core-v5 because -// of the re-writing we're doing. Once we've migrated, we can import this the exact same as before. -const WrappedForm = withTheme(require('@rjsf/material-ui-v5').Theme); +const WrappedForm = withTheme(MuiTheme); /** * The Form component * @alpha */ -export const Form = (props: PropsWithChildren) => { +export const Form = (props: PropsWithChildren) => { + // This is where we unbreak the changes from RJSF, and make it work with our custom fields so we don't pass on this + // breaking change to our users. We will look more into a better API for this in scaffolderv2. + const wrappedFields = Object.fromEntries( + Object.entries(props.fields ?? {}).map(([key, Component]) => [ + key, + (wrapperProps: FieldProps) => { + return ( + + ); + }, + ]), + ); + const templates = { FieldTemplate, DescriptionFieldTemplate, ...props.templates, }; - return ; + + return ( + + ); }; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx index 6183f32a6c..34243e232d 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -20,7 +20,7 @@ import { renderInTestApp } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; import type { RJSFValidationError } from '@rjsf/utils'; import { JsonValue } from '@backstage/types'; -import { NextFieldExtensionComponentProps } from '../../extensions'; +import { FieldExtensionComponentProps } from '../../../extensions'; import { LayoutTemplate } from '../../../layouts'; describe('Stepper', () => { @@ -115,7 +115,7 @@ describe('Stepper', () => { it('should merge nested formData correctly in multiple steps', async () => { const Repo = ({ onChange, - }: NextFieldExtensionComponentProps<{ repository: string }, any>) => ( + }: FieldExtensionComponentProps<{ repository: string }, any>) => ( { const Owner = ({ onChange, - }: NextFieldExtensionComponentProps<{ owner: string }, any>) => ( + }: FieldExtensionComponentProps<{ owner: string }, any>) => ( { />, ); - await act(async () => { - await fireEvent.click(getByRole('button', { name: 'Review' })); - - expect(getByRole('progressbar')).toBeInTheDocument(); - expect(getByRole('button', { name: 'Review' })).toBeDisabled(); + act(() => { + fireEvent.click(getByRole('button', { name: 'Review' })); }); + + expect(getByRole('progressbar')).toBeInTheDocument(); + expect(getByRole('button', { name: 'Review' })).toBeDisabled(); }); it('should transform default error message', async () => { @@ -312,7 +312,7 @@ describe('Stepper', () => { manifest={manifest} extensions={[]} onCreate={jest.fn()} - FormProps={{ transformErrors }} + formProps={{ transformErrors }} />, ); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 9c800b7605..1e43eba770 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -23,18 +23,23 @@ import { makeStyles, LinearProgress, } from '@material-ui/core'; -import { type IChangeEvent } from '@rjsf/core-v5'; +import { type IChangeEvent } from '@rjsf/core'; import { ErrorSchema } from '@rjsf/utils'; -import React, { useCallback, useMemo, useState, type ReactNode } from 'react'; -import { NextFieldExtensionOptions } from '../../extensions'; +import React, { + useCallback, + useMemo, + useState, + type ReactNode, + ComponentType, +} from 'react'; import { createAsyncValidators, type FormValidation, } from './createAsyncValidators'; import { ReviewState, type ReviewStateProps } from '../ReviewState'; -import { useTemplateSchema, useFormDataFromQuery } from '../../hooks'; +import { useTemplateSchema } from '../../hooks/useTemplateSchema'; import validator from '@rjsf/validator-ajv8'; -import { FormProps } from '../../types'; +import { useFormDataFromQuery } from '../../hooks'; import { useTransformSchemaToProps } from '../../hooks/useTransformSchemaToProps'; import { hasErrors } from './utils'; import * as FieldOverrides from './FieldOverrides'; @@ -42,7 +47,10 @@ import { Form } from '../Form'; import { TemplateParameterSchema, LayoutOptions, + FieldExtensionOptions, + FormProps, } from '@backstage/plugin-scaffolder-react'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; const useStyles = makeStyles(theme => ({ backButton: { @@ -65,14 +73,14 @@ const useStyles = makeStyles(theme => ({ */ export type StepperProps = { manifest: TemplateParameterSchema; - extensions: NextFieldExtensionOptions[]; + extensions: FieldExtensionOptions[]; templateName?: string; - FormProps?: FormProps; + formProps?: FormProps; initialState?: Record; onCreate: (values: Record) => Promise; components?: { + ReviewStepComponent?: ComponentType; ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; - backButtonText?: ReactNode; createButtonText?: ReactNode; reviewButtonText?: ReactNode; }; @@ -87,12 +95,12 @@ export const Stepper = (stepperProps: StepperProps) => { const { layouts = [], components = {}, ...props } = stepperProps; const { ReviewStateComponent = ReviewState, - backButtonText = 'Back', + ReviewStepComponent, createButtonText = 'Create', reviewButtonText = 'Review', } = components; const analytics = useAnalytics(); - const { configurations, steps } = useTemplateSchema(props.manifest); + const { steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); const [activeStep, setActiveStep] = useState(0); const [isValidating, setIsValidating] = useState(false); @@ -129,6 +137,13 @@ export const Stepper = (stepperProps: StepperProps) => { [setFormState], ); + const handleCreate = useCallback(() => { + props.onCreate(formState); + const name = + typeof formState.name === 'string' ? formState.name : undefined; + analytics.captureEvent('create', name ?? props.templateName ?? 'unknown'); + }, [props, formState, analytics]); + const currentStep = useTransformSchemaToProps(steps[activeStep], { layouts }); const handleNext = async ({ @@ -158,13 +173,6 @@ export const Stepper = (stepperProps: StepperProps) => { setFormState(current => ({ ...current, ...formData })); }; - const backLabel = - configurations?.buttonLabels?.backButtonText ?? backButtonText; - const createLabel = - configurations?.buttonLabels?.createButtonText ?? createButtonText; - const reviewLabel = - configurations?.buttonLabels?.reviewButtonText ?? reviewButtonText; - return ( <> {isValidating && } @@ -175,10 +183,11 @@ export const Stepper = (stepperProps: StepperProps) => { ))} - ${reviewLabel} + Review
+ {/* eslint-disable-next-line no-nested-ternary */} {activeStep < steps.length ? ( { fields={{ ...FieldOverrides, ...extensions }} showErrorList={false} onChange={handleChange} - {...(props.FormProps ?? {})} + {...(props.formProps ?? {})} >
+ ) : // TODO: potentially move away from this pattern, deprecate? + ReviewStepComponent ? ( + {}} + steps={steps} + handleCreate={handleCreate} + /> ) : ( <> @@ -220,24 +239,14 @@ export const Stepper = (stepperProps: StepperProps) => { className={styles.backButton} disabled={activeStep < 1} > - {configurations?.buttonLabels?.backButtonText ?? backButtonText} + Back
diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts index 3633410769..f4dab376bc 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { JsonObject } from '@backstage/types'; -import { NextCustomFieldValidator } from '../../extensions'; +import { CustomFieldValidator } from '../../../extensions'; import { createAsyncValidators } from './createAsyncValidators'; describe('createAsyncValidators', () => { @@ -158,16 +158,13 @@ describe('createAsyncValidators', () => { }, }; - const NameField: NextCustomFieldValidator = ( - value, - { addError }, - ) => { + const NameField: CustomFieldValidator = (value, { addError }) => { if (!value) { addError('something is broken here!'); } }; - const AddressField: NextCustomFieldValidator<{ + const AddressField: CustomFieldValidator<{ street?: string; postcode?: string; }> = (value, { addError }) => { @@ -183,8 +180,8 @@ describe('createAsyncValidators', () => { const validate = createAsyncValidators( schema, { - NameField: NameField as NextCustomFieldValidator, - AddressField: AddressField as NextCustomFieldValidator, + NameField: NameField as CustomFieldValidator, + AddressField: AddressField as CustomFieldValidator, }, { apiHolder: { get: jest.fn() }, @@ -298,7 +295,7 @@ describe('createAsyncValidators', () => { }, }; - const AddressField: NextCustomFieldValidator<{ + const AddressField: CustomFieldValidator<{ street?: string; postcode?: string; }> = (value, { addError }) => { @@ -311,18 +308,15 @@ describe('createAsyncValidators', () => { } }; - const NameField: NextCustomFieldValidator = ( - value, - { addError }, - ) => { + const NameField: CustomFieldValidator = (value, { addError }) => { if (!value) { addError('something is broken here!'); } }; const validators = { - AddressField: AddressField as NextCustomFieldValidator, - NameField: NameField as NextCustomFieldValidator, + AddressField: AddressField as CustomFieldValidator, + NameField: NameField as CustomFieldValidator, }; const validate = createAsyncValidators(schema, validators, { diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts index ceef701255..f50f44d8f5 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts @@ -19,22 +19,23 @@ import type { JsonObject, JsonValue } from '@backstage/types'; import { ApiHolder } from '@backstage/core-plugin-api'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { createFieldValidation, extractSchemaFromStep } from '../../lib'; -import { NextCustomFieldValidator } from '../../extensions'; +import { + CustomFieldValidator, + FieldExtensionUiSchema, +} from '@backstage/plugin-scaffolder-react'; import { isObject } from './utils'; -import { NextFieldExtensionUiSchema } from '../../extensions/types'; -/** - * @internal - */ +/** @alpha */ export type FormValidation = { [name: string]: FieldValidation | FormValidation; }; +/** @alpha */ export const createAsyncValidators = ( rootSchema: JsonObject, validators: Record< string, - undefined | NextCustomFieldValidator + undefined | CustomFieldValidator >, context: { apiHolder: ApiHolder; @@ -53,7 +54,7 @@ export const createAsyncValidators = ( key: string, value: JsonValue | undefined, schema: JsonObject, - uiSchema: NextFieldExtensionUiSchema, + uiSchema: FieldExtensionUiSchema, ) => { const validator = validators[validatorName]; if (validator) { @@ -82,7 +83,7 @@ export const createAsyncValidators = ( const doValidateItem = async ( propValue: JsonObject, itemSchema: JsonObject, - itemUiSchema: NextFieldExtensionUiSchema, + itemUiSchema: FieldExtensionUiSchema, ) => { await validateForm( propValue['ui:field'] as string, diff --git a/plugins/scaffolder-react/src/next/components/Stepper/index.ts b/plugins/scaffolder-react/src/next/components/Stepper/index.ts index daa47f078e..5f33c2ff78 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/index.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/index.ts @@ -14,3 +14,7 @@ * limitations under the License. */ export { Stepper, type StepperProps } from './Stepper'; +export { + createAsyncValidators, + type FormValidation, +} from './createAsyncValidators'; diff --git a/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx index ce6e342809..f3a6a99c42 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx @@ -20,6 +20,7 @@ import { TemplateCategoryPicker } from './TemplateCategoryPicker'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { alertApiRef } from '@backstage/core-plugin-api'; import { fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; jest.mock('@backstage/plugin-catalog-react', () => ({ useEntityTypeFilter: jest.fn(), @@ -91,7 +92,7 @@ describe('TemplateCategoryPicker', () => { ); const openButton = getByRole('button', { name: 'Open' }); - openButton.click(); + await userEvent.click(openButton); expect(getByRole('checkbox', { name: 'Foo' })).toBeInTheDocument(); expect(getByRole('checkbox', { name: 'Bar' })).toBeInTheDocument(); diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx index 894c6ea4d0..66c9d01ffd 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx @@ -18,7 +18,7 @@ jest.mock('@backstage/plugin-catalog-react', () => ({ useEntityList: jest.fn(), })); -jest.mock('@backstage/plugin-scaffolder-react/alpha', () => ({ +jest.mock('../TemplateGroup/TemplateGroup', () => ({ TemplateGroup: jest.fn(() => null), })); @@ -27,7 +27,7 @@ import { useEntityList } from '@backstage/plugin-catalog-react'; import { TemplateGroups } from './TemplateGroups'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { errorApiRef } from '@backstage/core-plugin-api'; -import { TemplateGroup } from '@backstage/plugin-scaffolder-react/alpha'; +import { TemplateGroup } from '../TemplateGroup/TemplateGroup'; describe('TemplateGroups', () => { beforeEach(() => jest.clearAllMocks()); diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx index f0f06b3410..800ec67a16 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx @@ -23,15 +23,8 @@ import { import { Progress, Link } from '@backstage/core-components'; import { Typography } from '@material-ui/core'; import { errorApiRef, IconComponent, useApi } from '@backstage/core-plugin-api'; -import { TemplateGroup } from '@backstage/plugin-scaffolder-react/alpha'; - -/** - * @alpha - */ -export type TemplateGroupFilter = { - title?: React.ReactNode; - filter: (entity: TemplateEntityV1beta3) => boolean; -}; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; +import { TemplateGroup } from '../TemplateGroup/TemplateGroup'; /** * @alpha diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 228f5cefd9..e7c56378a7 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -27,6 +27,7 @@ import { errorApiRef, useApi } from '@backstage/core-plugin-api'; import { useTemplateParameterSchema } from '../../hooks/useTemplateParameterSchema'; import { Stepper, type StepperProps } from '../Stepper/Stepper'; import { SecretsContextProvider } from '../../../secrets/SecretsContext'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; const useStyles = makeStyles(() => ({ markdown: { @@ -48,11 +49,14 @@ export type WorkflowProps = { description?: string; namespace: string; templateName: string; + components?: { + ReviewStepComponent?: React.ComponentType; + }; onError(error: Error | undefined): JSX.Element | null; } & Pick< StepperProps, | 'extensions' - | 'FormProps' + | 'formProps' | 'components' | 'onCreate' | 'initialState' diff --git a/plugins/scaffolder-react/src/next/extensions/types.ts b/plugins/scaffolder-react/src/next/extensions/types.ts deleted file mode 100644 index 803dcb2be6..0000000000 --- a/plugins/scaffolder-react/src/next/extensions/types.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 { ApiHolder } from '@backstage/core-plugin-api'; -import { - UIOptionsType, - FieldProps as FieldPropsV5, - UiSchema as UiSchemaV5, - FieldValidation as FieldValidationV5, -} from '@rjsf/utils'; -import { PropsWithChildren } from 'react'; -import { JsonObject } from '@backstage/types'; -import { CustomFieldExtensionSchema } from '@backstage/plugin-scaffolder-react'; - -/** - * Type for Field Extension Props for RJSF v5 - * - * @alpha - */ -export interface NextFieldExtensionComponentProps< - TFieldReturnValue, - TUiOptions = {}, -> extends PropsWithChildren> { - uiSchema?: NextFieldExtensionUiSchema; -} - -/** - * Type for Field Extension UiSchema - * - * @alpha - */ -export interface NextFieldExtensionUiSchema - extends UiSchemaV5 { - 'ui:options'?: TUiOptions & UIOptionsType; -} - -/** - * Field validation type for Custom Field Extensions. - * - * @alpha - */ -export type NextCustomFieldValidator< - TFieldReturnValue, - TUiOptions = unknown, -> = ( - data: TFieldReturnValue, - field: FieldValidationV5, - context: { - apiHolder: ApiHolder; - formData: JsonObject; - schema: JsonObject; - uiSchema?: NextFieldExtensionUiSchema; - }, -) => void | Promise; - -/** - * Type for the Custom Field Extension with the - * name and components and validation function. - * - * @alpha - */ -export type NextFieldExtensionOptions< - TFieldReturnValue = unknown, - TUiOptions = unknown, -> = { - name: string; - component: ( - props: NextFieldExtensionComponentProps, - ) => JSX.Element | null; - validation?: NextCustomFieldValidator; - schema?: CustomFieldExtensionSchema; -}; diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx index 9a0732442c..d2771b2eb9 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { useTemplateSchema } from './useTemplateSchema'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { TestApiProvider } from '@backstage/test-utils'; import React from 'react'; import { featureFlagsApiRef } from '@backstage/core-plugin-api'; diff --git a/plugins/scaffolder-react/src/next/hooks/useTransformSchemaToProps.test.tsx b/plugins/scaffolder-react/src/next/hooks/useTransformSchemaToProps.test.tsx index 7ee5cbfdfd..4138c8cde0 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTransformSchemaToProps.test.tsx +++ b/plugins/scaffolder-react/src/next/hooks/useTransformSchemaToProps.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React, { PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { TestApiProvider } from '@backstage/test-utils'; import { type ParsedTemplateSchema } from './useTemplateSchema'; import { useTransformSchemaToProps } from './useTransformSchemaToProps'; diff --git a/plugins/scaffolder-react/src/next/index.ts b/plugins/scaffolder-react/src/next/index.ts index a18649f506..f13bb76d7a 100644 --- a/plugins/scaffolder-react/src/next/index.ts +++ b/plugins/scaffolder-react/src/next/index.ts @@ -14,7 +14,5 @@ * limitations under the License. */ export * from './components'; -export * from './extensions'; -export * from './types'; export * from './lib'; export * from './hooks'; diff --git a/plugins/scaffolder-react/src/secrets/SecretsContext.test.tsx b/plugins/scaffolder-react/src/secrets/SecretsContext.test.tsx index 553f27d2a9..4d56b5764c 100644 --- a/plugins/scaffolder-react/src/secrets/SecretsContext.test.tsx +++ b/plugins/scaffolder-react/src/secrets/SecretsContext.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; import { useTemplateSecrets, SecretsContextProvider } from './SecretsContext'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; describe('SecretsContext', () => { it('should allow the setting of secrets in the context', async () => { diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index f32e05eed7..2f681837ea 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder +## 1.15.1 + +### Patch Changes + +- b337d78c3b: fixed issue related template editor fails with multiple templates per file. +- ff2ab02690: Make entity picker more reliable with only one available entity +- 83e4a42ccd: Display log visibility button on the template panel +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 4c70fe497d: `RepoUrlPickerRepoName` now correctly handles value changes in allowed repos. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-permission-react@0.4.16 + - @backstage/plugin-scaffolder-react@1.5.6 + - @backstage/theme@0.4.3 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-scaffolder-common@1.4.2 + ## 1.15.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder/alpha-api-report.md b/plugins/scaffolder/alpha-api-report.md index 8cacf6105e..55d14bff75 100644 --- a/plugins/scaffolder/alpha-api-report.md +++ b/plugins/scaffolder/alpha-api-report.md @@ -5,50 +5,58 @@ ```ts /// -import { FormProps as FormProps_2 } from '@backstage/plugin-scaffolder-react/alpha'; -import type { FormProps as FormProps_3 } from '@rjsf/core-v5'; +import { ComponentType } from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; +import type { FormProps as FormProps_2 } from '@rjsf/core'; +import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; import { JSX as JSX_2 } from 'react'; import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; -import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; -import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react/alpha'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; // @alpha @deprecated export type FormProps = Pick< - FormProps_3, + FormProps_2, 'transformErrors' | 'noHtml5Validate' >; // @alpha -export type NextRouterProps = { +export const LegacyRouter: (props: LegacyRouterProps) => React_2.JSX.Element; + +// @alpha +export type LegacyRouterProps = { components?: { - TemplateCardComponent?: React_2.ComponentType<{ - template: TemplateEntityV1beta3; - }>; - TaskPageComponent?: React_2.ComponentType>; - TemplateOutputsComponent?: React_2.ComponentType<{ - output?: ScaffolderTaskOutput; - }>; - TemplateListPageComponent?: React_2.ComponentType; - TemplateWizardPageComponent?: React_2.ComponentType; + ReviewStepComponent?: ComponentType; + TemplateCardComponent?: + | ComponentType<{ + template: TemplateEntityV1beta3; + }> + | undefined; + TaskPageComponent?: ComponentType>; }; - groups?: TemplateGroupFilter[]; + groups?: Array<{ + title?: React_2.ReactNode; + filter: (entity: Entity) => boolean; + }>; templateFilter?: (entity: TemplateEntityV1beta3) => boolean; - FormProps?: FormProps_2; + defaultPreviewTemplate?: string; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; contextMenu?: { editor?: boolean; actions?: boolean; - tasks?: boolean; }; }; // @alpha -export const NextScaffolderPage: ( - props: PropsWithChildren, -) => JSX_2.Element; +export const LegacyScaffolderPage: (props: LegacyRouterProps) => JSX_2.Element; // @alpha (undocumented) export type TemplateListPageProps = { @@ -66,9 +74,12 @@ export type TemplateListPageProps = { // @alpha (undocumented) export type TemplateWizardPageProps = { - customFieldExtensions: NextFieldExtensionOptions[]; + customFieldExtensions: FieldExtensionOptions[]; + components?: { + ReviewStepComponent?: React_2.ComponentType; + }; layouts?: LayoutOptions[]; - FormProps?: FormProps_2; + formProps?: FormProps_3; }; // (No @packageDocumentation comment for this package) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index ddda40d95f..6f8479990b 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -14,15 +14,14 @@ import { createScaffolderLayout as createScaffolderLayout_2 } from '@backstage/p import { CustomFieldExtensionSchema as CustomFieldExtensionSchema_2 } from '@backstage/plugin-scaffolder-react'; import { CustomFieldValidator as CustomFieldValidator_2 } from '@backstage/plugin-scaffolder-react'; import { DiscoveryApi } from '@backstage/core-plugin-api'; -import { Entity } from '@backstage/catalog-model'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; import { FieldExtensionComponent as FieldExtensionComponent_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionComponentProps as FieldExtensionComponentProps_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionOptions as FieldExtensionOptions_2 } from '@backstage/plugin-scaffolder-react'; -import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/utils'; +import { FormProps } from '@backstage/plugin-scaffolder-react'; import { IdentityApi } from '@backstage/core-plugin-api'; -import { JsonObject } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; import { LayoutOptions as LayoutOptions_2 } from '@backstage/plugin-scaffolder-react'; import { LayoutTemplate as LayoutTemplate_2 } from '@backstage/plugin-scaffolder-react'; @@ -33,6 +32,7 @@ import { PathParams } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { RouteRef } from '@backstage/core-plugin-api'; import { ScaffolderApi as ScaffolderApi_2 } from '@backstage/plugin-scaffolder-react'; import { ScaffolderDryRunOptions as ScaffolderDryRunOptions_2 } from '@backstage/plugin-scaffolder-react'; @@ -50,8 +50,10 @@ import { ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecrets_2 } from ' import { ScmIntegrationRegistry } from '@backstage/integration'; import { SubRouteRef } from '@backstage/core-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; +import { TemplateListPageProps } from '@backstage/plugin-scaffolder/alpha'; import { TemplateParameterSchema as TemplateParameterSchema_2 } from '@backstage/plugin-scaffolder-react'; -import { UiSchema } from '@rjsf/utils'; +import { TemplateWizardPageProps } from '@backstage/plugin-scaffolder/alpha'; import { z } from 'zod'; // @public @deprecated (undocumented) @@ -419,19 +421,7 @@ export const RepoUrlPickerFieldSchema: FieldSchema< export type RepoUrlPickerUiOptions = typeof RepoUrlPickerFieldSchema.uiOptionsType; -// @public -export type ReviewStepProps = { - disableButtons: boolean; - formData: JsonObject; - handleBack: () => void; - handleReset: () => void; - handleCreate: () => void; - steps: { - uiSchema: UiSchema; - mergedSchema: JsonObject; - schema: JsonObject; - }[]; -}; +export { ReviewStepProps }; // @public @deprecated (undocumented) export const rootRouteRef: RouteRef; @@ -439,28 +429,30 @@ export const rootRouteRef: RouteRef; // @public export type RouterProps = { components?: { - ReviewStepComponent?: ComponentType; - TemplateCardComponent?: - | ComponentType<{ - template: TemplateEntityV1beta3; - }> - | undefined; - TaskPageComponent?: ComponentType>; + ReviewStepComponent?: React_2.ComponentType; + TemplateCardComponent?: React_2.ComponentType<{ + template: TemplateEntityV1beta3; + }>; + TaskPageComponent?: React_2.ComponentType>; + EXPERIMENTAL_TemplateOutputsComponent?: React_2.ComponentType<{ + output?: ScaffolderTaskOutput_2; + }>; + EXPERIMENTAL_TemplateListPageComponent?: React_2.ComponentType; + EXPERIMENTAL_TemplateWizardPageComponent?: React_2.ComponentType; }; - groups?: Array<{ - title?: React_2.ReactNode; - filter: (entity: Entity) => boolean; - }>; + groups?: TemplateGroupFilter[]; templateFilter?: (entity: TemplateEntityV1beta3) => boolean; - defaultPreviewTemplate?: string; headerOptions?: { pageTitleOverride?: string; title?: string; subtitle?: string; }; + defaultPreviewTemplate?: string; + formProps?: FormProps; contextMenu?: { editor?: boolean; actions?: boolean; + tasks?: boolean; }; }; @@ -537,7 +529,9 @@ export const ScaffolderLayouts: ComponentType<{ export type ScaffolderOutputlink = ScaffolderOutputLink; // @public -export const ScaffolderPage: (props: RouterProps) => JSX_2.Element; +export const ScaffolderPage: ( + props: PropsWithChildren, +) => JSX_2.Element; // @public export const scaffolderPlugin: BackstagePlugin< @@ -585,10 +579,14 @@ export type ScaffolderTaskStatus = ScaffolderTaskStatus_2; // @public @deprecated (undocumented) export type ScaffolderUseTemplateSecrets = ScaffolderUseTemplateSecrets_2; -// @public -export const TaskPage: (props: TaskPageProps) => React_2.JSX.Element; +// @public (undocumented) +export const TaskPage: (props: { + TemplateOutputsComponent?: React_2.ComponentType<{ + output?: ScaffolderTaskOutput_2; + }>; +}) => React_2.JSX.Element; -// @public +// @public @deprecated export type TaskPageProps = { loadingText?: string; }; diff --git a/plugins/scaffolder/dev/index.tsx b/plugins/scaffolder/dev/index.tsx index 68c59eec2d..b683345ff5 100644 --- a/plugins/scaffolder/dev/index.tsx +++ b/plugins/scaffolder/dev/index.tsx @@ -24,7 +24,7 @@ import { } from '@backstage/plugin-catalog-react'; import React from 'react'; import { scaffolderApiRef, ScaffolderClient } from '../src'; -import { NextScaffolderPage, ScaffolderPage } from '../src/plugin'; +import { ScaffolderPage, LegacyScaffolderPage } from '../src/plugin'; import { discoveryApiRef, fetchApiRef, @@ -69,9 +69,9 @@ createDevApp() element: , }) .addPage({ - path: '/next-create', + path: '/legacy-create', title: 'Create (next)', - element: , + element: , }) .addPage({ path: '/create-groups', @@ -92,10 +92,10 @@ createDevApp() ), }) .addPage({ - path: '/next-create-groups', + path: '/legacy-create-groups', title: 'Groups (next)', element: ( - e.metadata.tags?.includes('techdocs') || false, diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 68066a5a79..d36ce86acc 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.15.1-next.2", + "version": "1.15.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -68,8 +68,8 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", - "@rjsf/core": "^3.2.1", - "@rjsf/material-ui": "^3.2.1", + "@rjsf/core": "5.13.0", + "@rjsf/material-ui": "5.13.0", "@rjsf/utils": "5.13.0", "@rjsf/validator-ajv8": "5.13.0", "@types/react": "^16.13.1 || ^17.0.0", @@ -92,8 +92,8 @@ "zod-to-json-schema": "^3.20.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -104,8 +104,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/humanize-duration": "^3.18.1", "@types/json-schema": "^7.0.9", diff --git a/plugins/scaffolder/src/alpha.ts b/plugins/scaffolder/src/alpha.ts index d2bd762190..92ec945de4 100644 --- a/plugins/scaffolder/src/alpha.ts +++ b/plugins/scaffolder/src/alpha.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -export { NextScaffolderPage } from './plugin'; export { - type NextRouterProps, type FormProps, type TemplateListPageProps, type TemplateWizardPageProps, } from './next'; + +export * from './legacy'; diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx index a402e078a8..614e3fcff0 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx @@ -22,6 +22,7 @@ import { import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { ApiProvider } from '@backstage/core-app-api'; import { rootRouteRef } from '../../routes'; +import { userEvent } from '@testing-library/user-event'; const scaffolderApiMock: jest.Mocked = { scaffold: jest.fn(), @@ -261,7 +262,7 @@ describe('TemplatePage', () => { expect(rendered.queryByText('nested prop b')).not.toBeInTheDocument(); expect(rendered.queryByText('number')).not.toBeInTheDocument(); - objectChip.click(); + await userEvent.click(objectChip); expect(rendered.queryByText('nested prop a')).toBeInTheDocument(); expect(rendered.queryByText('string')).toBeInTheDocument(); @@ -323,7 +324,7 @@ describe('TemplatePage', () => { expect(rendered.queryByText('nested prop b')).not.toBeInTheDocument(); expect(rendered.queryByText('nested object c')).not.toBeInTheDocument(); - objectChip.click(); + await userEvent.click(objectChip); expect(rendered.queryByText('nested object a')).toBeInTheDocument(); expect(rendered.queryByText('nested prop b')).toBeInTheDocument(); @@ -331,7 +332,7 @@ describe('TemplatePage', () => { const allObjectChips = rendered.getAllByText('object'); expect(allObjectChips.length).toBe(2); - allObjectChips[1].click(); + await userEvent.click(allObjectChips[1]); expect(rendered.queryByText('nested object a')).toBeInTheDocument(); expect(rendered.queryByText('nested prop b')).toBeInTheDocument(); @@ -374,7 +375,7 @@ describe('TemplatePage', () => { expect(rendered.queryByText('No schema defined')).not.toBeInTheDocument(); - objectChip.click(); + await userEvent.click(objectChip); expect(rendered.queryByText('No schema defined')).toBeInTheDocument(); }); @@ -471,7 +472,7 @@ describe('TemplatePage', () => { expect(rendered.queryByText('nested object a')).not.toBeInTheDocument(); expect(rendered.queryByText('nested prop b')).not.toBeInTheDocument(); - objectChip.click(); + await userEvent.click(objectChip); expect(rendered.queryByText('nested object a')).toBeInTheDocument(); expect(rendered.queryByText('nested prop b')).toBeInTheDocument(); diff --git a/plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx similarity index 100% rename from plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx rename to plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx similarity index 100% rename from plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx rename to plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx similarity index 99% rename from plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx rename to plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx index b483cd27cb..cc988599a0 100644 --- a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx @@ -51,6 +51,9 @@ const useStyles = makeStyles(theme => ({ }, })); +/** + * @public + */ export const OngoingTask = (props: { TemplateOutputsComponent?: React.ComponentType<{ output?: ScaffolderTaskOutput; diff --git a/plugins/scaffolder/src/next/OngoingTask/index.ts b/plugins/scaffolder/src/components/OngoingTask/index.ts similarity index 100% rename from plugins/scaffolder/src/next/OngoingTask/index.ts rename to plugins/scaffolder/src/components/OngoingTask/index.ts diff --git a/plugins/scaffolder/src/next/Router/Router.test.tsx b/plugins/scaffolder/src/components/Router/Router.test.tsx similarity index 91% rename from plugins/scaffolder/src/next/Router/Router.test.tsx rename to plugins/scaffolder/src/components/Router/Router.test.tsx index 3d52dd0dd0..8c301b55fb 100644 --- a/plugins/scaffolder/src/next/Router/Router.test.tsx +++ b/plugins/scaffolder/src/components/Router/Router.test.tsx @@ -14,8 +14,6 @@ * limitations under the License. */ import React from 'react'; -import { TemplateListPage } from '../TemplateListPage'; -import { TemplateWizardPage } from '../TemplateWizardPage'; import { Router } from './Router'; import { renderInTestApp } from '@backstage/test-utils'; import { @@ -27,13 +25,11 @@ import { createScaffolderLayout, ScaffolderLayouts, } from '@backstage/plugin-scaffolder-react'; +import { TemplateListPage, TemplateWizardPage } from '../../next'; -jest.mock('../TemplateListPage', () => ({ - TemplateListPage: jest.fn(() => null), -})); - -jest.mock('../TemplateWizardPage', () => ({ +jest.mock('../../next', () => ({ TemplateWizardPage: jest.fn(() => null), + TemplateListPage: jest.fn(() => null), })); describe('Router', () => { @@ -52,7 +48,7 @@ describe('Router', () => { const { getByText } = await renderInTestApp( <>foobar, + EXPERIMENTAL_TemplateListPageComponent: () => <>foobar, }} />, { @@ -77,7 +73,7 @@ describe('Router', () => { const { getByText } = await renderInTestApp( <>foobar, + EXPERIMENTAL_TemplateWizardPageComponent: () => <>foobar, }} />, { @@ -93,7 +89,7 @@ describe('Router', () => { await renderInTestApp( { const mock = TemplateWizardPage as jest.Mock; - const [{ FormProps }] = mock.mock.calls[0]; + const [{ formProps }] = mock.mock.calls[0]; - expect(FormProps).toEqual({ + expect(formProps).toEqual({ transformErrors: transformErrorsMock, noHtml5Validate: true, }); diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx similarity index 74% rename from plugins/scaffolder/src/next/Router/Router.tsx rename to plugins/scaffolder/src/components/Router/Router.tsx index 2061cd1243..dede51d676 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -15,16 +15,13 @@ */ import React, { PropsWithChildren } from 'react'; import { Routes, Route, useOutlet } from 'react-router-dom'; -import { TemplateListPage, TemplateListPageProps } from '../TemplateListPage'; + import { - TemplateWizardPage, - TemplateWizardPageProps, -} from '../TemplateWizardPage'; -import { - NextFieldExtensionOptions, + FieldExtensionOptions, FormProps, + ReviewStepProps, TemplateGroupFilter, -} from '@backstage/plugin-scaffolder-react/alpha'; +} from '@backstage/plugin-scaffolder-react'; import { ScaffolderTaskOutput, SecretsContextProvider, @@ -43,32 +40,45 @@ import { selectedTemplateRouteRef, } from '../../routes'; import { ErrorPage } from '@backstage/core-components'; -import { OngoingTask } from '../OngoingTask'; + import { ActionsPage } from '../../components/ActionsPage'; import { ListTasksPage } from '../../components/ListTasksPage'; -import { TemplateEditorPage } from '../TemplateEditorPage'; + +import { + TemplateListPageProps, + TemplateWizardPageProps, +} from '@backstage/plugin-scaffolder/alpha'; +import { TemplateListPage, TemplateWizardPage } from '../../next'; +import { OngoingTask } from '../OngoingTask'; +import { TemplateEditorPage } from '../../next/TemplateEditorPage'; /** * The Props for the Scaffolder Router * - * @alpha + * @public */ -export type NextRouterProps = { +export type RouterProps = { components?: { + ReviewStepComponent?: React.ComponentType; TemplateCardComponent?: React.ComponentType<{ template: TemplateEntityV1beta3; }>; TaskPageComponent?: React.ComponentType>; - TemplateOutputsComponent?: React.ComponentType<{ + EXPERIMENTAL_TemplateOutputsComponent?: React.ComponentType<{ output?: ScaffolderTaskOutput; }>; - TemplateListPageComponent?: React.ComponentType; - TemplateWizardPageComponent?: React.ComponentType; + EXPERIMENTAL_TemplateListPageComponent?: React.ComponentType; + EXPERIMENTAL_TemplateWizardPageComponent?: React.ComponentType; }; groups?: TemplateGroupFilter[]; templateFilter?: (entity: TemplateEntityV1beta3) => boolean; - // todo(blam): rename this to formProps - FormProps?: FormProps; + headerOptions?: { + pageTitleOverride?: string; + title?: string; + subtitle?: string; + }; + defaultPreviewTemplate?: string; + formProps?: FormProps; contextMenu?: { /** Whether to show a link to the template editor */ editor?: boolean; @@ -82,21 +92,24 @@ export type NextRouterProps = { /** * The Scaffolder Router * - * @alpha + * @public */ -export const Router = (props: PropsWithChildren) => { +export const Router = (props: PropsWithChildren) => { const { components: { TemplateCardComponent, - TemplateOutputsComponent, TaskPageComponent = OngoingTask, - TemplateListPageComponent = TemplateListPage, - TemplateWizardPageComponent = TemplateWizardPage, + ReviewStepComponent, + EXPERIMENTAL_TemplateOutputsComponent: TemplateOutputsComponent, + EXPERIMENTAL_TemplateListPageComponent: + TemplateListPageComponent = TemplateListPage, + EXPERIMENTAL_TemplateWizardPageComponent: + TemplateWizardPageComponent = TemplateWizardPage, } = {}, } = props; const outlet = useOutlet() || props.children; const customFieldExtensions = - useCustomFieldExtensions(outlet); + useCustomFieldExtensions(outlet); const fieldExtensions = [ ...customFieldExtensions, @@ -106,7 +119,7 @@ export const Router = (props: PropsWithChildren) => { customFieldExtension => customFieldExtension.name === name, ), ), - ] as NextFieldExtensionOptions[]; + ] as FieldExtensionOptions[]; const customLayouts = useCustomLayouts(outlet); @@ -130,7 +143,8 @@ export const Router = (props: PropsWithChildren) => { } diff --git a/plugins/stack-overflow-backend/src/search/index.ts b/plugins/scaffolder/src/components/Router/index.ts similarity index 91% rename from plugins/stack-overflow-backend/src/search/index.ts rename to plugins/scaffolder/src/components/Router/index.ts index ed3e05cb28..afe51fbdc9 100644 --- a/plugins/stack-overflow-backend/src/search/index.ts +++ b/plugins/scaffolder/src/components/Router/index.ts @@ -13,5 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export * from './StackOverflowQuestionsCollatorFactory'; +export { Router, type RouterProps } from './Router'; diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.test.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.test.tsx deleted file mode 100644 index bf9cd8c464..0000000000 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 { 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 from 'react'; -import { TemplateEditorPage } from './TemplateEditorPage'; - -describe('TemplateEditorPage', () => { - it('renders without exploding', async () => { - await renderInTestApp(); - - expect(screen.getByText('Load Template Directory')).toBeInTheDocument(); - expect(screen.getByText('Edit Template Form')).toBeInTheDocument(); - }); - - it('template directory loading should not be supported in Jest', async () => { - await renderInTestApp(); - - expect( - screen.getByRole('button', { name: /Load Template Directory/ }), - ).toBeDisabled(); - }); - - it('should be able to continue to form preview', async () => { - await renderInTestApp( - - - , - ); - - await userEvent.click(screen.getByText('Edit Template Form')); - - expect(screen.getByLabelText('Load Existing Template')).toBeInTheDocument(); - }); -}); diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.test.ts b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.test.ts index 290650387e..7201c9c4b3 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.test.ts +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/utils'; import { KubernetesValidatorFunctions } from '@backstage/catalog-model'; import { entityNamePickerValidation } from './validation'; diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts index d116bef228..9302e9abc1 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/utils'; import { KubernetesValidatorFunctions } from '@backstage/catalog-model'; export const entityNamePickerValidation = ( diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx index cbc587a732..4329b2208b 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx @@ -18,11 +18,12 @@ import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { FieldProps } from '@rjsf/core'; + import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; import { EntityPicker } from './EntityPicker'; import { EntityPickerProps } from './schema'; +import { ScaffolderRJSFFieldProps as FieldProps } from '@backstage/plugin-scaffolder-react'; const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ apiVersion: 'scaffolder.backstage.io/v1beta3', @@ -39,7 +40,7 @@ describe('', () => { const rawErrors: string[] = []; const formData = undefined; - let props: FieldProps; + let props: FieldProps; const catalogApi: jest.Mocked = { getLocationById: jest.fn(), @@ -76,7 +77,7 @@ describe('', () => { uiSchema, rawErrors, formData, - } as unknown as FieldProps; + } as unknown as FieldProps; catalogApi.getEntities.mockResolvedValue({ items: entities }); }); diff --git a/plugins/scaffolder/src/components/fields/MyGroupsPicker/MyGroupsPicker.test.tsx b/plugins/scaffolder/src/components/fields/MyGroupsPicker/MyGroupsPicker.test.tsx index 099d6fa6ed..521c4029b3 100644 --- a/plugins/scaffolder/src/components/fields/MyGroupsPicker/MyGroupsPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/MyGroupsPicker/MyGroupsPicker.test.tsx @@ -17,7 +17,6 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { CatalogApi } from '@backstage/catalog-client'; -import { FieldProps } from '@rjsf/core'; import { MyGroupsPicker } from './MyGroupsPicker'; import { TestApiProvider } from '@backstage/test-utils'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; @@ -29,6 +28,7 @@ import { identityApiRef, } from '@backstage/core-plugin-api'; import userEvent from '@testing-library/user-event'; +import { ScaffolderRJSFFieldProps as FieldProps } from '@backstage/plugin-scaffolder-react'; // Create a mock IdentityApi const mockIdentityApi: IdentityApi = { @@ -109,7 +109,7 @@ describe('', () => { onChange, schema, required, - } as unknown as FieldProps; + } as unknown as FieldProps; render( ', () => { onChange, schema, required, - } as unknown as FieldProps; + } as unknown as FieldProps; const { queryByText, getByRole } = render( ', () => { onChange, schema, required, - } as unknown as FieldProps; + } as unknown as FieldProps; const { getByRole } = render( ', () => { const rawErrors: string[] = []; const formData = undefined; - let props: FieldProps; + let props: FieldProps; const catalogApi: jest.Mocked = { getLocationById: jest.fn(), diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index 4b44a4fa3e..da86e6e4b8 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -15,7 +15,8 @@ */ import React from 'react'; import { RepoUrlPicker } from './RepoUrlPicker'; -import Form from '@rjsf/core'; +import { Form } from '@backstage/plugin-scaffolder-react/alpha'; +import validator from '@rjsf/validator-ajv8'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { scmIntegrationsApiRef, @@ -29,6 +30,7 @@ import { scaffolderApiRef, ScaffolderApi, useTemplateSecrets, + ScaffolderRJSFField, } from '@backstage/plugin-scaffolder-react'; import { act, fireEvent } from '@testing-library/react'; @@ -73,9 +75,12 @@ describe('RepoUrlPicker', () => { >
, + }} onSubmit={onSubmit} /> @@ -109,12 +114,15 @@ describe('RepoUrlPicker', () => { > , + }} /> , @@ -144,6 +152,7 @@ describe('RepoUrlPicker', () => { > { }, }, }} - fields={{ RepoUrlPicker: RepoUrlPicker }} + fields={{ + RepoUrlPicker: RepoUrlPicker as ScaffolderRJSFField, + }} /> @@ -206,6 +217,7 @@ describe('RepoUrlPicker', () => { > { }, }, }} - fields={{ RepoUrlPicker: RepoUrlPicker }} + fields={{ + RepoUrlPicker: RepoUrlPicker as ScaffolderRJSFField, + }} /> @@ -259,6 +273,7 @@ describe('RepoUrlPicker', () => { > { }, }, }} - fields={{ RepoUrlPicker: RepoUrlPicker }} + fields={{ + RepoUrlPicker: RepoUrlPicker as ScaffolderRJSFField, + }} /> diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts index 45e44b4072..b9c481957c 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.test.ts @@ -15,7 +15,7 @@ */ import { repoPickerValidation } from './validation'; -import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/utils'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/core-app-api'; import { ApiHolder } from '@backstage/core-plugin-api'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts index 99847f9e3b..55ba92abdc 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/validation.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/utils'; import { ApiHolder } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; diff --git a/plugins/scaffolder/src/components/index.ts b/plugins/scaffolder/src/components/index.ts index a5c17b8ab0..fd8c11e2da 100644 --- a/plugins/scaffolder/src/components/index.ts +++ b/plugins/scaffolder/src/components/index.ts @@ -15,7 +15,12 @@ */ export * from './fields'; export type { RepoUrlPickerUiOptions } from './fields'; + export { TemplateTypePicker } from './TemplateTypePicker'; -export { TaskPage, type TaskPageProps } from './TaskPage'; + export type { RouterProps } from './Router'; -export type { ReviewStepProps } from './types'; +export { OngoingTask as TaskPage } from './OngoingTask'; + +export type { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; + +export type { TaskPageProps } from '../legacy/TaskPage'; diff --git a/plugins/scaffolder/src/components/types.ts b/plugins/scaffolder/src/components/types.ts index f5989a2ae1..b1e99a84e6 100644 --- a/plugins/scaffolder/src/components/types.ts +++ b/plugins/scaffolder/src/components/types.ts @@ -13,25 +13,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { UiSchema } from '@rjsf/utils'; -import { JsonObject } from '@backstage/types'; - -/** - * The props for the Last Step in scaffolder template form. - * Which represents the summary of the input provided by the end user. - * - * @public - */ -export type ReviewStepProps = { - disableButtons: boolean; - formData: JsonObject; - handleBack: () => void; - handleReset: () => void; - handleCreate: () => void; - steps: { - uiSchema: UiSchema; - mergedSchema: JsonObject; - schema: JsonObject; - }[]; -}; diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/FieldOverrides/DescriptionField.tsx b/plugins/scaffolder/src/legacy/MultistepJsonForm/FieldOverrides/DescriptionField.tsx similarity index 95% rename from plugins/scaffolder/src/components/MultistepJsonForm/FieldOverrides/DescriptionField.tsx rename to plugins/scaffolder/src/legacy/MultistepJsonForm/FieldOverrides/DescriptionField.tsx index 3c592860ef..eded38beee 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/FieldOverrides/DescriptionField.tsx +++ b/plugins/scaffolder/src/legacy/MultistepJsonForm/FieldOverrides/DescriptionField.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { MarkdownContent } from '@backstage/core-components'; -import { FieldProps } from '@rjsf/core'; +import { FieldProps } from '@rjsf/utils'; export const DescriptionField = ({ description }: FieldProps) => description && ; diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/FieldOverrides/index.ts b/plugins/scaffolder/src/legacy/MultistepJsonForm/FieldOverrides/index.ts similarity index 100% rename from plugins/scaffolder/src/components/MultistepJsonForm/FieldOverrides/index.ts rename to plugins/scaffolder/src/legacy/MultistepJsonForm/FieldOverrides/index.ts diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx b/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx rename to plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.test.tsx diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx similarity index 95% rename from plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx rename to plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx index d8299a9b5f..312522bc88 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/legacy/MultistepJsonForm/MultistepJsonForm.tsx @@ -29,17 +29,20 @@ import { useRouteRefParams, useApi, } from '@backstage/core-plugin-api'; -import { FormProps, IChangeEvent, ISubmitEvent, withTheme } from '@rjsf/core'; +import { FormProps, IChangeEvent, withTheme } from '@rjsf/core'; import { Theme as MuiTheme } from '@rjsf/material-ui'; import React, { ComponentType, useState } from 'react'; import { transformSchemaToProps } from './schema'; import cloneDeep from 'lodash/cloneDeep'; import * as fieldOverrides from './FieldOverrides'; -import { ReviewStepProps } from '../types'; import { ReviewStep } from './ReviewStep'; +import validator from '@rjsf/validator-ajv8'; import { extractSchemaFromStep } from '@backstage/plugin-scaffolder-react/alpha'; import { selectedTemplateRouteRef } from '../../routes'; -import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { + LayoutOptions, + ReviewStepProps, +} from '@backstage/plugin-scaffolder-react'; const Form = withTheme(MuiTheme); @@ -178,6 +181,7 @@ export const MultistepJsonForm = (props: MultistepJsonFormProps) => { { formData={formData} formContext={{ formData }} onChange={onChange} - onSubmit={(e: ISubmitEvent) => { + onSubmit={(e: IChangeEvent) => { if (e.errors.length === 0) handleNext(); }} {...formProps} diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/ReviewStep.tsx b/plugins/scaffolder/src/legacy/MultistepJsonForm/ReviewStep.tsx similarity index 96% rename from plugins/scaffolder/src/components/MultistepJsonForm/ReviewStep.tsx rename to plugins/scaffolder/src/legacy/MultistepJsonForm/ReviewStep.tsx index 112b96bdf1..c3b244e921 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/ReviewStep.tsx +++ b/plugins/scaffolder/src/legacy/MultistepJsonForm/ReviewStep.tsx @@ -16,9 +16,9 @@ import { Box, Button, Paper, Typography } from '@material-ui/core'; import React from 'react'; import { Content, StructuredMetadataTable } from '@backstage/core-components'; -import { UiSchema } from '@rjsf/core'; +import { UiSchema } from '@rjsf/utils'; import { JsonObject } from '@backstage/types'; -import { ReviewStepProps } from '../types'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; export function getReviewData( formData: Record, diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/index.ts b/plugins/scaffolder/src/legacy/MultistepJsonForm/index.ts similarity index 100% rename from plugins/scaffolder/src/components/MultistepJsonForm/index.ts rename to plugins/scaffolder/src/legacy/MultistepJsonForm/index.ts diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts b/plugins/scaffolder/src/legacy/MultistepJsonForm/schema.test.ts similarity index 100% rename from plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts rename to plugins/scaffolder/src/legacy/MultistepJsonForm/schema.test.ts diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts b/plugins/scaffolder/src/legacy/MultistepJsonForm/schema.ts similarity index 95% rename from plugins/scaffolder/src/components/MultistepJsonForm/schema.ts rename to plugins/scaffolder/src/legacy/MultistepJsonForm/schema.ts index c3c90ae86a..e6221cb8d5 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts +++ b/plugins/scaffolder/src/legacy/MultistepJsonForm/schema.ts @@ -15,8 +15,9 @@ */ import { JsonObject } from '@backstage/types'; -import { FormProps, UiSchema } from '@rjsf/core'; +import { UiSchema } from '@rjsf/utils'; import type { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { FormProps } from '@rjsf/core'; function isObject(value: unknown): value is JsonObject { return typeof value === 'object' && value !== null && !Array.isArray(value); @@ -120,8 +121,7 @@ export function transformSchemaToProps( )?.component; if (Layout) { - uiSchema['ui:ObjectFieldTemplate'] = - Layout as unknown as FormProps['ObjectFieldTemplate']; + uiSchema['ui:ObjectFieldTemplate'] = Layout; } } diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/legacy/Router.tsx similarity index 91% rename from plugins/scaffolder/src/components/Router.tsx rename to plugins/scaffolder/src/legacy/Router.tsx index 3ceda359cc..ac183b9470 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/legacy/Router.tsx @@ -21,18 +21,17 @@ import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { ScaffolderPage } from './ScaffolderPage'; import { TemplatePage } from './TemplatePage'; import { TaskPage } from './TaskPage'; -import { ActionsPage } from './ActionsPage'; -import { TemplateEditorPage } from './TemplateEditorPage'; +import { ActionsPage } from '../components/ActionsPage'; import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../extensions/default'; import { useRouteRef, useRouteRefParams } from '@backstage/core-plugin-api'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; import { - FieldExtensionOptions, + ReviewStepProps, SecretsContextProvider, useCustomFieldExtensions, useCustomLayouts, } from '@backstage/plugin-scaffolder-react'; -import { ListTasksPage } from './ListTasksPage'; -import { ReviewStepProps } from './types'; +import { ListTasksPage } from '../components/ListTasksPage'; import { actionsRouteRef, editRouteRef, @@ -41,12 +40,13 @@ import { scaffolderTaskRouteRef, selectedTemplateRouteRef, } from '../routes'; +import { TemplateEditorPage } from './TemplateEditorPage'; /** * The props for the entrypoint `ScaffolderPage` component the plugin. - * @public + * @alpha */ -export type RouterProps = { +export type LegacyRouterProps = { components?: { ReviewStepComponent?: ComponentType; TemplateCardComponent?: @@ -77,11 +77,11 @@ export type RouterProps = { }; /** - * The main entrypoint `Router` for the `ScaffolderPlugin`. + * The legacy router * - * @public + * @alpha */ -export const Router = (props: RouterProps) => { +export const LegacyRouter = (props: LegacyRouterProps) => { const { groups, templateFilter, @@ -95,7 +95,9 @@ export const Router = (props: RouterProps) => { const outlet = useOutlet(); const TaskPageElement = TaskPageComponent ?? TaskPage; - const customFieldExtensions = useCustomFieldExtensions(outlet); + const customFieldExtensions = + useCustomFieldExtensions(outlet); + const fieldExtensions = [ ...customFieldExtensions, ...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter( @@ -104,7 +106,7 @@ export const Router = (props: RouterProps) => { customFieldExtension => customFieldExtension.name === name, ), ), - ] as FieldExtensionOptions[]; + ] as LegacyFieldExtensionOptions[]; const customLayouts = useCustomLayouts(outlet); diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPage.tsx similarity index 98% rename from plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx rename to plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPage.tsx index 40435573e9..54122eddf0 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx +++ b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPage.tsx @@ -34,11 +34,11 @@ import { } from '@backstage/plugin-catalog-react'; import React, { ComponentType } from 'react'; import { TemplateList } from '../TemplateList'; -import { TemplateTypePicker } from '../TemplateTypePicker'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; import { usePermission } from '@backstage/plugin-permission-react'; import { ScaffolderPageContextMenu } from './ScaffolderPageContextMenu'; import { registerComponentRouteRef } from '../../routes'; +import { TemplateTypePicker } from '../../components'; export type ScaffolderPageProps = { TemplateCardComponent?: diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx rename to plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.test.tsx diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx b/plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx similarity index 100% rename from plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx rename to plugins/scaffolder/src/legacy/ScaffolderPage/ScaffolderPageContextMenu.tsx diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.ts b/plugins/scaffolder/src/legacy/ScaffolderPage/index.ts similarity index 100% rename from plugins/scaffolder/src/components/ScaffolderPage/index.ts rename to plugins/scaffolder/src/legacy/ScaffolderPage/index.ts diff --git a/plugins/scaffolder/src/components/TaskPage/IconLink.test.tsx b/plugins/scaffolder/src/legacy/TaskPage/IconLink.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/IconLink.test.tsx rename to plugins/scaffolder/src/legacy/TaskPage/IconLink.test.tsx diff --git a/plugins/scaffolder/src/components/TaskPage/IconLink.tsx b/plugins/scaffolder/src/legacy/TaskPage/IconLink.tsx similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/IconLink.tsx rename to plugins/scaffolder/src/legacy/TaskPage/IconLink.tsx diff --git a/plugins/scaffolder/src/components/TaskPage/TaskErrors.tsx b/plugins/scaffolder/src/legacy/TaskPage/TaskErrors.tsx similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/TaskErrors.tsx rename to plugins/scaffolder/src/legacy/TaskPage/TaskErrors.tsx diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/legacy/TaskPage/TaskPage.tsx similarity index 98% rename from plugins/scaffolder/src/components/TaskPage/TaskPage.tsx rename to plugins/scaffolder/src/legacy/TaskPage/TaskPage.tsx index 78cdc5d935..e2165ed358 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/legacy/TaskPage/TaskPage.tsx @@ -64,9 +64,7 @@ import { selectedTemplateRouteRef, } from '../../routes'; import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; - -// typings are wrong for this library, so fallback to not parsing types. -const humanizeDuration = require('humanize-duration'); +import humanizeDuration from 'humanize-duration'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -236,8 +234,8 @@ const hasLinks = ({ links = [] }: ScaffolderTaskOutput): boolean => /** * TaskPageProps for constructing a TaskPage * @param loadingText - Optional loading text shown before a task begins executing. - * * @public + * @deprecated - this is a useless type that is no longer used. */ export type TaskPageProps = { loadingText?: string; @@ -246,7 +244,7 @@ export type TaskPageProps = { /** * TaskPage for showing the status of the taskId provided as a param * - * @public + * @alpha */ export const TaskPage = (props: TaskPageProps) => { const { loadingText } = props; diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPageLinks.test.tsx b/plugins/scaffolder/src/legacy/TaskPage/TaskPageLinks.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/TaskPageLinks.test.tsx rename to plugins/scaffolder/src/legacy/TaskPage/TaskPageLinks.test.tsx diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPageLinks.tsx b/plugins/scaffolder/src/legacy/TaskPage/TaskPageLinks.tsx similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/TaskPageLinks.tsx rename to plugins/scaffolder/src/legacy/TaskPage/TaskPageLinks.tsx diff --git a/plugins/scaffolder/src/components/TaskPage/index.ts b/plugins/scaffolder/src/legacy/TaskPage/index.ts similarity index 100% rename from plugins/scaffolder/src/components/TaskPage/index.ts rename to plugins/scaffolder/src/legacy/TaskPage/index.ts diff --git a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx rename to plugins/scaffolder/src/legacy/TemplateCard/TemplateCard.tsx diff --git a/plugins/scaffolder/src/components/TemplateCard/index.ts b/plugins/scaffolder/src/legacy/TemplateCard/index.ts similarity index 100% rename from plugins/scaffolder/src/components/TemplateCard/index.ts rename to plugins/scaffolder/src/legacy/TemplateCard/index.ts diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx similarity index 88% rename from plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx rename to plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx index e470267b23..9107ac67eb 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/CustomFieldExplorer.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/CustomFieldExplorer.tsx @@ -28,16 +28,13 @@ import { Select, } from '@material-ui/core'; import CloseIcon from '@material-ui/icons/Close'; -import { ISubmitEvent, 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 '@backstage/plugin-scaffolder-react'; -import * as fieldOverrides from '../MultistepJsonForm/FieldOverrides'; +import { Form } from '@backstage/plugin-scaffolder-react/alpha'; import { TemplateEditorForm } from './TemplateEditorForm'; - -const Form = withTheme(MuiTheme); +import validator from '@rjsf/validator-ajv8'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; const useStyles = makeStyles(theme => ({ root: { @@ -69,15 +66,15 @@ export const CustomFieldExplorer = ({ customFieldExtensions = [], onClose, }: { - customFieldExtensions?: FieldExtensionOptions[]; + customFieldExtensions?: LegacyFieldExtensionOptions[]; 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 [formState, setFormState] = useState({}); const sampleFieldTemplate = useMemo( () => yaml.stringify({ @@ -104,18 +101,17 @@ export const CustomFieldExplorer = ({ }, [customFieldExtensions]); const handleSelectionChange = useCallback( - (selection: FieldExtensionOptions) => { + (selection: LegacyFieldExtensionOptions) => { setSelectedField(selection); setFieldFormState({}); setFormState({}); }, - [setFieldFormState, setFormState, setSelectedField], + [setFieldFormState, setSelectedField, setFormState], ); 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()); @@ -135,7 +131,9 @@ export const CustomFieldExplorer = ({ label="Choose Custom Field Extension" labelId="select-field-label" onChange={e => - handleSelectionChange(e.target.value as FieldExtensionOptions) + handleSelectionChange( + e.target.value as LegacyFieldExtensionOptions, + ) } > {fieldOptions.map((option, idx) => ( @@ -156,13 +154,12 @@ export const CustomFieldExplorer = ({ ) => - handleFieldConfigChange(e.formData) - } + onSubmit={e => handleFieldConfigChange(e.formData)} + validator={validator} schema={selectedField.schema?.uiOptions || {}} >
diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditor.tsx similarity index 79% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx rename to plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditor.tsx index e07434aff7..f6e7b38d7d 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditor.tsx @@ -15,17 +15,15 @@ */ import { makeStyles } from '@material-ui/core'; import React, { useState } from 'react'; -import type { - FieldExtensionOptions, - LayoutOptions, -} from '@backstage/plugin-scaffolder-react'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; import { TemplateDirectoryAccess } from '../../lib/filesystem'; -import { DirectoryEditorProvider } from './DirectoryEditorContext'; -import { DryRunProvider } from './DryRunContext'; -import { DryRunResults } from './DryRunResults'; -import { TemplateEditorBrowser } from './TemplateEditorBrowser'; +import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { DirectoryEditorProvider } from '../../next/TemplateEditorPage/DirectoryEditorContext'; +import { DryRunProvider } from '../../next/TemplateEditorPage/DryRunContext'; +import { TemplateEditorBrowser } from '../../next/TemplateEditorPage/TemplateEditorBrowser'; +import { TemplateEditorTextArea } from '../../next/TemplateEditorPage/TemplateEditorTextArea'; import { TemplateEditorForm } from './TemplateEditorForm'; -import { TemplateEditorTextArea } from './TemplateEditorTextArea'; +import { DryRunResults } from '../../next/TemplateEditorPage/DryRunResults'; const useStyles = makeStyles({ // Reset and fix sizing to make sure scrolling behaves correctly @@ -59,7 +57,7 @@ const useStyles = makeStyles({ export const TemplateEditor = (props: { directory: TemplateDirectoryAccess; - fieldExtensions?: FieldExtensionOptions[]; + fieldExtensions?: LegacyFieldExtensionOptions[]; layouts?: LayoutOptions[]; onClose?: () => void; }) => { diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorForm.tsx similarity index 94% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx rename to plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorForm.tsx index 2a726110b8..df05efc921 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorForm.tsx @@ -19,15 +19,16 @@ import { makeStyles } from '@material-ui/core/styles'; import React, { Component, ReactNode, useMemo, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import yaml from 'yaml'; -import type { - FieldExtensionOptions, +import { LayoutOptions, TemplateParameterSchema, } from '@backstage/plugin-scaffolder-react'; + +import { useDryRun } from '../../next/TemplateEditorPage/DryRunContext'; +import { useDirectoryEditor } from '../../next/TemplateEditorPage/DirectoryEditorContext'; import { MultistepJsonForm } from '../MultistepJsonForm'; import { createValidator } from '../TemplatePage'; -import { useDirectoryEditor } from './DirectoryEditorContext'; -import { useDryRun } from './DryRunContext'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; const useStyles = makeStyles({ containerWrapper: { @@ -85,7 +86,7 @@ interface TemplateEditorFormProps { setErrorText: (errorText?: string) => void; onDryRun?: (data: JsonObject) => Promise; - fieldExtensions?: FieldExtensionOptions[]; + fieldExtensions?: LegacyFieldExtensionOptions[]; layouts?: LayoutOptions[]; } @@ -191,7 +192,7 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { onUpdate(e.formData)} onReset={() => onUpdate({})} diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorPage.tsx similarity index 90% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx rename to plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorPage.tsx index ebb763e145..127c73dcf5 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateEditorPage.tsx @@ -19,14 +19,12 @@ import { TemplateDirectoryAccess, WebFileSystemAccess, } from '../../lib/filesystem'; -import { CustomFieldExplorer } from './CustomFieldExplorer'; -import { TemplateEditorIntro } from './TemplateEditorIntro'; +import { type LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; +import { TemplateEditorIntro } from '../../next/TemplateEditorPage/TemplateEditorIntro'; import { TemplateEditor } from './TemplateEditor'; import { TemplateFormPreviewer } from './TemplateFormPreviewer'; -import { - type FieldExtensionOptions, - type LayoutOptions, -} from '@backstage/plugin-scaffolder-react'; +import { CustomFieldExplorer } from './CustomFieldExplorer'; type Selection = | { @@ -42,7 +40,7 @@ type Selection = interface TemplateEditorPageProps { defaultPreviewTemplate?: string; - customFieldExtensions?: FieldExtensionOptions[]; + customFieldExtensions?: LegacyFieldExtensionOptions[]; layouts?: LayoutOptions[]; } diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateFormPreviewer.tsx similarity index 94% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx rename to plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateFormPreviewer.tsx index 9442394177..9e92d12d93 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/TemplateFormPreviewer.tsx @@ -32,12 +32,10 @@ import CloseIcon from '@material-ui/icons/Close'; import React, { useCallback, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import yaml from 'yaml'; -import { - type FieldExtensionOptions, - type LayoutOptions, -} from '@backstage/plugin-scaffolder-react'; +import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; +import { TemplateEditorTextArea } from '../../next/TemplateEditorPage/TemplateEditorTextArea'; import { TemplateEditorForm } from './TemplateEditorForm'; -import { TemplateEditorTextArea } from './TemplateEditorTextArea'; const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI parameters: @@ -116,7 +114,7 @@ export const TemplateFormPreviewer = ({ layouts = [], }: { defaultPreviewTemplate?: string; - customFieldExtensions?: FieldExtensionOptions[]; + customFieldExtensions?: LegacyFieldExtensionOptions[]; onClose?: () => void; layouts?: LayoutOptions[]; }) => { @@ -195,7 +193,7 @@ export const TemplateFormPreviewer = ({ - +
@@ -208,11 +206,11 @@ export const TemplateFormPreviewer = ({
diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/index.ts b/plugins/scaffolder/src/legacy/TemplateEditorPage/index.ts similarity index 93% rename from plugins/scaffolder/src/components/TemplateEditorPage/index.ts rename to plugins/scaffolder/src/legacy/TemplateEditorPage/index.ts index 7ec6bddb64..7de0d3c679 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/index.ts +++ b/plugins/scaffolder/src/legacy/TemplateEditorPage/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,5 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - export { TemplateEditorPage } from './TemplateEditorPage'; diff --git a/plugins/scaffolder/src/components/TemplateList/TemplateList.test.tsx b/plugins/scaffolder/src/legacy/TemplateList/TemplateList.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateList/TemplateList.test.tsx rename to plugins/scaffolder/src/legacy/TemplateList/TemplateList.test.tsx diff --git a/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx b/plugins/scaffolder/src/legacy/TemplateList/TemplateList.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateList/TemplateList.tsx rename to plugins/scaffolder/src/legacy/TemplateList/TemplateList.tsx diff --git a/plugins/scaffolder/src/components/TemplateList/index.ts b/plugins/scaffolder/src/legacy/TemplateList/index.ts similarity index 100% rename from plugins/scaffolder/src/components/TemplateList/index.ts rename to plugins/scaffolder/src/legacy/TemplateList/index.ts diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/legacy/TemplatePage/TemplatePage.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx rename to plugins/scaffolder/src/legacy/TemplatePage/TemplatePage.test.tsx diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/legacy/TemplatePage/TemplatePage.tsx similarity index 96% rename from plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx rename to plugins/scaffolder/src/legacy/TemplatePage/TemplatePage.tsx index c615649f93..ffb754bae3 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/legacy/TemplatePage/TemplatePage.tsx @@ -20,10 +20,10 @@ import React, { ComponentType, useCallback, useState } from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { - type FieldExtensionOptions, type LayoutOptions, scaffolderApiRef, useTemplateSecrets, + ReviewStepProps, } from '@backstage/plugin-scaffolder-react'; import { MultistepJsonForm } from '../MultistepJsonForm'; import { createValidator } from './createValidator'; @@ -38,12 +38,12 @@ import { useRouteRefParams, } from '@backstage/core-plugin-api'; import { stringifyEntityRef } from '@backstage/catalog-model'; -import { ReviewStepProps } from '../types'; import { rootRouteRef, scaffolderTaskRouteRef, selectedTemplateRouteRef, } from '../../routes'; +import { LegacyFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; const useTemplateParameterSchema = (templateRef: string) => { const scaffolderApi = useApi(scaffolderApiRef); @@ -56,7 +56,7 @@ const useTemplateParameterSchema = (templateRef: string) => { type Props = { ReviewStepComponent?: ComponentType; - customFieldExtensions?: FieldExtensionOptions[]; + customFieldExtensions?: LegacyFieldExtensionOptions[]; layouts?: LayoutOptions[]; headerOptions?: { pageTitleOverride?: string; @@ -162,7 +162,7 @@ export const TemplatePage = ({ { - const validators: Record> = - { - CustomPicker: ( - value: unknown, - fieldValidation: FieldValidation, - _context: { apiHolder: ApiHolder }, - ) => { - if (!value || !(value as { value?: unknown }).value) { - fieldValidation.addError('Error !'); - } - }, - CustomLink: ( - values: unknown, - fieldValidation: FieldValidation, - _context: { apiHolder: ApiHolder }, - ) => { - const input = values as CustomLinkType[]; - for (const item of input) { - const validGitlabUrlRegex = - /gitlab\.(?:stg\.)?spotify\.com\?owner=.*&repo=.*/; + const validators: Record< + string, + undefined | LegacyCustomFieldValidator + > = { + CustomPicker: ( + value: unknown, + fieldValidation: FieldValidation, + _context: { apiHolder: ApiHolder }, + ) => { + if (!value || !(value as { value?: unknown }).value) { + fieldValidation.addError('Error !'); + } + }, + CustomLink: ( + values: unknown, + fieldValidation: FieldValidation, + _context: { apiHolder: ApiHolder }, + ) => { + const input = values as CustomLinkType[]; + for (const item of input) { + const validGitlabUrlRegex = + /gitlab\.(?:stg\.)?spotify\.com\?owner=.*&repo=.*/; - if (!item || !validGitlabUrlRegex.test(item.url)) { - fieldValidation.addError( - `Make sure to put in a valid gitlab clone url.`, - ); - } + if (!item || !validGitlabUrlRegex.test(item.url)) { + fieldValidation.addError( + `Make sure to put in a valid gitlab clone url.`, + ); } - }, - TagPicker: ( - values: unknown, - fieldValidation: FieldValidation, - _context: { apiHolder: ApiHolder }, - ) => { - const input = values as string[]; - for (const item of input) { - if (!/^[a-z0-9-]+$/.test(item)) { - fieldValidation.addError( - 'A tag name can only contain lowercase letters, numeric characters or dashes', - ); - } + } + }, + TagPicker: ( + values: unknown, + fieldValidation: FieldValidation, + _context: { apiHolder: ApiHolder }, + ) => { + const input = values as string[]; + for (const item of input) { + if (!/^[a-z0-9-]+$/.test(item)) { + fieldValidation.addError( + 'A tag name can only contain lowercase letters, numeric characters or dashes', + ); } - }, - }; + } + }, + }; const apiHolderMock: jest.Mocked = { get: jest.fn().mockImplementation(() => { @@ -109,7 +111,7 @@ describe('createValidator', () => { /* THEN */ expect(result).not.toBeNull(); - expect(result.p1.addError).toHaveBeenCalledTimes(1); + expect(result.p1?.addError).toHaveBeenCalledTimes(1); }); it('should call validator for array property from a custom field extension', () => { @@ -144,7 +146,7 @@ describe('createValidator', () => { /* THEN */ expect(result).not.toBeNull(); - expect(result.tags.addError).toHaveBeenCalledTimes(1); + expect(result.tags?.addError).toHaveBeenCalledTimes(1); }); it('should call validator for array object property from a custom field extension', () => { @@ -193,6 +195,6 @@ describe('createValidator', () => { /* THEN */ expect(result).not.toBeNull(); - expect(result.links.addError).toHaveBeenCalledTimes(1); + expect(result.links?.addError).toHaveBeenCalledTimes(1); }); }); diff --git a/plugins/scaffolder/src/components/TemplatePage/createValidator.ts b/plugins/scaffolder/src/legacy/TemplatePage/createValidator.ts similarity index 91% rename from plugins/scaffolder/src/components/TemplatePage/createValidator.ts rename to plugins/scaffolder/src/legacy/TemplatePage/createValidator.ts index 8bfe8c8313..ae0b834fe9 100644 --- a/plugins/scaffolder/src/components/TemplatePage/createValidator.ts +++ b/plugins/scaffolder/src/legacy/TemplatePage/createValidator.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; -import { FormValidation } from '@rjsf/core'; +import { LegacyCustomFieldValidator } from '@backstage/plugin-scaffolder-react/alpha'; +import { FieldValidation, FormValidation } from '@rjsf/utils'; import { JsonObject, JsonValue } from '@backstage/types'; import { ApiHolder } from '@backstage/core-plugin-api'; @@ -29,7 +29,7 @@ function isArray(obj: unknown): obj is JsonObject { export const createValidator = ( rootSchema: JsonObject, - validators: Record>, + validators: Record>, context: { apiHolder: ApiHolder; }, @@ -56,7 +56,7 @@ export const createValidator = ( if (fieldName && typeof validators[fieldName] === 'function') { validators[fieldName]!( propData as JsonObject[], - propValidation, + propValidation as FieldValidation, context, ); } diff --git a/plugins/scaffolder/src/components/TemplatePage/index.ts b/plugins/scaffolder/src/legacy/TemplatePage/index.ts similarity index 100% rename from plugins/scaffolder/src/components/TemplatePage/index.ts rename to plugins/scaffolder/src/legacy/TemplatePage/index.ts diff --git a/plugins/scaffolder/src/legacy/index.ts b/plugins/scaffolder/src/legacy/index.ts new file mode 100644 index 0000000000..2393be0f69 --- /dev/null +++ b/plugins/scaffolder/src/legacy/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { LegacyRouter, type LegacyRouterProps } from './Router'; +export { LegacyScaffolderPage } from '../plugin'; diff --git a/plugins/scaffolder/src/next/TemplateEditorPage/CustomFieldExplorer.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/CustomFieldExplorer.tsx index 15298dff8a..a6c06ea20a 100644 --- a/plugins/scaffolder/src/next/TemplateEditorPage/CustomFieldExplorer.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/CustomFieldExplorer.tsx @@ -31,12 +31,10 @@ import CloseIcon from '@material-ui/icons/Close'; import CodeMirror from '@uiw/react-codemirror'; import React, { useCallback, useMemo, useState } from 'react'; import yaml from 'yaml'; -import { - NextFieldExtensionOptions, - Form, -} from '@backstage/plugin-scaffolder-react/alpha'; +import { Form } from '@backstage/plugin-scaffolder-react/alpha'; import { TemplateEditorForm } from './TemplateEditorForm'; import validator from '@rjsf/validator-ajv8'; +import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; const useStyles = makeStyles(theme => ({ root: { @@ -68,7 +66,7 @@ export const CustomFieldExplorer = ({ customFieldExtensions = [], onClose, }: { - customFieldExtensions?: NextFieldExtensionOptions[]; + customFieldExtensions?: FieldExtensionOptions[]; onClose?: () => void; }) => { const classes = useStyles(); @@ -102,7 +100,7 @@ export const CustomFieldExplorer = ({ }, [customFieldExtensions]); const handleSelectionChange = useCallback( - (selection: NextFieldExtensionOptions) => { + (selection: FieldExtensionOptions) => { setSelectedField(selection); setFieldFormState({}); }, @@ -131,7 +129,7 @@ export const CustomFieldExplorer = ({ label="Choose Custom Field Extension" labelId="select-field-label" onChange={e => - handleSelectionChange(e.target.value as NextFieldExtensionOptions) + handleSelectionChange(e.target.value as FieldExtensionOptions) } > {fieldOptions.map((option, idx) => ( diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DirectoryEditorContext.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DirectoryEditorContext.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DirectoryEditorContext.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DirectoryEditorContext.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.test.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunContext.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.test.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunContext.test.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunContext.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunContext.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunContext.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResults.test.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResults.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResults.test.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResults.test.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResults.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResults.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResults.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResults.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.test.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsList.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.test.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsList.test.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsList.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx similarity index 92% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx index c2d8d3a2a4..c5c391907e 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.test.tsx @@ -16,7 +16,7 @@ import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { screen } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { ReactNode, useEffect } from 'react'; import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; @@ -91,9 +91,13 @@ describe('DryRunResultsView', () => { expect(screen.queryByText('Foo Link')).not.toBeInTheDocument(); await userEvent.click(screen.getByText('Log')); - expect(screen.getByText('Foo Message')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText('Foo Message')).toBeInTheDocument(); + }); await userEvent.click(screen.getByText('Output')); - expect(screen.getByText('Foo Link')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText('Foo Link')).toBeInTheDocument(); + }); }); }); diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx similarity index 96% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx index 9c56039808..68ed6f906f 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/DryRunResultsView.tsx @@ -24,11 +24,11 @@ import Tab from '@material-ui/core/Tab'; import Tabs from '@material-ui/core/Tabs'; import CodeMirror from '@uiw/react-codemirror'; import React, { useEffect, useMemo, useState } from 'react'; -import { TaskStatusStepper } from '../../TaskPage/TaskPage'; -import { TaskPageLinks } from '../../TaskPage/TaskPageLinks'; import { useDryRun } from '../DryRunContext'; -import { FileBrowser } from '../../FileBrowser'; import { DryRunResultsSplitView } from './DryRunResultsSplitView'; +import { FileBrowser } from '../../../components/FileBrowser'; +import { TaskPageLinks } from '../../../legacy/TaskPage/TaskPageLinks'; +import { TaskStatusStepper } from '../../../legacy/TaskPage/TaskPage'; const useStyles = makeStyles({ root: { diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/index.ts b/plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/index.ts similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/DryRunResults/index.ts rename to plugins/scaffolder/src/next/TemplateEditorPage/DryRunResults/index.ts diff --git a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditor.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditor.tsx index 16067e8095..a348f5e513 100644 --- a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditor.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditor.tsx @@ -16,14 +16,14 @@ import { makeStyles } from '@material-ui/core'; import React, { useState } from 'react'; import type { LayoutOptions } from '@backstage/plugin-scaffolder-react'; -import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; +import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { TemplateDirectoryAccess } from '../../lib/filesystem'; -import { DirectoryEditorProvider } from '../../components/TemplateEditorPage/DirectoryEditorContext'; -import { DryRunProvider } from '../../components/TemplateEditorPage/DryRunContext'; -import { DryRunResults } from '../../components/TemplateEditorPage/DryRunResults'; -import { TemplateEditorBrowser } from '../../components/TemplateEditorPage/TemplateEditorBrowser'; +import { DirectoryEditorProvider } from './DirectoryEditorContext'; +import { TemplateEditorBrowser } from './TemplateEditorBrowser'; +import { DryRunProvider } from './DryRunContext'; +import { TemplateEditorTextArea } from './TemplateEditorTextArea'; import { TemplateEditorForm } from './TemplateEditorForm'; -import { TemplateEditorTextArea } from '../../components/TemplateEditorPage/TemplateEditorTextArea'; +import { DryRunResults } from './DryRunResults'; const useStyles = makeStyles({ // Reset and fix sizing to make sure scrolling behaves correctly @@ -57,7 +57,7 @@ const useStyles = makeStyles({ export const TemplateEditor = (props: { directory: TemplateDirectoryAccess; - fieldExtensions?: NextFieldExtensionOptions[]; + fieldExtensions?: FieldExtensionOptions[]; layouts?: LayoutOptions[]; onClose?: () => void; }) => { diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorBrowser.test.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorBrowser.test.tsx diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorBrowser.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorBrowser.tsx similarity index 98% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorBrowser.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorBrowser.tsx index 177ad11c2b..996da98d4a 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorBrowser.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorBrowser.tsx @@ -18,8 +18,8 @@ import CloseIcon from '@material-ui/icons/Close'; import RefreshIcon from '@material-ui/icons/Refresh'; import SaveIcon from '@material-ui/icons/Save'; import React from 'react'; -import { FileBrowser } from '../FileBrowser'; import { useDirectoryEditor } from './DirectoryEditorContext'; +import { FileBrowser } from '../../components/FileBrowser'; const useStyles = makeStyles(theme => ({ button: { diff --git a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorForm.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorForm.tsx index 898487e200..4b5a00b7ba 100644 --- a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorForm.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorForm.tsx @@ -16,19 +16,20 @@ import { useApiHolder } from '@backstage/core-plugin-api'; import { JsonObject, JsonValue } from '@backstage/types'; import { makeStyles } from '@material-ui/core/styles'; -import React, { Component, ReactNode, useState } from 'react'; +import React, { Component, ReactNode, useMemo, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import yaml from 'yaml'; import { LayoutOptions, TemplateParameterSchema, + FieldExtensionOptions, } from '@backstage/plugin-scaffolder-react'; import { - NextFieldExtensionOptions, Stepper, + createAsyncValidators, } from '@backstage/plugin-scaffolder-react/alpha'; -import { useDryRun } from '../../components/TemplateEditorPage/DryRunContext'; -import { useDirectoryEditor } from '../../components/TemplateEditorPage/DirectoryEditorContext'; +import { useDryRun } from './DryRunContext'; +import { useDirectoryEditor } from './DirectoryEditorContext'; const useStyles = makeStyles({ containerWrapper: { @@ -82,8 +83,9 @@ interface TemplateEditorFormProps { /** Setting this to true will cause the content to be parsed as if it is the template entity spec */ contentIsSpec?: boolean; setErrorText: (errorText?: string) => void; + onDryRun?: (data: JsonObject) => Promise; - fieldExtensions?: NextFieldExtensionOptions[]; + fieldExtensions?: FieldExtensionOptions[]; layouts?: LayoutOptions[]; } @@ -106,6 +108,12 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { const [steps, setSteps] = useState(); + const fields = useMemo(() => { + return Object.fromEntries( + fieldExtensions.map(({ name, component }) => [name, component]), + ); + }, [fieldExtensions]); + useDebounce( () => { try { @@ -113,7 +121,10 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { setSteps(undefined); return; } - const parsed: JsonValue = yaml.parse(content); + const parsed: JsonValue = yaml + .parseAllDocuments(content) + .filter(c => c) + .map(c => c.toJSON())[0]; if (!isJsonObject(parsed)) { setSteps(undefined); @@ -140,6 +151,10 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { return; } + const fieldValidators = Object.fromEntries( + fieldExtensions.map(({ name, validation }) => [name, validation]), + ); + setErrorText(); setSteps( parameters.flatMap(param => @@ -148,6 +163,9 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { { title: String(param.title), schema: param, + validate: createAsyncValidators(param, fieldValidators, { + apiHolder, + }), }, ] : [], @@ -172,11 +190,11 @@ export function TemplateEditorForm(props: TemplateEditorFormProps) { { - await onDryRun?.(data); + components={fields} + onCreate={async options => { + await onDryRun?.(options); }} layouts={layouts} - components={{ createButtonText: onDryRun && 'Try It' }} />
@@ -197,7 +215,7 @@ export function TemplateEditorFormDirectoryEditorDryRun( const directoryEditor = useDirectoryEditor(); const { selectedFile } = directoryEditor; - const handleDryRun = async (values: JsonObject) => { + const handleDryRun = async (data: JsonObject) => { if (!selectedFile) { return; } @@ -205,7 +223,7 @@ export function TemplateEditorFormDirectoryEditorDryRun( try { await dryRun.execute({ templateContent: selectedFile.content, - values, + values: data, files: directoryEditor.files, }); setErrorText(); diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorIntro.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorIntro.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorIntro.tsx diff --git a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorPage.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorPage.tsx index 9863e99c73..aab693e590 100644 --- a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorPage.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorPage.tsx @@ -22,9 +22,11 @@ import { import { CustomFieldExplorer } from './CustomFieldExplorer'; import { TemplateEditor } from './TemplateEditor'; import { TemplateFormPreviewer } from './TemplateFormPreviewer'; -import { type LayoutOptions } from '@backstage/plugin-scaffolder-react'; -import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; -import { TemplateEditorIntro } from '../../components/TemplateEditorPage/TemplateEditorIntro'; +import { + FieldExtensionOptions, + type LayoutOptions, +} from '@backstage/plugin-scaffolder-react'; +import { TemplateEditorIntro } from './TemplateEditorIntro'; type Selection = | { @@ -40,7 +42,7 @@ type Selection = interface TemplateEditorPageProps { defaultPreviewTemplate?: string; - customFieldExtensions?: NextFieldExtensionOptions[]; + customFieldExtensions?: FieldExtensionOptions[]; layouts?: LayoutOptions[]; } diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorTextArea.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorTextArea.tsx similarity index 100% rename from plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorTextArea.tsx rename to plugins/scaffolder/src/next/TemplateEditorPage/TemplateEditorTextArea.tsx diff --git a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateFormPreviewer.tsx b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateFormPreviewer.tsx index 75d8c511b1..c253bc0a5f 100644 --- a/plugins/scaffolder/src/next/TemplateEditorPage/TemplateFormPreviewer.tsx +++ b/plugins/scaffolder/src/next/TemplateEditorPage/TemplateFormPreviewer.tsx @@ -32,10 +32,12 @@ import CloseIcon from '@material-ui/icons/Close'; import React, { useCallback, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import yaml from 'yaml'; -import { type LayoutOptions } from '@backstage/plugin-scaffolder-react'; -import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; +import { + LayoutOptions, + FieldExtensionOptions, +} from '@backstage/plugin-scaffolder-react'; import { TemplateEditorForm } from './TemplateEditorForm'; -import { TemplateEditorTextArea } from '../../components/TemplateEditorPage/TemplateEditorTextArea'; +import { TemplateEditorTextArea } from './TemplateEditorTextArea'; const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI parameters: @@ -114,7 +116,7 @@ export const TemplateFormPreviewer = ({ layouts = [], }: { defaultPreviewTemplate?: string; - customFieldExtensions?: NextFieldExtensionOptions[]; + customFieldExtensions?: FieldExtensionOptions[]; onClose?: () => void; layouts?: LayoutOptions[]; }) => { diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx index 863d3009e1..44390bc03c 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx @@ -38,7 +38,6 @@ import { import { ScaffolderPageContextMenu, TemplateCategoryPicker, - TemplateGroupFilter, TemplateGroups, } from '@backstage/plugin-scaffolder-react/alpha'; @@ -52,6 +51,7 @@ import { viewTechDocRouteRef, } from '../../routes'; import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; /** * @alpha diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index a7133ae8c7..3b14f2c07f 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -26,12 +26,11 @@ import { scaffolderApiRef, useTemplateSecrets, type LayoutOptions, -} from '@backstage/plugin-scaffolder-react'; -import { FormProps, - Workflow, - NextFieldExtensionOptions, -} from '@backstage/plugin-scaffolder-react/alpha'; + FieldExtensionOptions, + ReviewStepProps, +} from '@backstage/plugin-scaffolder-react'; +import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; @@ -45,9 +44,12 @@ import { * @alpha */ export type TemplateWizardPageProps = { - customFieldExtensions: NextFieldExtensionOptions[]; + customFieldExtensions: FieldExtensionOptions[]; + components?: { + ReviewStepComponent?: React.ComponentType; + }; layouts?: LayoutOptions[]; - FormProps?: FormProps; + formProps?: FormProps; }; export const TemplateWizardPage = (props: TemplateWizardPageProps) => { @@ -90,9 +92,10 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { namespace={namespace} templateName={templateName} onCreate={onCreate} + components={props.components} onError={onError} extensions={props.customFieldExtensions} - FormProps={props.FormProps} + formProps={props.formProps} layouts={props.layouts} /> diff --git a/plugins/scaffolder/src/next/index.ts b/plugins/scaffolder/src/next/index.ts index 6cef3eaa03..2ae1b7b6c7 100644 --- a/plugins/scaffolder/src/next/index.ts +++ b/plugins/scaffolder/src/next/index.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './Router'; export * from './TemplateListPage'; export * from './TemplateWizardPage'; export * from './types'; diff --git a/plugins/scaffolder/src/next/types.ts b/plugins/scaffolder/src/next/types.ts index c2ee473d54..80e01042f2 100644 --- a/plugins/scaffolder/src/next/types.ts +++ b/plugins/scaffolder/src/next/types.ts @@ -20,7 +20,7 @@ * It exists already in the `scaffolder-react` plugin, so you may have to update both files. */ -import type { FormProps as SchemaFormProps } from '@rjsf/core-v5'; +import type { FormProps as SchemaFormProps } from '@rjsf/core'; /** * Any `@rjsf/core` form properties that are publicly exposed to the `NextScaffolderPage` diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index ad9e70d843..fdde81695d 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -217,10 +217,10 @@ export const EntityTagsPickerFieldExtension = scaffolderPlugin.provide( * @alpha * The Router and main entrypoint to the Alpha Scaffolder plugin. */ -export const NextScaffolderPage = scaffolderPlugin.provide( +export const LegacyScaffolderPage = scaffolderPlugin.provide( createRoutableExtension({ - name: 'NextScaffolderPage', - component: () => import('./next/Router').then(m => m.Router), + name: 'LegacyScaffolderPage', + component: () => import('./legacy/Router').then(m => m.LegacyRouter), mountPoint: rootRouteRef, }), ); diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 80f8e6b2b9..c65b3a119c 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend-module-catalog +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 0.1.10-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index dc69657e74..4bcdf8f53b 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-catalog", "description": "A module for the search backend that exports catalog modules", - "version": "0.1.10-next.2", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index e08124fc5a..94727e88a2 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.3.9 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/plugin-search-common@1.2.7 + ## 1.3.9-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 505af44be1..ef15b13290 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.3.9-next.2", + "version": "1.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 9acc5a8616..f4b64f07c8 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.7 + ## 0.1.10-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index e050734050..41a390d773 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-explore", "description": "A module for the search backend that exports explore modules", - "version": "0.1.10-next.2", + "version": "0.1.10", "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 0e2b137bbc..3f8d5adeb7 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 0.5.15-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 1a34413dcc..2bdea9b391 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.5.15-next.2", + "version": "0.5.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-stack-overflow-collator/.eslintrc.js b/plugins/search-backend-module-stack-overflow-collator/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/search-backend-module-stack-overflow-collator/README.md b/plugins/search-backend-module-stack-overflow-collator/README.md new file mode 100644 index 0000000000..7df3229eeb --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/README.md @@ -0,0 +1,95 @@ +# Stack Overflow Search Backend Module + +A plugin that provides stack overflow specific functionality that can be used in different ways (e.g. for search) to compose your Backstage App. + +## Getting started + +Before we begin, make sure: + +- You have created your own standalone Backstage app using @backstage/create-app and not using a fork of the backstage repository. If you haven't setup Backstage already, start [here](https://backstage.io/docs/getting-started/). + +To use any of the functionality this plugin provides, you need to start by configuring your App with the following config: + +```yaml +stackoverflow: + baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance +``` + +### Stack Overflow for Teams + +If you have a private Stack Overflow instance and/or a private Stack Overflow Team you will need to supply an API key or Personal Access Token. You can read more about how to set this up by going to [Stack Overflow's Help Page](https://stackoverflow.help/en/articles/4385859-stack-overflow-for-teams-api). + +The existing API key approach remains the default, to support the new v2.3 API and PAT authentication model you need to pass the team name and the new PAT into the existing apiAccessToken parameter to the new URL. See [15770](https://github.com/backstage/backstage/issues/15770) for more details. + +```yaml +stackoverflow: + baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance + apiKey: $STACK_OVERFLOW_API_KEY + apiAccessToken: $STACK_OVERFLOW_API_ACCESS_TOKEN +``` + +```yaml +stackoverflow: + baseUrl: https://api.stackoverflowteams.com/2.3 # alternative: your internal stack overflow instance + teamName: $STACK_OVERFLOW_TEAM_NAME + apiAccessToken: $STACK_OVERFLOW_API_ACCESS_TOKEN +``` + +## Areas of Responsibility + +This stack overflow backend plugin is primarily responsible for the following: + +- Provides a `StackOverflowQuestionsCollatorFactory`, which can be used in the search backend to index stack overflow questions to your Backstage Search. + +### Index Stack Overflow Questions to search + +Before you are able to start index stack overflow questions to search, you need to go through the [search getting started guide](https://backstage.io/docs/features/search/getting-started). + +When you have your `packages/backend/src/plugins/search.ts` file ready to make modifications, add the following code snippet to add the `StackOverflowQuestionsCollatorFactory`. Note that you can optionally modify the `requestParams`, otherwise it will defaults to `{ order: 'desc', sort: 'activity', site: 'stackoverflow' }` as done in the `Try It` section on the [official Stack Overflow API documentation](https://api.stackexchange.com/docs/questions). + +> Note: if your `baseUrl` is set to the external stack overflow api `https://api.stackexchange.com/2.2`, you can find optional and required parameters under the official API documentation under [`Usage of /questions GET`](https://api.stackexchange.com/docs/questions) + +```ts +indexBuilder.addCollator({ + schedule, + factory: StackOverflowQuestionsCollatorFactory.fromConfig(env.config, { + logger: env.logger, + requestParams: { + tagged: ['backstage'], + site: 'stackoverflow', + pagesize: 100, + }, + }), +}); +``` + +## New Backend System + +> DISCLAIMER: The new backend system is in alpha, and so are the search backend module support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, you can find getting started guides below. + +This package exports a module that extends the search backend to also indexing the questions exposed by the [`Stack Overflow` API](https://api.stackexchange.com/docs/questions). + +### Installation + +Add the module package as a dependency: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-search-backend-module-stack-overflow-collator +``` + +Add the collator to your backend instance, along with the search plugin itself: + +```tsx +// packages/backend/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); +backend.add(import('@backstage/plugin-search-backend/alpha')); +backend.add( + import('@backstage/plugin-search-backend-module-stack-overflow-collator'), +); +backend.start(); +``` + +You may also want to add configuration parameters to your app-config, for example for controlling the scheduled indexing interval. These parameters should be placed under the `stackoverflow` key. See [the config definition file](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-stack-overflow-collator/config.d.ts) for more details. diff --git a/plugins/search-backend-module-stack-overflow-collator/api-report.md b/plugins/search-backend-module-stack-overflow-collator/api-report.md new file mode 100644 index 0000000000..9243e786ac --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/api-report.md @@ -0,0 +1,61 @@ +## API Report File for "@backstage/plugin-search-backend-module-stack-overflow-collator" + +> 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 { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { IndexableDocument } from '@backstage/plugin-search-common'; +import { Logger } from 'winston'; +import { Readable } from 'stream'; + +// @public +const searchStackOverflowCollatorModule: () => BackendFeature; +export default searchStackOverflowCollatorModule; + +// @public +export interface StackOverflowDocument extends IndexableDocument { + // (undocumented) + answers: number; + // (undocumented) + tags: string[]; +} + +// @public +export class StackOverflowQuestionsCollatorFactory + implements DocumentCollatorFactory +{ + // (undocumented) + execute(): AsyncGenerator; + // (undocumented) + static fromConfig( + config: Config, + options: StackOverflowQuestionsCollatorFactoryOptions, + ): StackOverflowQuestionsCollatorFactory; + // (undocumented) + getCollator(): Promise; + // (undocumented) + protected requestParams: StackOverflowQuestionsRequestParams; + // (undocumented) + readonly type: string; +} + +// @public +export type StackOverflowQuestionsCollatorFactoryOptions = { + baseUrl?: string; + maxPage?: number; + apiKey?: string; + apiAccessToken?: string; + teamName?: string; + requestParams?: StackOverflowQuestionsRequestParams; + logger: Logger; +}; + +// @public +export type StackOverflowQuestionsRequestParams = { + [key: string]: string | string[] | number; +}; +``` diff --git a/plugins/search-backend-module-stack-overflow-collator/catalog-info.yaml b/plugins/search-backend-module-stack-overflow-collator/catalog-info.yaml new file mode 100644 index 0000000000..ed73bd0eca --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-search-backend-module-stack-overflow-collator + title: '@backstage/plugin-search-backend-module-stack-overflow-collator' + description: A module for the search backend that exports stack overflow modules +spec: + lifecycle: experimental + type: backstage-backend-plugin-module + owner: discoverability-maintainers diff --git a/plugins/search-backend-module-stack-overflow-collator/config.d.ts b/plugins/search-backend-module-stack-overflow-collator/config.d.ts new file mode 100644 index 0000000000..d615179ed0 --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/config.d.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + /** + * Configuration options for the stack overflow plugin + */ + stackoverflow?: { + /** + * The base url of the Stack Overflow API used for the plugin + */ + baseUrl?: string; + + /** + * The API key to authenticate to Stack Overflow API + * @visibility secret + */ + apiKey?: string; + + /** + * The name of the team for a Stack Overflow for Teams account + */ + teamName?: string; + + /** + * The API Access Token to authenticate to Stack Overflow API + * @visibility secret + */ + apiAccessToken?: string; + + /** + * Type representing the request parameters. + */ + requestParams?: { + [key: string]: string | string[] | number; + }; + }; +} diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json new file mode 100644 index 0000000000..14e547de8e --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -0,0 +1,52 @@ +{ + "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", + "description": "A module for the search backend that exports stack overflow modules", + "version": "0.0.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": "backend-plugin-module" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/search-backend-module-stack-overflow" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "node-fetch": "^2.6.7", + "qs": "^6.9.4", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.2.1" + }, + "files": [ + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.test.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts similarity index 100% rename from plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.test.ts rename to plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.test.ts diff --git a/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts similarity index 90% rename from plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts rename to plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts index c5f8a8c16b..3c97937365 100644 --- a/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts @@ -54,7 +54,7 @@ export type StackOverflowQuestionsCollatorFactoryOptions = { apiKey?: string; apiAccessToken?: string; teamName?: string; - requestParams: StackOverflowQuestionsRequestParams; + requestParams?: StackOverflowQuestionsRequestParams; logger: Logger; }; @@ -81,7 +81,14 @@ export class StackOverflowQuestionsCollatorFactory this.apiAccessToken = options.apiAccessToken; this.teamName = options.teamName; this.maxPage = options.maxPage; - this.requestParams = options.requestParams; + // Sets the same default request parameters as the official API documentation + // See https://api.stackexchange.com/docs/questions + this.requestParams = options.requestParams ?? { + order: 'desc', + sort: 'activity', + site: 'stackoverflow', + ...(options.requestParams ?? {}), + }; this.logger = options.logger.child({ documentType: this.type }); } @@ -98,12 +105,16 @@ export class StackOverflowQuestionsCollatorFactory config.getOptionalString('stackoverflow.baseUrl') || 'https://api.stackexchange.com/2.3'; const maxPage = options.maxPage || 100; + const requestParams = config + .getOptionalConfig('stackoverflow.requestParams') + ?.get(); return new StackOverflowQuestionsCollatorFactory({ baseUrl, maxPage, apiKey, apiAccessToken, teamName, + requestParams, ...options, }); } @@ -175,7 +186,7 @@ export class StackOverflowQuestionsCollatorFactory ); const data = await res.json(); - for (const question of data.items) { + for (const question of data.items ?? []) { yield { title: question.title, location: question.link, diff --git a/plugins/scaffolder-react/src/next/types.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/index.ts similarity index 51% rename from plugins/scaffolder-react/src/next/types.ts rename to plugins/search-backend-module-stack-overflow-collator/src/collators/index.ts index 192fdf4146..1170b52423 100644 --- a/plugins/scaffolder-react/src/next/types.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/collators/index.ts @@ -14,18 +14,9 @@ * limitations under the License. */ -import type { FormProps as SchemaFormProps } from '@rjsf/core-v5'; - -// TODO(Rugvip): The FormProps type is actually supposed to be alpha, but since we want to -// refer to it from @backstage/plugin-scaffolder, it needs to be public for now. -// Once we support internal alpha re-exports this should be switched to an alpha export. - -/** - * Any `@rjsf/core` form properties that are publicly exposed to the `NextScaffolderpage` - * - * @alpha - */ -export type FormProps = Pick< - SchemaFormProps, - 'transformErrors' | 'noHtml5Validate' ->; +export { + type StackOverflowDocument, + type StackOverflowQuestionsRequestParams, + type StackOverflowQuestionsCollatorFactoryOptions, + StackOverflowQuestionsCollatorFactory, +} from './StackOverflowQuestionsCollatorFactory'; diff --git a/plugins/search-backend-module-stack-overflow-collator/src/index.ts b/plugins/search-backend-module-stack-overflow-collator/src/index.ts new file mode 100644 index 0000000000..00d57a7b27 --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports Stack Overflow modules. + */ + +export * from './collators'; +export { searchStackOverflowCollatorModule as default } from './module'; diff --git a/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.test.ts b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.test.ts new file mode 100644 index 0000000000..a785ead6eb --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { searchStackOverflowCollatorModule } from './SearchStackOverflowCollatorModule'; + +describe('searchStackOverflowCollatorModule', () => { + const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + it('should register the stack overflow collator to the search index registry extension point with factory and schedule', async () => { + const extensionPointMock = { + addCollator: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [ + [searchIndexRegistryExtensionPoint, extensionPointMock], + ], + features: [ + searchStackOverflowCollatorModule(), + mockServices.rootConfig.factory({ + data: { + stackoverflow: { + schedule, + }, + }, + }), + ], + }); + + expect(extensionPointMock.addCollator).toHaveBeenCalledTimes(1); + expect(extensionPointMock.addCollator).toHaveBeenCalledWith({ + factory: expect.objectContaining({ type: 'stack-overflow' }), + schedule: expect.objectContaining({ run: expect.any(Function) }), + }); + }); +}); diff --git a/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts new file mode 100644 index 0000000000..3ef3d72c32 --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/src/module/SearchStackOverflowCollatorModule.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { readTaskScheduleDefinitionFromConfig } from '@backstage/backend-tasks'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { StackOverflowQuestionsCollatorFactory } from '../collators'; + +/** + * @public + * Search backend module for the Stack Overflow index. + */ +export const searchStackOverflowCollatorModule = createBackendModule({ + moduleId: 'stackOverflowCollator', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + config: coreServices.rootConfig, + logger: coreServices.logger, + discovery: coreServices.discovery, + scheduler: coreServices.scheduler, + indexRegistry: searchIndexRegistryExtensionPoint, + }, + async init({ config, logger, scheduler, indexRegistry }) { + const defaultSchedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + const schedule = config.has('stackoverflow.schedule') + ? readTaskScheduleDefinitionFromConfig( + config.getConfig('stackoverflow.schedule'), + ) + : defaultSchedule; + + indexRegistry.addCollator({ + schedule: scheduler.createScheduledTaskRunner(schedule), + factory: StackOverflowQuestionsCollatorFactory.fromConfig(config, { + logger: loggerToWinstonLogger(logger), + }), + }); + }, + }); + }, +}); diff --git a/plugins/search-backend-module-stack-overflow-collator/src/module/index.ts b/plugins/search-backend-module-stack-overflow-collator/src/module/index.ts new file mode 100644 index 0000000000..ab424398e0 --- /dev/null +++ b/plugins/search-backend-module-stack-overflow-collator/src/module/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { searchStackOverflowCollatorModule } from './SearchStackOverflowCollatorModule'; diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 557b7edd13..fa8997a990 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.1.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 0.1.10-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index ec57b3f624..aa888a3d8a 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", "description": "A module for the search backend that exports techdocs modules", - "version": "0.1.10-next.2", + "version": "0.1.10", "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 58f334fb30..c2767e6463 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-node +## 1.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 1.2.10-next.2 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index a040f3a8f7..78d693466d 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.2.10-next.2", + "version": "1.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts index ae5a541e81..27cfae3fdf 100644 --- a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts +++ b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts @@ -329,11 +329,11 @@ export function parseHighlightFields({ const highlightedField = positions.reduce((content, pos) => { return ( - `${content.substring(0, pos[0])}${preTag}` + - `${content.substring(pos[0], pos[0] + pos[1])}` + - `${postTag}${content.substring(pos[0] + pos[1])}` + `${String(content).substring(0, pos[0])}${preTag}` + + `${String(content).substring(pos[0], pos[0] + pos[1])}` + + `${postTag}${String(content).substring(pos[0] + pos[1])}` ); - }, doc[field]); + }, doc[field] ?? ''); return [field, highlightedField]; }), diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index ea0a17908c..94f8c5d605 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend +## 1.4.6 + +### Patch Changes + +- 16be6f9473: Set the default length limit to search query to 100. To override it, define `search.maxTermLength` in the config file. +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-node@1.2.10 + - @backstage/plugin-permission-node@0.7.17 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 1.4.6-next.2 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index ead9e7f6b6..cd3c16efe2 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.4.6-next.2", + "version": "1.4.6", "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 f1ca109111..bfb7959327 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-common +## 1.2.7 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.9 + ## 1.2.7-next.0 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index 427d6b8498..3fe45d84d2 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.2.7-next.0", + "version": "1.2.7", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 0a5cc65d96..91ec2e4421 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-search-react +## 1.7.1 + +### Patch Changes + +- 06432f900c: Updated `/alpha` exports to use new `attachTo` option. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: The filter options passed to `SearchResultGroupLayout` are now always explicitly rendered as strings by default. +- 703a4ffc5b: Create `createSearchResultListItem` alpha version that only supports declarative integration. +- Updated dependencies + - @backstage/frontend-app-api@0.2.0 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 1.7.1-next.2 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index fa01c9cb5a..c2c181f657 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.7.1-next.2", + "version": "1.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,8 +62,8 @@ "react-use": "^17.3.2" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -72,8 +72,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0" }, "files": [ diff --git a/plugins/search-react/src/alpha.tsx b/plugins/search-react/src/alpha.tsx index 366112c95e..f937ef99cc 100644 --- a/plugins/search-react/src/alpha.tsx +++ b/plugins/search-react/src/alpha.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { lazy, Suspense } from 'react'; +import React, { lazy } from 'react'; import { ListItemProps } from '@material-ui/core'; @@ -25,7 +25,6 @@ import { createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; -import { Progress } from '@backstage/core-components'; import { SearchDocument, SearchResult } from '@backstage/plugin-search-common'; import { SearchResultListItemExtension } from './extensions'; @@ -87,6 +86,8 @@ export type SearchResultItemExtensionOptions< export function createSearchResultListItemExtension< TConfig extends { noTrack?: boolean }, >(options: SearchResultItemExtensionOptions) { + const id = `plugin.search.result.item.${options.id}`; + const configSchema = 'configSchema' in options ? options.configSchema @@ -95,15 +96,19 @@ export function createSearchResultListItemExtension< noTrack: z.boolean().default(false), }), ) as PortableSchema); + return createExtension({ - id: `plugin.search.result.item.${options.id}`, - attachTo: options.attachTo ?? { id: 'plugin.search.page', input: 'items' }, + id, + attachTo: options.attachTo ?? { + id: 'plugin.search.page', + input: 'items', + }, configSchema, output: { item: searchResultItemExtensionData, }, factory({ bind, config, source }) { - const LazyComponent = lazy(() => + const ExtensionComponent = lazy(() => options .component({ config }) .then(component => ({ default: component })), @@ -113,16 +118,14 @@ export function createSearchResultListItemExtension< item: { predicate: options.predicate, component: props => ( - - }> - - - - + + + + ), }, diff --git a/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx b/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx index ce3c285852..8a3dd84286 100644 --- a/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx +++ b/plugins/search-react/src/components/SearchBar/SearchBar.test.tsx @@ -318,7 +318,7 @@ describe('SearchBar', () => { , ); - const textbox = screen.getByLabelText('Search'); + const textbox = screen.getByLabelText('Search'); let value = 'value'; await user.type(textbox, value); @@ -339,6 +339,7 @@ describe('SearchBar', () => { value = 'new value'; await user.clear(textbox); + // make sure new term is captured await user.type(textbox, value); await waitFor(() => { diff --git a/plugins/search-react/src/components/SearchBar/SearchBar.tsx b/plugins/search-react/src/components/SearchBar/SearchBar.tsx index cfd0538694..d101efa669 100644 --- a/plugins/search-react/src/components/SearchBar/SearchBar.tsx +++ b/plugins/search-react/src/components/SearchBar/SearchBar.tsx @@ -30,6 +30,7 @@ import React, { KeyboardEvent, useCallback, useEffect, + useRef, useState, } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; @@ -88,14 +89,28 @@ export const SearchBarBase: ForwardRefExoticComponent = const configApi = useApi(configApiRef); const [value, setValue] = useState(''); + const forwardedValueRef = useRef(''); useEffect(() => { - setValue(prevValue => - prevValue !== defaultValue ? String(defaultValue) : prevValue, - ); - }, [defaultValue]); + setValue(prevValue => { + // We only update the value if our current value is the same as it was + // for the most recent onChange call. Otherwise it means that the users + // has continued typing and we should not replace their input. + if (prevValue === forwardedValueRef.current) { + return String(defaultValue); + } + return prevValue; + }); + }, [defaultValue, forwardedValueRef]); - useDebounce(() => onChange(value), debounceTime, [value]); + useDebounce( + () => { + forwardedValueRef.current = value; + onChange(value); + }, + debounceTime, + [value], + ); const handleChange = useCallback( (e: ChangeEvent) => { @@ -115,7 +130,9 @@ export const SearchBarBase: ForwardRefExoticComponent = ); const handleClear = useCallback(() => { + forwardedValueRef.current = ''; onChange(''); + setValue(''); if (onClear) { onClear(); } diff --git a/plugins/search-react/src/components/SearchFilter/SearchFilter.Autocomplete.test.tsx b/plugins/search-react/src/components/SearchFilter/SearchFilter.Autocomplete.test.tsx index e95f7fa856..abf5e828f6 100644 --- a/plugins/search-react/src/components/SearchFilter/SearchFilter.Autocomplete.test.tsx +++ b/plugins/search-react/src/components/SearchFilter/SearchFilter.Autocomplete.test.tsx @@ -364,7 +364,7 @@ describe('SearchFilter.Autocomplete', () => { }); // Blur the field and only one tag should be shown with a +1. - input.blur(); + await userEvent.tab(); expect( screen.queryByRole('button', { name: values[0] }), ).not.toBeInTheDocument(); diff --git a/plugins/search-react/src/components/SearchFilter/hooks.test.tsx b/plugins/search-react/src/components/SearchFilter/hooks.test.tsx index 5135cd4ae6..884512963f 100644 --- a/plugins/search-react/src/components/SearchFilter/hooks.test.tsx +++ b/plugins/search-react/src/components/SearchFilter/hooks.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { ApiProvider } from '@backstage/core-app-api'; import { MockConfigApi, TestApiRegistry } from '@backstage/test-utils'; -import { renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import { searchApiRef } from '../../api'; import { SearchContextProvider, useSearch } from '../../context'; @@ -67,7 +67,7 @@ describe('SearchFilter.hooks', () => { it('should set non-empty string value', async () => { const expectedFilter = 'someField'; const expectedValue = 'someValue'; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, expectedValue); return useSearch(); @@ -77,15 +77,15 @@ describe('SearchFilter.hooks', () => { }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should set non-empty array value', async () => { const expectedFilter = 'someField'; const expectedValue = ['someValue', 'anotherValue']; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, expectedValue); return useSearch(); @@ -95,134 +95,139 @@ describe('SearchFilter.hooks', () => { }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should not set undefined value', async () => { const expectedFilter = 'someField'; const expectedValue = 'notEmpty'; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, undefined); return useSearch(); }, { - wrapper, - initialProps: { - overrides: { - filters: { - [expectedFilter]: expectedValue, + wrapper: ({ children }) => + wrapper({ + children, + overrides: { + filters: { + [expectedFilter]: expectedValue, + }, }, - }, - }, + }), }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should not set null value', async () => { const expectedFilter = 'someField'; const expectedValue = 'notEmpty'; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, null); return useSearch(); }, { - wrapper, - initialProps: { - overrides: { - filters: { - [expectedFilter]: expectedValue, + wrapper: ({ children }) => + wrapper({ + children, + overrides: { + filters: { + [expectedFilter]: expectedValue, + }, }, - }, - }, + }), }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should not set empty string value', async () => { const expectedFilter = 'someField'; const expectedValue = 'notEmpty'; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, ''); return useSearch(); }, { - wrapper, - initialProps: { - overrides: { - filters: { - [expectedFilter]: expectedValue, + wrapper: ({ children }) => + wrapper({ + children, + overrides: { + filters: { + [expectedFilter]: expectedValue, + }, }, - }, - }, + }), }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should not set empty array value', async () => { const expectedFilter = 'someField'; const expectedValue = ['not', 'empty']; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, []); return useSearch(); }, { - wrapper, - initialProps: { - overrides: { - filters: { - [expectedFilter]: expectedValue, + wrapper: ({ children }) => + wrapper({ + children, + overrides: { + filters: { + [expectedFilter]: expectedValue, + }, }, - }, - }, + }), }, ); - await waitForNextUpdate(); - - expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + await waitFor(() => { + expect(result.current.filters[expectedFilter]).toEqual(expectedValue); + }); }); it('should not affect unrelated filters', async () => { const expectedFilter = 'someField'; const expectedValue = 'someValue'; - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => { useDefaultFilterValue(expectedFilter, expectedValue); return useSearch(); }, { - wrapper, - initialProps: { - overrides: { - filters: { - unrelatedField: 'unrelatedValue', + wrapper: ({ children }) => + wrapper({ + children, + overrides: { + filters: { + unrelatedField: 'unrelatedValue', + }, }, - }, - }, + }), }, ); - await waitForNextUpdate(); - - expect(result.current.filters.unrelatedField).toEqual('unrelatedValue'); + await waitFor(() => { + expect(result.current.filters.unrelatedField).toEqual('unrelatedValue'); + }); }); }); @@ -240,14 +245,15 @@ describe('SearchFilter.hooks', () => { it('should return resolved values of provided async function', async () => { const expectedValues = ['value1', 'value2']; const asyncFn = () => Promise.resolve(expectedValues); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useAsyncFilterValues(asyncFn, '', undefined, 1000), ); expect(result.current.loading).toEqual(true); - jest.runAllTimers(); - await waitForNextUpdate(); + await act(async () => { + jest.runAllTimers(); + }); expect(result.current.loading).toEqual(false); expect(result.current.value).toEqual(expectedValues); @@ -261,11 +267,15 @@ describe('SearchFilter.hooks', () => { expect(asyncFn).not.toHaveBeenCalled(); // Advance timers by 600ms - jest.advanceTimersByTime(600); + await act(async () => { + jest.advanceTimersByTime(600); + }); expect(asyncFn).not.toHaveBeenCalled(); // Another 600ms to exceed the 1000ms debounce - jest.advanceTimersByTime(600); + await act(async () => { + jest.advanceTimersByTime(600); + }); expect(asyncFn).toHaveBeenCalled(); }); @@ -273,21 +283,23 @@ describe('SearchFilter.hooks', () => { const asyncFn = jest .fn() .mockImplementation((x: string) => Promise.resolve([x])); - const { rerender, waitForNextUpdate } = renderHook( + const { rerender } = renderHook( (props: { inputValue: string } = { inputValue: '' }) => useAsyncFilterValues(asyncFn, props.inputValue, undefined, 1000), ); expect(asyncFn).not.toHaveBeenCalled(); - jest.runAllTimers(); - await waitForNextUpdate(); + await act(async () => { + jest.runAllTimers(); + }); expect(asyncFn).toHaveBeenCalledTimes(1); expect(asyncFn).toHaveBeenCalledWith(''); // Re-render with different input value. rerender({ inputValue: 'somethingElse' }); - jest.runAllTimers(); - await waitForNextUpdate(); + await act(async () => { + jest.runAllTimers(); + }); expect(asyncFn).toHaveBeenCalledTimes(2); expect(asyncFn).toHaveBeenLastCalledWith('somethingElse'); }); @@ -295,15 +307,16 @@ describe('SearchFilter.hooks', () => { it('should not call provided method more than once when re-rendered with same input', async () => { const expectedValues = ['value1', 'value2']; const asyncFn = jest.fn().mockResolvedValue(expectedValues); - const { rerender, waitForNextUpdate } = renderHook( + const { rerender } = renderHook( (props: { inputValue: string } = { inputValue: '' }) => useAsyncFilterValues(asyncFn, props.inputValue, undefined, 1000), ); expect(asyncFn).not.toHaveBeenCalled(); - jest.runAllTimers(); - await waitForNextUpdate(); + await act(async () => { + jest.runAllTimers(); + }); expect(asyncFn).toHaveBeenCalledTimes(1); // Re-render multiple times with the same input. diff --git a/plugins/search-react/src/context/SearchContext.test.tsx b/plugins/search-react/src/context/SearchContext.test.tsx index df71a848b0..5aa217553f 100644 --- a/plugins/search-react/src/context/SearchContext.test.tsx +++ b/plugins/search-react/src/context/SearchContext.test.tsx @@ -15,8 +15,13 @@ */ import { configApiRef } from '@backstage/core-plugin-api'; -import { render, screen, waitFor } from '@testing-library/react'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { + render, + screen, + waitFor, + act, + renderHook, +} from '@testing-library/react'; import { MockConfigApi, TestApiProvider } from '@backstage/test-utils'; import React from 'react'; import { @@ -70,10 +75,8 @@ describe('SearchContext', () => { }); it('Throws error when no context is set', () => { - const { result } = renderHook(() => useSearch()); - - expect(result.error).toEqual( - Error('useSearch must be used within a SearchContextProvider'), + expect(() => renderHook(() => useSearch())).toThrow( + 'useSearch must be used within a SearchContextProvider', ); }); @@ -82,203 +85,188 @@ describe('SearchContext', () => { expect(hook.result.current).toEqual(false); - const { result, waitForNextUpdate } = renderHook( - () => useSearchContextCheck(), - { - wrapper, - initialProps: { - initialState, - }, - }, - ); + const { result } = renderHook(() => useSearchContextCheck(), { + wrapper: ({ children }) => wrapper({ children, initialState }), + }); - await waitForNextUpdate(); - - expect(result.current).toEqual(true); + await waitFor(() => { + expect(result.current).toEqual(true); + }); }); describe('Uses initial state values', () => { it('Uses default initial state values', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { + const { result } = renderHook(() => useSearch(), { wrapper, }); - await waitForNextUpdate(); - - expect(result.current).toEqual( - expect.objectContaining({ - term: '', - types: [], - filters: {}, - pageLimit: undefined, - pageCursor: undefined, - }), - ); + await waitFor(() => { + expect(result.current).toEqual( + expect.objectContaining({ + term: '', + types: [], + filters: {}, + pageLimit: undefined, + pageCursor: undefined, + }), + ); + }); }); it('Uses provided initial state values', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); - - expect(result.current).toEqual(expect.objectContaining(initialState)); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); }); it('Uses page limit provided via config api', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - config: { - search: { - query: { - pageLimit: 100, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => + wrapper({ + children, + initialState, + config: { + search: { + query: { + pageLimit: 100, + }, }, }, - }, - }, + }), }); - await waitForNextUpdate(); - - expect(result.current).toEqual( - expect.objectContaining({ ...initialState, pageLimit: 100 }), - ); + await waitFor(() => { + expect(result.current).toEqual( + expect.objectContaining({ ...initialState, pageLimit: 100 }), + ); + }); }); }); describe('Resets cursor', () => { it('When term is cleared', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState: { - ...initialState, - term: 'first term', - pageCursor: 'SOMEPAGE', - }, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => + wrapper({ + children, + initialState: { + ...initialState, + term: 'first term', + pageCursor: 'SOMEPAGE', + }, + }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.term).toEqual('first term'); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + }); - expect(result.current.term).toEqual('first term'); - expect(result.current.pageCursor).toEqual('SOMEPAGE'); - - act(() => { + await act(async () => { result.current.setTerm(''); }); - await waitForNextUpdate(); - expect(result.current.pageCursor).toBeUndefined(); }); it('When term is set (and different from previous)', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState: { - ...initialState, - term: 'first term', - pageCursor: 'SOMEPAGE', - }, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => + wrapper({ + children, + initialState: { + ...initialState, + term: 'first term', + pageCursor: 'SOMEPAGE', + }, + }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.term).toEqual('first term'); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + }); - expect(result.current.term).toEqual('first term'); - expect(result.current.pageCursor).toEqual('SOMEPAGE'); - - act(() => { + await act(async () => { result.current.setTerm('second term'); }); - await waitForNextUpdate(); - expect(result.current.pageCursor).toBeUndefined(); }); it('When filters are cleared', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState: { - ...initialState, - term: 'first term', - filters: { foo: 'bar' }, - pageCursor: 'SOMEPAGE', - }, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => + wrapper({ + children, + initialState: { + ...initialState, + term: 'first term', + filters: { foo: 'bar' }, + pageCursor: 'SOMEPAGE', + }, + }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.filters).toEqual({ foo: 'bar' }); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + }); - expect(result.current.filters).toEqual({ foo: 'bar' }); - expect(result.current.pageCursor).toEqual('SOMEPAGE'); - - act(() => { + await act(async () => { result.current.setFilters({}); }); - await waitForNextUpdate(); - expect(result.current.pageCursor).toBeUndefined(); }); it('When filters are set (and different from previous)', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState: { - ...initialState, - term: 'first term', - filters: { foo: 'bar' }, - pageCursor: 'SOMEPAGE', - }, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => + wrapper({ + children, + initialState: { + ...initialState, + term: 'first term', + filters: { foo: 'bar' }, + pageCursor: 'SOMEPAGE', + }, + }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current.filters).toEqual({ foo: 'bar' }); + expect(result.current.pageCursor).toEqual('SOMEPAGE'); + }); - expect(result.current.filters).toEqual({ foo: 'bar' }); - expect(result.current.pageCursor).toEqual('SOMEPAGE'); - - act(() => { + await act(async () => { result.current.setFilters({ foo: 'test' }); }); - await waitForNextUpdate(); - expect(result.current.pageCursor).toBeUndefined(); }); }); describe('Performs search (and sets results)', () => { it('When term is set', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); const term = 'term'; - act(() => { + await act(async () => { result.current.setTerm(term); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ term, types: ['*'], @@ -287,23 +275,20 @@ describe('SearchContext', () => { }); it('When types is set', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); const types = ['type']; - act(() => { + await act(async () => { result.current.setTypes(types); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ types, term: '', @@ -312,23 +297,20 @@ describe('SearchContext', () => { }); it('When filters are set', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); const filters = { filter: 'filter' }; - act(() => { + await act(async () => { result.current.setFilters(filters); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ filters, term: '', @@ -337,23 +319,20 @@ describe('SearchContext', () => { }); it('When page limit is set', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); const pageLimit = 30; - act(() => { + await act(async () => { result.current.setPageLimit(pageLimit); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ pageLimit, term: '', @@ -363,23 +342,20 @@ describe('SearchContext', () => { }); it('When page cursor is set', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); const pageCursor = 'SOMEPAGE'; - act(() => { + await act(async () => { result.current.setPageCursor(pageCursor); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ pageCursor, term: '', @@ -394,24 +370,21 @@ describe('SearchContext', () => { nextPageCursor: 'NEXT', }); - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); expect(result.current.fetchNextPage).toBeDefined(); expect(result.current.fetchPreviousPage).toBeUndefined(); - act(() => { + await act(async () => { result.current.fetchNextPage!(); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ term: '', types: ['*'], @@ -426,24 +399,21 @@ describe('SearchContext', () => { previousPageCursor: 'PREVIOUS', }); - const { result, waitForNextUpdate } = renderHook(() => useSearch(), { - wrapper, - initialProps: { - initialState, - }, + const { result } = renderHook(() => useSearch(), { + wrapper: ({ children }) => wrapper({ children, initialState }), }); - await waitForNextUpdate(); + await waitFor(() => { + expect(result.current).toEqual(expect.objectContaining(initialState)); + }); expect(result.current.fetchNextPage).toBeUndefined(); expect(result.current.fetchPreviousPage).toBeDefined(); - act(() => { + await act(async () => { result.current.fetchPreviousPage!(); }); - await waitForNextUpdate(); - expect(searchApiMock.query).toHaveBeenLastCalledWith({ term: '', types: ['*'], diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 067c7dfc41..ff8d87c347 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-search +## 1.4.1 + +### Patch Changes + +- e5a2956dd2: Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 0296f272b4: Minor internal code cleanup. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/version-bridge@1.0.6 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 1.4.1-next.2 ### Patch Changes diff --git a/plugins/search/alpha-api-report.md b/plugins/search/alpha-api-report.md index 58c963b1d6..99f3d07b57 100644 --- a/plugins/search/alpha-api-report.md +++ b/plugins/search/alpha-api-report.md @@ -3,13 +3,17 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + root: RouteRef; + }, + {} +>; export default _default; // @alpha (undocumented) diff --git a/plugins/search/package.json b/plugins/search/package.json index e4e5ee5aa0..23abaefa1d 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.4.1-next.2", + "version": "1.4.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -66,8 +66,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -77,8 +77,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "history": "^5.0.0", "msw": "^1.0.0" diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index f1c4f68d02..14e7067dfa 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -28,7 +28,6 @@ import { useSidebarPinState, } from '@backstage/core-components'; import { - createRouteRef, useApi, DiscoveryApi, IdentityApi, @@ -64,9 +63,11 @@ import { SearchResult } from '@backstage/plugin-search-common'; import { searchApiRef } from '@backstage/plugin-search-react'; import { searchResultItemExtensionData } from '@backstage/plugin-search-react/alpha'; +import { rootRouteRef } from './plugin'; import { SearchClient } from './apis'; import { SearchType } from './components/SearchType'; import { UrlUpdater } from './components/SearchPage/SearchPage'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; /** @alpha */ export const SearchApi = createApiExtension({ @@ -95,12 +96,10 @@ const useSearchPageStyles = makeStyles((theme: Theme) => ({ }, })); -const searchRouteRef = createRouteRef({ id: 'plugin.search.page' }); - /** @alpha */ export const SearchPage = createPageExtension({ id: 'plugin.search.page', - routeRef: searchRouteRef, + routeRef: convertLegacyRouteRef(rootRouteRef), configSchema: createSchemaFromZod(z => z.object({ path: z.string().default('/search'), @@ -237,13 +236,16 @@ export const SearchPage = createPageExtension({ /** @alpha */ export const SearchNavItem = createNavItemExtension({ id: 'plugin.search.nav.index', - routeRef: searchRouteRef, + routeRef: convertLegacyRouteRef(rootRouteRef), title: 'Search', icon: SearchIcon, }); /** @alpha */ export default createPlugin({ - id: 'plugin.search', + id: 'search', extensions: [SearchApi, SearchPage, SearchNavItem], + routes: { + root: convertLegacyRouteRef(rootRouteRef), + }, }); diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index 274f9e21a1..0d0bfdef5c 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -203,9 +203,8 @@ describe('SearchModal', () => { expect.objectContaining({ term: 'term' }), ); - const input = screen.getByLabelText('Search'); + const input = screen.getByLabelText('Search'); await userEvent.clear(input); - await 'a tick'; await userEvent.type(input, 'new term{enter}'); expect(navigate).toHaveBeenCalledWith('/search?query=new term'); diff --git a/plugins/search/src/components/SearchModal/useSearchModal.test.tsx b/plugins/search/src/components/SearchModal/useSearchModal.test.tsx index e21f864ac2..a78f9b92af 100644 --- a/plugins/search/src/components/SearchModal/useSearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/useSearchModal.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { useSearchModal } from './useSearchModal'; import { BrowserRouter, Router } from 'react-router-dom'; import { createMemoryHistory } from 'history'; diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 7794d30a34..77895eb2f1 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-sentry +## 0.5.10 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.5.10-next.2 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index cc9c553bf1..3856270628 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.5.10-next.2", + "version": "0.5.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,8 +50,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/luxon": "^3.0.0", "cross-fetch": "^3.1.5", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index 49298f1942..6774c7eaf2 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-shortcuts +## 0.3.15 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + ## 0.3.15-next.2 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index db2a5ab6fb..c38125d561 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.15-next.2", + "version": "0.3.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ "zen-observable": "^0.10.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -55,7 +55,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/zen-observable": "^0.8.2", "msw": "^1.0.0" diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index 72533260d3..caf2a677c1 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sonarqube-backend +## 0.2.8 + +### Patch Changes + +- a5d592d0ad: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/config@1.1.1 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 2b9baba2de..63592380db 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.2.8-next.2", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-react/CHANGELOG.md b/plugins/sonarqube-react/CHANGELOG.md index 9bf9e3177f..af370f6d1a 100644 --- a/plugins/sonarqube-react/CHANGELOG.md +++ b/plugins/sonarqube-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-sonarqube-react +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/catalog-model@1.4.3 + ## 0.1.9-next.1 ### Patch Changes diff --git a/plugins/sonarqube-react/package.json b/plugins/sonarqube-react/package.json index 958c41dde9..c643df3702 100644 --- a/plugins/sonarqube-react/package.json +++ b/plugins/sonarqube-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-react", - "version": "0.1.9-next.1", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "@backstage/core-plugin-api": "workspace:^" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index f8e8b1dde1..3ed88667a9 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-sonarqube +## 0.7.6 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + - @backstage/plugin-sonarqube-react@0.1.9 + ## 0.7.6-next.2 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index b99233d945..00d6c494db 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.7.6-next.2", + "version": "0.7.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,8 +53,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -64,7 +64,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 086deabcb7..4b1ac632d1 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-splunk-on-call +## 0.4.14 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.4.3 + ## 0.4.14-next.2 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 5066b28a52..e07a08254f 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.4.14-next.2", + "version": "0.4.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,8 +48,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -59,7 +59,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/luxon": "^3.0.0", "msw": "^1.0.0" diff --git a/plugins/splunk-on-call/src/components/Incident/Incidents.test.tsx b/plugins/splunk-on-call/src/components/Incident/Incidents.test.tsx index 665dd3281c..9b8d5feb97 100644 --- a/plugins/splunk-on-call/src/components/Incident/Incidents.test.tsx +++ b/plugins/splunk-on-call/src/components/Incident/Incidents.test.tsx @@ -34,8 +34,12 @@ const apis = TestApiRegistry.from( ); describe('Incidents', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); afterEach(() => { jest.resetAllMocks(); + jest.useRealTimers(); }); it('Renders an empty state when there are no incidents', async () => { @@ -47,13 +51,10 @@ describe('Incidents', () => { , ); - await waitFor(() => !screen.queryByTestId('progress')); - await waitFor( - () => - expect( - screen.getByText('Nice! No incidents found!'), - ).toBeInTheDocument(), - { timeout: 2000 }, + jest.advanceTimersByTime(2000); + await waitFor(() => expect(screen.queryByTestId('progress')).toBe(null)); + await waitFor(() => + expect(screen.getByText('Nice! No incidents found!')).toBeInTheDocument(), ); }); @@ -66,15 +67,14 @@ describe('Incidents', () => { , ); - await waitFor(() => !screen.queryByTestId('progress')); - await waitFor( - () => - expect( - screen.getByText('user', { - exact: false, - }), - ).toBeInTheDocument(), - { timeout: 2000 }, + jest.advanceTimersByTime(2000); + await waitFor(() => expect(screen.queryByTestId('progress')).toBe(null)); + await waitFor(() => + expect( + screen.getByText('user', { + exact: false, + }), + ).toBeInTheDocument(), ); expect(screen.getByText('test-incident')).toBeInTheDocument(); expect(screen.getByTitle('Acknowledged')).toBeInTheDocument(); @@ -93,15 +93,14 @@ describe('Incidents', () => { , ); - await waitFor(() => !screen.queryByTestId('progress')); - await waitFor( - () => - expect( - screen.getByText('user', { - exact: false, - }), - ).toBeInTheDocument(), - { timeout: 2000 }, + jest.advanceTimersByTime(2000); + await waitFor(() => expect(screen.queryByTestId('progress')).toBe(null)); + await waitFor(() => + expect( + screen.getByText('user', { + exact: false, + }), + ).toBeInTheDocument(), ); expect(screen.getByText('test-incident')).toBeInTheDocument(); expect(screen.getByLabelText('Status warning')).toBeInTheDocument(); @@ -127,15 +126,14 @@ describe('Incidents', () => { , ); - await waitFor(() => !screen.queryByTestId('progress')); - await waitFor( - () => - expect( - screen.getByText( - 'Error encountered while fetching information. Error occurred', - ), - ).toBeInTheDocument(), - { timeout: 2000 }, + jest.advanceTimersByTime(2000); + await waitFor(() => expect(screen.queryByTestId('progress')).toBe(null)); + await waitFor(() => + expect( + screen.getByText( + 'Error encountered while fetching information. Error occurred', + ), + ).toBeInTheDocument(), ); }); }); diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index 588eb3e4c0..bb83becff1 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-stack-overflow-backend +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/stack-overflow-backend/README.md b/plugins/stack-overflow-backend/README.md index 4575ab58c0..8129d36e38 100644 --- a/plugins/stack-overflow-backend/README.md +++ b/plugins/stack-overflow-backend/README.md @@ -1,64 +1,3 @@ -# Stack Overflow +# Stack Overflow Backend -A plugin that provides stack overflow specific functionality that can be used in different ways (e.g. for search) to compose your Backstage App. - -## Getting started - -Before we begin, make sure: - -- You have created your own standalone Backstage app using @backstage/create-app and not using a fork of the backstage repository. If you haven't setup Backstage already, start [here](https://backstage.io/docs/getting-started/). - -To use any of the functionality this plugin provides, you need to start by configuring your App with the following config: - -```yaml -stackoverflow: - baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance -``` - -### Stack Overflow for Teams - -If you have a private Stack Overflow instance and/or a private Stack Overflow Team you will need to supply an API key or Personal Access Token. You can read more about how to set this up by going to [Stack Overflow's Help Page](https://stackoverflow.help/en/articles/4385859-stack-overflow-for-teams-api). - -The existing API key approach remains the default, to support the new v2.3 API and PAT authentication model you need to pass the team name and the new PAT into the existing apiAccessToken parameter to the new URL. See [15770](https://github.com/backstage/backstage/issues/15770) for more details. - -```yaml -stackoverflow: - baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance - apiKey: $STACK_OVERFLOW_API_KEY - apiAccessToken: $STACK_OVERFLOW_API_ACCESS_TOKEN -``` - -```yaml -stackoverflow: - baseUrl: https://api.stackoverflowteams.com/2.3 # alternative: your internal stack overflow instance - teamName: $STACK_OVERFLOW_TEAM_NAME - apiAccessToken: $STACK_OVERFLOW_API_ACCESS_TOKEN -``` - -## Areas of Responsibility - -This stack overflow backend plugin is primarily responsible for the following: - -- Provides a `StackOverflowQuestionsCollatorFactory`, which can be used in the search backend to index stack overflow questions to your Backstage Search. - -### Index Stack Overflow Questions to search - -Before you are able to start index stack overflow questions to search, you need to go through the [search getting started guide](https://backstage.io/docs/features/search/getting-started). - -When you have your `packages/backend/src/plugins/search.ts` file ready to make modifications, add the following code snippet to add the `StackOverflowQuestionsCollatorFactory`. Note that you can modify the `requestParams`. - -> Note: if your `baseUrl` is set to the external stack overflow api `https://api.stackexchange.com/2.2`, you can find optional and required parameters under the official API documentation under [`Usage of /questions GET`](https://api.stackexchange.com/docs/questions) - -```ts -indexBuilder.addCollator({ - schedule, - factory: StackOverflowQuestionsCollatorFactory.fromConfig(env.config, { - logger: env.logger, - requestParams: { - tagged: ['backstage'], - site: 'stackoverflow', - pagesize: 100, - }, - }), -}); -``` +Deprecated, consider using `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. diff --git a/plugins/stack-overflow-backend/api-report.md b/plugins/stack-overflow-backend/api-report.md index 8c601399c1..14dcdf2007 100644 --- a/plugins/stack-overflow-backend/api-report.md +++ b/plugins/stack-overflow-backend/api-report.md @@ -3,54 +3,21 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// +import { StackOverflowDocument as StackOverflowDocument_2 } from '@backstage/plugin-search-backend-module-stack-overflow-collator'; +import { StackOverflowQuestionsCollatorFactory as StackOverflowQuestionsCollatorFactory_2 } from '@backstage/plugin-search-backend-module-stack-overflow-collator'; +import { StackOverflowQuestionsRequestParams as StackOverflowQuestionsRequestParams_2 } from '@backstage/plugin-search-backend-module-stack-overflow-collator'; -import { Config } from '@backstage/config'; -import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; -import { IndexableDocument } from '@backstage/plugin-search-common'; -import { Logger } from 'winston'; -import { Readable } from 'stream'; +// @public @deprecated (undocumented) +export type StackOverflowDocument = StackOverflowDocument_2; -// @public -export interface StackOverflowDocument extends IndexableDocument { - // (undocumented) - answers: number; - // (undocumented) - tags: string[]; -} +// @public @deprecated (undocumented) +export const StackOverflowQuestionsCollatorFactory: typeof StackOverflowQuestionsCollatorFactory_2; -// @public -export class StackOverflowQuestionsCollatorFactory - implements DocumentCollatorFactory -{ - // (undocumented) - execute(): AsyncGenerator; - // (undocumented) - static fromConfig( - config: Config, - options: StackOverflowQuestionsCollatorFactoryOptions, - ): StackOverflowQuestionsCollatorFactory; - // (undocumented) - getCollator(): Promise; - // (undocumented) - protected requestParams: StackOverflowQuestionsRequestParams; - // (undocumented) - readonly type: string; -} +// @public @deprecated (undocumented) +export type StackOverflowQuestionsCollatorFactoryOptions = + StackOverflowQuestionsCollatorFactory_2; -// @public -export type StackOverflowQuestionsCollatorFactoryOptions = { - baseUrl?: string; - maxPage?: number; - apiKey?: string; - apiAccessToken?: string; - teamName?: string; - requestParams: StackOverflowQuestionsRequestParams; - logger: Logger; -}; - -// @public -export type StackOverflowQuestionsRequestParams = { - [key: string]: string | string[] | number; -}; +// @public @deprecated (undocumented) +export type StackOverflowQuestionsRequestParams = + StackOverflowQuestionsRequestParams_2; ``` diff --git a/plugins/stack-overflow-backend/config.d.ts b/plugins/stack-overflow-backend/config.d.ts index b97f237c19..613a7aa887 100644 --- a/plugins/stack-overflow-backend/config.d.ts +++ b/plugins/stack-overflow-backend/config.d.ts @@ -40,5 +40,12 @@ export interface Config { * @visibility secret */ apiAccessToken?: string; + + /** + * Type representing the request parameters. + */ + requestParams?: { + [key: string]: string | string[] | number; + }; }; } diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 17f5edd9ad..77ebd8c69e 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,6 +1,7 @@ { "name": "@backstage/plugin-stack-overflow-backend", - "version": "0.2.10-next.2", + "description": "Deprecated, consider using @backstage/plugin-search-backend-module-stack-overflow-collator instead", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,6 +35,7 @@ "dependencies": { "@backstage/backend-common": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "node-fetch": "^2.6.7", "qs": "^6.9.4", diff --git a/plugins/stack-overflow-backend/src/index.ts b/plugins/stack-overflow-backend/src/index.ts index 6e461b8183..5ca1c8d283 100644 --- a/plugins/stack-overflow-backend/src/index.ts +++ b/plugins/stack-overflow-backend/src/index.ts @@ -15,9 +15,46 @@ */ /** - * Stack Overflow backend plugin - * * @packageDocumentation + * Stack Overflow backend plugin + * @deprecated + * Deprecated, consider using `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. */ -export * from './search'; +import { + StackOverflowDocument as _StackOverflowDocument, + StackOverflowQuestionsRequestParams as _StackOverflowQuestionsRequestParams, + StackOverflowQuestionsCollatorFactory as _StackOverflowQuestionsCollatorFactory, + StackOverflowQuestionsCollatorFactoryOptions as _StackOverflowQuestionsCollatorFactoryOptions, +} from '@backstage/plugin-search-backend-module-stack-overflow-collator'; + +/** + * @public + * @deprecated + * Import from `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. + */ +export type StackOverflowDocument = _StackOverflowDocument; + +/** + * @public + * @deprecated + * Import from `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. + */ +export type StackOverflowQuestionsRequestParams = + _StackOverflowQuestionsRequestParams; + +/** + * @public + * @deprecated + * Import from `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. + */ +export type StackOverflowQuestionsCollatorFactoryOptions = + _StackOverflowQuestionsCollatorFactory; + +/** + * @public + * @deprecated + * Import from `@backstage/plugin-search-backend-module-stack-overflow-collator` instead. + */ +export const StackOverflowQuestionsCollatorFactory = + _StackOverflowQuestionsCollatorFactory; diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index cb9d27d7e1..7ff52c4364 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-stack-overflow +## 0.1.21 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-home-react@0.1.4 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 0.1.21-next.2 ### Patch Changes diff --git a/plugins/stack-overflow/alpha-api-report.md b/plugins/stack-overflow/alpha-api-report.md new file mode 100644 index 0000000000..167f8e1736 --- /dev/null +++ b/plugins/stack-overflow/alpha-api-report.md @@ -0,0 +1,13 @@ +## API Report File for "@backstage/plugin-stack-overflow" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin<{}, {}>; +export default _default; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 857b6f22cf..431f8a5b80 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -1,13 +1,26 @@ { "name": "@backstage/plugin-stack-overflow", - "version": "0.1.21-next.2", + "version": "0.1.21", "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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -32,6 +45,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-home-react": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", @@ -46,8 +60,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +70,7 @@ "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/stack-overflow/src/alpha.tsx b/plugins/stack-overflow/src/alpha.tsx new file mode 100644 index 0000000000..3708271ef1 --- /dev/null +++ b/plugins/stack-overflow/src/alpha.tsx @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { configApiRef, createApiFactory } from '@backstage/core-plugin-api'; +import { + createApiExtension, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; +import { StackOverflowClient, stackOverflowApiRef } from './api'; + +/** @alpha */ +const StackOverflowApi = createApiExtension({ + factory: createApiFactory({ + api: stackOverflowApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => StackOverflowClient.fromConfig(configApi), + }), +}); + +/** @alpha */ +const StackOverflowSearchResultListItem = createSearchResultListItemExtension({ + id: 'stack-overflow', + predicate: result => result.type === 'stack-overflow', + component: () => + import('./search/StackOverflowSearchResultListItem').then( + m => m.StackOverflowSearchResultListItem, + ), +}); + +/** @alpha */ +export default createPlugin({ + id: 'stack-overflow', + // TODO: Migrate homepage cards when the declarative homepage plugin supports them + extensions: [StackOverflowApi, StackOverflowSearchResultListItem], +}); diff --git a/plugins/stackstorm/CHANGELOG.md b/plugins/stackstorm/CHANGELOG.md index 199e2e320e..d831792629 100644 --- a/plugins/stackstorm/CHANGELOG.md +++ b/plugins/stackstorm/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-stackstorm +## 0.1.7 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/stackstorm/package.json b/plugins/stackstorm/package.json index a0c2a0ecdf..76f9958812 100644 --- a/plugins/stackstorm/package.json +++ b/plugins/stackstorm/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stackstorm", "description": "A Backstage plugin that integrates towards StackStorm", - "version": "0.1.7-next.2", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 531e00b079..f319b515ec 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.38 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/config@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.1.38-next.2 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 496b61cf7b..17fa4702e3 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.38-next.2", + "version": "0.1.38", "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 9a41dd8389..fcd5520d29 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-tech-insights-backend +## 0.5.20 + +### Patch Changes + +- cc7dddfa7f: Increase the maximum allowed length of an entity filter for tech insights fact schemas. +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-node@0.4.12 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.5.20-next.2 ### Patch Changes diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 048ea64364..1dda0595f5 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.20-next.2", + "version": "0.5.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts index 846871db88..b723fcd7f5 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts @@ -175,6 +175,7 @@ export class DefaultFactRetrieverEngine implements FactRetrieverEngine { try { facts = await factRetriever.handler({ ...this.factRetrieverContext, + logger: this.logger.child({ factRetrieverId: factRetriever.id }), entityFilter: factRetriever.entityFilter, }); this.logger.debug( diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index fa99e50423..37117bc0d8 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-node +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.4.12-next.2 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 1d72568bc9..23863a774d 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.4.12-next.2", + "version": "0.4.12", "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 ee64de0b64..83644ecdab 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-tech-insights +## 0.3.17 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 21f409d776: Export `ScorecardInfo` and `ScorecardsList` components to be able to use manually queried check results directly. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.3.17-next.2 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index e8d9d7a12c..7735fb3719 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.17-next.2", + "version": "0.3.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,8 +45,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -56,7 +56,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index b182aa25a9..276c50be04 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-tech-radar +## 0.6.9 + +### Patch Changes + +- 0b55f773a7: Removed some unused dependencies +- c09d2fa1d6: Added experimental support for the declarative integration. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/theme@0.4.3 + ## 0.6.9-next.2 ### Patch Changes diff --git a/plugins/tech-radar/alpha-api-report.md b/plugins/tech-radar/alpha-api-report.md index 9245acfaf2..da8f12cf0e 100644 --- a/plugins/tech-radar/alpha-api-report.md +++ b/plugins/tech-radar/alpha-api-report.md @@ -3,13 +3,17 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + root: RouteRef; + }, + {} +>; export default _default; // @alpha (undocumented) diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index d954c71a0c..82fd7ca147 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.6.9-next.2", + "version": "0.6.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,8 +59,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -70,7 +70,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/color": "^3.0.1", "@types/d3-force": "^3.0.0", diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx index 6a2ec882ba..78230c0337 100644 --- a/plugins/tech-radar/src/alpha.tsx +++ b/plugins/tech-radar/src/alpha.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createApiFactory, createRouteRef } from '@backstage/core-plugin-api'; +import { createApiFactory } from '@backstage/core-plugin-api'; import { createApiExtension, createPageExtension, @@ -24,14 +24,14 @@ import { import React from 'react'; import { techRadarApiRef } from './api'; import { SampleTechRadarApi } from './sample'; - -const techRadarRouteRef = createRouteRef({ id: 'plugin.techradar.page' }); +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { rootRouteRef } from './plugin'; /** @alpha */ export const TechRadarPage = createPageExtension({ id: 'plugin.techradar.page', defaultPath: '/tech-radar', - routeRef: techRadarRouteRef, + routeRef: convertLegacyRouteRef(rootRouteRef), configSchema: createSchemaFromZod(z => z.object({ title: z.string().default('Tech Radar'), @@ -59,4 +59,7 @@ const sampleTechRadarApi = createApiExtension({ export default createPlugin({ id: 'tech-radar', extensions: [TechRadarPage, sampleTechRadarApi], + routes: { + root: convertLegacyRouteRef(rootRouteRef), + }, }); diff --git a/plugins/tech-radar/src/plugin.ts b/plugins/tech-radar/src/plugin.ts index 7f042a1b6f..3a8e0a5f2d 100644 --- a/plugins/tech-radar/src/plugin.ts +++ b/plugins/tech-radar/src/plugin.ts @@ -23,7 +23,7 @@ import { createApiFactory, } from '@backstage/core-plugin-api'; -const rootRouteRef = createRouteRef({ +export const rootRouteRef = createRouteRef({ id: 'tech-radar', }); diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 321bf0737e..e215d3d842 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.22 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog@1.14.0 + - @backstage/test-utils@1.4.4 + - @backstage/core-app-api@1.11.0 + - @backstage/plugin-techdocs@1.8.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + ## 1.0.22-next.2 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 90fac69b95..b65cc1d2b1 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.22-next.2", + "version": "1.0.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,14 +46,14 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@types/react": "^16.13.1 || ^17.0.0", "react-use": "^17.2.4", "testing-library__dom": "^7.29.4-beta.1" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,6 @@ "@backstage/dev-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/techdocs-addons-test-utils/src/test-utils.tsx b/plugins/techdocs-addons-test-utils/src/test-utils.tsx index 1a921437b1..865e8c0d3b 100644 --- a/plugins/techdocs-addons-test-utils/src/test-utils.tsx +++ b/plugins/techdocs-addons-test-utils/src/test-utils.tsx @@ -19,7 +19,6 @@ import React, { ReactElement } from 'react'; // Shadow DOM support for the simple and complete DOM testing utilities // https://github.com/testing-library/dom-testing-library/issues/742#issuecomment-674987855 import { screen } from 'testing-library__dom'; -import { renderToStaticMarkup } from 'react-dom/server'; import { Route } from 'react-router-dom'; import { act, render } from '@testing-library/react'; @@ -39,6 +38,13 @@ import { catalogPlugin } from '@backstage/plugin-catalog'; import { searchApiRef } from '@backstage/plugin-search-react'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; +// Since React 18 react-dom/server eagerly uses TextEncoder, so lazy load and make it available globally first +if (!global.TextEncoder) { + global.TextEncoder = require('util').TextEncoder; +} +const { renderToStaticMarkup } = + require('react-dom/server') as typeof import('react-dom/server'); + const techdocsApi = { getTechDocsMetadata: jest.fn(), getEntityMetadata: jest.fn(), diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index caa2e42dcf..ad2b8f67ed 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-techdocs-backend +## 1.8.0 + +### Minor Changes + +- 344cfbcfbc: Allow prepared directory clean up for custom preparers + + When using custom preparer for TechDocs, the `preparedDir` might + end up taking disk space. This requires all custom preparers to + implement a new method `shouldCleanPreparedDirectory` which indicates + whether the prepared directory should be cleaned after generation. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-techdocs-node@1.9.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/plugin-search-backend-module-techdocs@0.1.10 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.17 + - @backstage/plugin-permission-common@0.7.9 + - @backstage/plugin-search-common@1.2.7 + ## 1.8.0-next.2 ### Minor Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 3c247508ef..c3e2ee0708 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.8.0-next.2", + "version": "1.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts index 52a3b82651..ff714eee63 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts @@ -258,7 +258,7 @@ describe('DocsSynchronizer', () => { expect(mockResponseHandler.log).toHaveBeenCalledTimes(1); expect(mockResponseHandler.log).toHaveBeenCalledWith( expect.stringMatching( - /error.*: Failed to build the docs page: Some random error/, + /error.*: Failed to build the docs page for entity component:default\/test: Some random error/, ), ); expect(mockResponseHandler.finish).toHaveBeenCalledTimes(0); diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts index 8456f64a6a..fad915b068 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts @@ -15,7 +15,11 @@ */ import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { + DEFAULT_NAMESPACE, + Entity, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { assertError, NotFoundError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -142,7 +146,9 @@ export class DocsSynchronizer { } } catch (e) { assertError(e); - const msg = `Failed to build the docs page: ${e.message}`; + const msg = `Failed to build the docs page for entity ${stringifyEntityRef( + entity, + )}: ${e.message}`; taskLogger.error(msg); this.logger.error(msg, e); error(e); diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index fe8fd1834c..37b6a46b20 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.1 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + ## 1.1.1-next.2 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index c4ff929540..cf92b0c969 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.1.1-next.2", + "version": "1.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,8 +49,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -61,7 +61,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/react": "^16.13.1 || ^17.0.0", "msw": "^1.0.0" diff --git a/plugins/techdocs-module-addons-contrib/src/setupTests.ts b/plugins/techdocs-module-addons-contrib/src/setupTests.ts index 326d2ed212..56b9b18321 100644 --- a/plugins/techdocs-module-addons-contrib/src/setupTests.ts +++ b/plugins/techdocs-module-addons-contrib/src/setupTests.ts @@ -14,3 +14,5 @@ * limitations under the License. */ import '@testing-library/jest-dom'; + +Element.prototype.scrollIntoView = jest.fn(); diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 91290cc550..2576313037 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-techdocs-node +## 1.9.0 + +### Minor Changes + +- 344cfbcfbc: Allow prepared directory clean up for custom preparers + + When using custom preparer for TechDocs, the `preparedDir` might + end up taking disk space. This requires all custom preparers to + implement a new method `shouldCleanPreparedDirectory` which indicates + whether the prepared directory should be cleaned after generation. + +- d06b30b050: Add possibility to use a mkdocs config file with a different name than `mkdocs. with the serve command using the `--mkdocs-config-file-name` argument + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.7 + - @backstage/plugin-search-common@1.2.7 + ## 1.9.0-next.2 ### Minor Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 4ec11fde71..712693f6af 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.9.0-next.2", + "version": "1.9.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 0d5aafecbc..42edbad969 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-react +## 1.1.12 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/version-bridge@1.0.6 + - @backstage/config@1.1.1 + ## 1.1.12-next.2 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index f324f3be76..79d2b3cc17 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.1.12-next.2", + "version": "1.1.12", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -49,8 +49,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,8 +58,7 @@ "@backstage/test-utils": "workspace:^", "@backstage/theme": "workspace:^", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0" + "@testing-library/react": "^14.0.0" }, "files": [ "alpha", diff --git a/plugins/techdocs-react/src/context.test.tsx b/plugins/techdocs-react/src/context.test.tsx index 4800204f36..bcab445729 100644 --- a/plugins/techdocs-react/src/context.test.tsx +++ b/plugins/techdocs-react/src/context.test.tsx @@ -14,12 +14,16 @@ * limitations under the License. */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act, waitFor } from '@testing-library/react'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; -import { MockAnalyticsApi, TestApiProvider } from '@backstage/test-utils'; +import { + MockAnalyticsApi, + MockConfigApi, + TestApiProvider, +} from '@backstage/test-utils'; import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; import { analyticsApiRef, @@ -30,6 +34,7 @@ import { import { techdocsApiRef } from './api'; import { useTechDocsReaderPage, TechDocsReaderPageProvider } from './context'; import { TechDocsMetadata } from './types'; +import { JsonObject } from '@backstage/config'; const mockShadowRoot = () => { const div = document.createElement('div'); @@ -60,10 +65,6 @@ const techdocsApiMock = { getTechDocsMetadata: jest.fn().mockResolvedValue(mockTechDocsMetadata), }; -const configApiMock = { - getOptionalBoolean: jest.fn().mockReturnValue(undefined), -}; - const analyticsApiMock = new MockAnalyticsApi(); const wrapper = ({ @@ -72,16 +73,18 @@ const wrapper = ({ name: mockEntityMetadata.metadata.name, namespace: mockEntityMetadata.metadata.namespace!!, }, + config, children, }: { entityRef?: CompoundEntityRef; + config?: JsonObject; children: React.ReactNode; }) => ( @@ -98,47 +101,32 @@ describe('useTechDocsReaderPage', () => { }); it('should set title', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, - ); + const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); expect(result.current.title).toBe(''); - act(() => result.current.setTitle('test site title')); - - await waitForNextUpdate(); + await act(async () => result.current.setTitle('test site title')); expect(result.current.title).toBe('test site title'); }); it('should set subtitle', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, - ); + const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); expect(result.current.subtitle).toBe(''); - act(() => result.current.setSubtitle('test site subtitle')); - - await waitForNextUpdate(); + await act(async () => result.current.setSubtitle('test site subtitle')); expect(result.current.subtitle).toBe('test site subtitle'); }); it('should set shadow root', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsReaderPage(), - { wrapper }, - ); + const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); // mock shadowroot const shadowRoot = mockShadowRoot(); - act(() => result.current.setShadowRoot(shadowRoot)); - - await waitForNextUpdate(); + await act(async () => result.current.setShadowRoot(shadowRoot)); expect(result.current.shadowRoot?.innerHTML).toBe( '

Shadow DOM Mock

', @@ -152,37 +140,42 @@ describe('useTechDocsReaderPage', () => { namespace: mockEntityMetadata.metadata.namespace?.toLocaleLowerCase(), }; const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - - expect(result.current.entityRef).toStrictEqual(lowercaseEntityRef); + await waitFor(() => { + expect(result.current.entityRef).toStrictEqual(lowercaseEntityRef); + }); }); it('entityRef is not modified when legacyUseCaseSensitiveTripletPaths is true', async () => { - configApiMock.getOptionalBoolean.mockReturnValueOnce(true); const caseSensitiveEntityRef = { kind: mockEntityMetadata.kind, name: mockEntityMetadata.metadata.name, namespace: mockEntityMetadata.metadata.namespace!!, }; - const { result } = renderHook(() => useTechDocsReaderPage(), { wrapper }); - - expect(result.current.entityRef).toStrictEqual(caseSensitiveEntityRef); + const { result } = renderHook(() => useTechDocsReaderPage(), { + wrapper: ({ children }) => + wrapper({ + children, + config: { techdocs: { legacyUseCaseSensitiveTripletPaths: true } }, + }), + }); + await waitFor(() => { + 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', - }, + renderHook(() => useAnalytics().captureEvent('action', 'subject'), { + wrapper, + }); + await waitFor(() => { + expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + action: 'action', + subject: 'subject', + context: { + entityRef: 'component:default/test', + }, + }); }); }); }); diff --git a/plugins/techdocs-react/src/hooks.test.ts b/plugins/techdocs-react/src/hooks.test.ts index 2aa53b32d5..0cd55fa10f 100644 --- a/plugins/techdocs-react/src/hooks.test.ts +++ b/plugins/techdocs-react/src/hooks.test.ts @@ -19,7 +19,7 @@ import { useShadowRootElements, useShadowRootSelection, } from './hooks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { fireEvent, waitFor } from '@testing-library/react'; const fireSelectionChangeEvent = (window: Window) => { diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 8797b30bd2..4db98ea055 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-techdocs +## 1.8.0 + +### Minor Changes + +- 27740caa2d: Added experimental support for declarative integration via the `/alpha` subpath. + +### Patch Changes + +- 4918f65ab2: Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- 3605370af6: Improved `DocsTable` to display pagination controls dynamically, appearing only when needed. +- 0296f272b4: The `spec.lifecycle' field in entities will now always be rendered as a string. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- 9468a67b92: Added support for React 18. The new `createRoot` API from `react-dom/client` will now be used if present. +- df449a7a31: Add kind column by default to TechDocsTable +- Updated dependencies + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/integration-react@1.1.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-react@1.7.1 + - @backstage/plugin-techdocs-react@1.1.12 + - @backstage/theme@0.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.7 + ## 1.7.1-next.2 ### Patch Changes diff --git a/plugins/techdocs/alpha-api-report.md b/plugins/techdocs/alpha-api-report.md index 0bf8c25b33..2b63d6e691 100644 --- a/plugins/techdocs/alpha-api-report.md +++ b/plugins/techdocs/alpha-api-report.md @@ -3,13 +3,23 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + root: RouteRef; + docRoot: RouteRef<{ + name: string; + kind: string; + namespace: string; + }>; + entityContent: RouteRef; + }, + {} +>; export default _default; // @alpha (undocumented) diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 578535c351..3df7399521 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.7.1-next.2", + "version": "1.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -86,8 +86,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", - "@testing-library/react-hooks": "^8.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/dompurify": "^2.2.2", "@types/event-source-polyfill": "^1.0.0", diff --git a/plugins/techdocs/src/alpha.tsx b/plugins/techdocs/src/alpha.tsx index 2f991f2fcc..ceb5f47364 100644 --- a/plugins/techdocs/src/alpha.tsx +++ b/plugins/techdocs/src/alpha.tsx @@ -15,88 +15,34 @@ */ import React from 'react'; +import LibraryBooks from '@material-ui/icons/LibraryBooks'; import { createPlugin, createSchemaFromZod, createApiExtension, createPageExtension, + createNavItemExtension, } from '@backstage/frontend-plugin-api'; import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; import { configApiRef, createApiFactory, - createRouteRef, discoveryApiRef, fetchApiRef, identityApiRef, } from '@backstage/core-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; import { techdocsApiRef, techdocsStorageApiRef, } from '@backstage/plugin-techdocs-react'; import { TechDocsClient, TechDocsStorageClient } from './client'; - -const rootRouteRef = createRouteRef({ - id: 'plugin.techdocs.indexPage', -}); - -const rootDocsRouteRef = createRouteRef({ - id: 'plugin.techdocs.readerPage', - params: ['namespace', 'kind', 'name'], -}); - -/** @alpha */ -export const TechDocsSearchResultListItemExtension = - createSearchResultListItemExtension({ - id: 'techdocs', - configSchema: createSchemaFromZod(z => - z.object({ - // TODO: Define how the icon can be configurable - title: z.string().optional(), - lineClamp: z.number().default(5), - asLink: z.boolean().default(true), - asListItem: z.boolean().default(true), - noTrack: z.boolean().default(false), - }), - ), - predicate: result => result.type === 'techdocs', - component: async ({ config }) => { - const { TechDocsSearchResultListItem } = await import( - './search/components/TechDocsSearchResultListItem' - ); - return props => ; - }, - }); - -/** - * Responsible for rendering the provided router element - * - * @alpha - */ -const TechDocsIndexPage = createPageExtension({ - id: 'plugin.techdocs.indexPage', - defaultPath: '/docs', - routeRef: rootRouteRef, - loader: () => - import('./home/components/TechDocsIndexPage').then(m => ( - - )), -}); - -/** - * Component responsible for composing a TechDocs reader page experience - * - * @alpha - */ -const TechDocsReaderPage = createPageExtension({ - id: 'plugin.techdocs.readerPage', - loader: () => - import('./reader/components/TechDocsReaderPage').then(m => ( - - )), - routeRef: rootDocsRouteRef, - defaultPath: '/docs/:namespace/:kind/:name/*', -}); +import { + rootCatalogDocsRouteRef, + rootDocsRouteRef, + rootRouteRef, +} from './routes'; +import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha'; /** @alpha */ const techDocsStorage = createApiExtension({ @@ -143,14 +89,94 @@ const techDocsClient = createApiExtension({ }, }); +/** @alpha */ +export const TechDocsSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'techdocs', + configSchema: createSchemaFromZod(z => + z.object({ + // TODO: Define how the icon can be configurable + title: z.string().optional(), + lineClamp: z.number().default(5), + asLink: z.boolean().default(true), + asListItem: z.boolean().default(true), + noTrack: z.boolean().default(false), + }), + ), + predicate: result => result.type === 'techdocs', + component: async ({ config }) => { + const { TechDocsSearchResultListItem } = await import( + './search/components/TechDocsSearchResultListItem' + ); + return props => ; + }, + }); + +/** + * Responsible for rendering the provided router element + * + * @alpha + */ +const TechDocsIndexPage = createPageExtension({ + id: 'plugin.techdocs.indexPage', + defaultPath: '/docs', + routeRef: convertLegacyRouteRef(rootRouteRef), + loader: () => + import('./home/components/TechDocsIndexPage').then(m => ( + + )), +}); + +/** + * Component responsible for composing a TechDocs reader page experience + * + * @alpha + */ +const TechDocsReaderPage = createPageExtension({ + id: 'plugin.techdocs.readerPage', + defaultPath: '/docs/:namespace/:kind/:name', + routeRef: convertLegacyRouteRef(rootDocsRouteRef), + loader: () => + import('./reader/components/TechDocsReaderPage').then(m => ( + + )), +}); + +/** + * Component responsible for rendering techdocs on entity pages + * + * @alpha + */ +const TechDocsEntityContent = createEntityContentExtension({ + id: 'techdocs', + defaultPath: 'docs', + defaultTitle: 'TechDocs', + loader: () => import('./Router').then(m => ), +}); + +/** @alpha */ +const TechDocsNavItem = createNavItemExtension({ + id: 'plugin.techdocs.nav.index', + icon: LibraryBooks, + title: 'Docs', + routeRef: convertLegacyRouteRef(rootRouteRef), +}); + /** @alpha */ export default createPlugin({ id: 'techdocs', extensions: [ - TechDocsIndexPage, - TechDocsReaderPage, techDocsClient, techDocsStorage, + TechDocsNavItem, + TechDocsIndexPage, + TechDocsReaderPage, + TechDocsEntityContent, TechDocsSearchResultListItemExtension, ], + routes: { + root: convertLegacyRouteRef(rootRouteRef), + docRoot: convertLegacyRouteRef(rootDocsRouteRef), + entityContent: convertLegacyRouteRef(rootCatalogDocsRouteRef), + }, }); diff --git a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx index afdac63a99..34aaf76394 100644 --- a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx @@ -20,6 +20,7 @@ import { TechDocsBuildLogs, TechDocsBuildLogsDrawerContent, } from './TechDocsBuildLogs'; +import { userEvent } from '@testing-library/user-event'; // The inside needs mocking to render in jsdom jest.mock('react-virtualized-auto-sizer', () => ({ @@ -38,7 +39,7 @@ describe('', () => { it('should open drawer', async () => { const rendered = await renderInTestApp(); - rendered.getByText(/Show Build Logs/i).click(); + await userEvent.click(rendered.getByText(/Show Build Logs/i)); expect(rendered.getByText(/Build Details/i)).toBeInTheDocument(); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index e11b7b6e81..f732afd31d 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ import React from 'react'; -import { act } from '@testing-library/react'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; @@ -150,31 +149,25 @@ describe('', () => { }); it('should render a techdocs reader page with children', async () => { - await act(async () => { - const rendered = await renderInTestApp( - - - techdocs reader page - - , - { - mountedRoutes, - }, - ); - expect( - rendered.container.querySelector('header'), - ).not.toBeInTheDocument(); - expect( - rendered.container.querySelector('article'), - ).not.toBeInTheDocument(); - expect(rendered.getByText('techdocs reader page')).toBeInTheDocument(); - }); + const rendered = await renderInTestApp( + + + techdocs reader page + + , + { + mountedRoutes, + }, + ); + expect(rendered.container.querySelector('header')).not.toBeInTheDocument(); + expect(rendered.container.querySelector('article')).not.toBeInTheDocument(); + expect(rendered.getByText('techdocs reader page')).toBeInTheDocument(); }); it('should render techdocs reader page with addons', async () => { @@ -183,56 +176,52 @@ describe('', () => { const namespace = 'test-namespace'; const kind = 'test'; - await act(async () => { - const rendered = await renderInTestApp( - - - } - > - - - - - - , - { - mountedRoutes, - routeEntries: ['/docs/test-namespace/test/test-name'], - }, - ); + const rendered = await renderInTestApp( + + + } + > + + + + + + , + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); - expect( - rendered.getByText(`PageMock: ${namespace}#${kind}#${name}`), - ).toBeInTheDocument(); - }); + expect( + rendered.getByText(`PageMock: ${namespace}#${kind}#${name}`), + ).toBeInTheDocument(); }); it('should render techdocs reader page with addons and page', async () => { (Page as jest.Mock).mockImplementation(PageMock); - await act(async () => { - const rendered = await renderInTestApp( - - - } - > -

the page

- - - -
-
-
, - { - mountedRoutes, - routeEntries: ['/docs/test-namespace/test/test-name'], - }, - ); + const rendered = await renderInTestApp( + + + } + > +

the page

+ + + +
+
+
, + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); - expect(rendered.getByText('the page')).toBeInTheDocument(); - }); + expect(rendered.getByText('the page')).toBeInTheDocument(); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.test.tsx index 2380724960..670653ce6b 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/context.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { ThemeProvider } from '@material-ui/core'; @@ -95,16 +95,13 @@ describe('context', () => { }); it('should return expected entity values', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useEntityMetadata(), - { wrapper }, - ); + const { result } = renderHook(() => useEntityMetadata(), { wrapper }); - await waitForNextUpdate(); - - expect(result.current.value).toBeDefined(); - expect(result.current.error).toBeUndefined(); - expect(result.current.value).toMatchObject(mockEntityMetadata); + await waitFor(() => { + expect(result.current.value).toBeDefined(); + expect(result.current.error).toBeUndefined(); + expect(result.current.value).toMatchObject(mockEntityMetadata); + }); }); }); @@ -116,16 +113,13 @@ describe('context', () => { }); it('should return expected techdocs metadata values', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useTechDocsMetadata(), - { wrapper }, - ); + const { result } = renderHook(() => useTechDocsMetadata(), { wrapper }); - await waitForNextUpdate(); - - expect(result.current.value).toBeDefined(); - expect(result.current.error).toBeUndefined(); - expect(result.current.value).toMatchObject(mockTechDocsMetadata); + await waitFor(() => { + expect(result.current.value).toBeDefined(); + expect(result.current.error).toBeUndefined(); + expect(result.current.value).toMatchObject(mockTechDocsMetadata); + }); }); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.test.tsx index 3e5a4c73c3..adef2f64d0 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { act, waitFor } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { @@ -33,6 +33,10 @@ jest.mock('../useReaderState', () => ({ ...jest.requireActual('../useReaderState'), useReaderState: (...args: any[]) => useReaderState(...args), })); +jest.mock('@backstage/plugin-techdocs-react', () => ({ + ...jest.requireActual('@backstage/plugin-techdocs-react'), + useShadowDomStylesLoading: jest.fn().mockReturnValue(false), +})); import { TechDocsReaderPageContent } from './TechDocsReaderPageContent'; @@ -84,24 +88,26 @@ const Wrapper = ({ ); describe('', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should render techdocs page content', async () => { getEntityMetadata.mockResolvedValue(mockEntityMetadata); getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); useTechDocsReaderDom.mockReturnValue(document.createElement('html')); useReaderState.mockReturnValue({ state: 'cached' }); - await act(async () => { - const rendered = await renderInTestApp( - - - , - ); + const rendered = await renderInTestApp( + + + , + ); - await waitFor(() => { - expect( - rendered.getByTestId('techdocs-native-shadowroot'), - ).toBeInTheDocument(); - }); + await waitFor(() => { + expect( + rendered.getByTestId('techdocs-native-shadowroot'), + ).toBeInTheDocument(); }); }); @@ -110,21 +116,19 @@ describe('', () => { useTechDocsReaderDom.mockReturnValue(document.createElement('html')); useReaderState.mockReturnValue({ state: 'cached' }); - await act(async () => { - const rendered = await renderInTestApp( - - - , - ); + const rendered = await renderInTestApp( + + + , + ); - await waitFor(() => { - expect( - rendered.queryByTestId('techdocs-native-shadowroot'), - ).not.toBeInTheDocument(); - expect( - rendered.getByText('ERROR 404: PAGE NOT FOUND'), - ).toBeInTheDocument(); - }); + await waitFor(() => { + expect( + rendered.queryByTestId('techdocs-native-shadowroot'), + ).not.toBeInTheDocument(); + expect( + rendered.getByText('ERROR 404: PAGE NOT FOUND'), + ).toBeInTheDocument(); }); }); @@ -134,21 +138,76 @@ describe('', () => { useTechDocsReaderDom.mockReturnValue(undefined); useReaderState.mockReturnValue({ state: 'CONTENT_NOT_FOUND' }); - await act(async () => { - const rendered = await renderInTestApp( - - - , - ); + const rendered = await renderInTestApp( + + + , + ); - await waitFor(() => { - expect( - rendered.queryByTestId('techdocs-native-shadowroot'), - ).not.toBeInTheDocument(); - expect( - rendered.getByText('ERROR 404: Documentation not found'), - ).toBeInTheDocument(); - }); + await waitFor(() => { + expect( + rendered.queryByTestId('techdocs-native-shadowroot'), + ).not.toBeInTheDocument(); + expect( + rendered.getByText('ERROR 404: Documentation not found'), + ).toBeInTheDocument(); + }); + }); + + it('should scroll to hash if hash is present in url', async () => { + jest.spyOn(document, 'querySelector'); + + const mockScrollIntoView = jest.fn(); + const h2 = document.createElement('h2'); + h2.innerText = 'emojis'; + h2.id = 'emojis'; + h2.scrollIntoView = mockScrollIntoView; + const mockTechDocsPage = document.createElement('html'); + mockTechDocsPage.appendChild(h2); + + getEntityMetadata.mockResolvedValue(mockEntityMetadata); + getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); + useTechDocsReaderDom.mockReturnValue(mockTechDocsPage); + useReaderState.mockReturnValue({ state: 'cached' }); + + window.location.hash = '#emojis'; + + const rendered = await renderInTestApp( + + + , + ); + + await waitFor(() => { + expect( + rendered.getByTestId('techdocs-native-shadowroot'), + ).toBeInTheDocument(); + expect(mockScrollIntoView).toHaveBeenCalled(); + expect(document.querySelector).not.toHaveBeenCalledWith('header'); + }); + + window.location.hash = ''; + }); + + it('should scroll to header if hash is not present in url', async () => { + jest.spyOn(document, 'querySelector'); + + getEntityMetadata.mockResolvedValue(mockEntityMetadata); + getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); + useTechDocsReaderDom.mockReturnValue(document.createElement('html')); + useReaderState.mockReturnValue({ state: 'cached' }); + + const rendered = await renderInTestApp( + + + , + ); + + await waitFor(() => { + expect( + rendered.getByTestId('techdocs-native-shadowroot'), + ).toBeInTheDocument(); + expect(document.querySelector).toHaveBeenCalledWith('header'); }); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx index 1e5459fc9d..f4c5ad8745 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx @@ -14,12 +14,14 @@ * limitations under the License. */ -import React, { useCallback } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { makeStyles, Grid } from '@material-ui/core'; import { TechDocsShadowDom, + useShadowDomStylesLoading, + useShadowRootElements, useTechDocsReaderPage, } from '@backstage/plugin-techdocs-react'; import { CompoundEntityRef } from '@backstage/catalog-model'; @@ -78,8 +80,23 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider( entityRef, setShadowRoot, } = useTechDocsReaderPage(); - const dom = useTechDocsReaderDom(entityRef); + const path = window.location.pathname; + const hash = window.location.hash; + const isStyleLoading = useShadowDomStylesLoading(dom); + const [hashElement] = useShadowRootElements([`[id="${hash.slice(1)}"]`]); + + useEffect(() => { + if (isStyleLoading) return; + + if (hash) { + if (hashElement) { + hashElement.scrollIntoView(); + } + } else { + document?.querySelector('header')?.scrollIntoView(); + } + }, [path, hash, hashElement, isStyleLoading]); const handleAppend = useCallback( (newShadowRoot: ShadowRoot) => { diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index cc42c46b4e..29e6945fa7 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -39,7 +39,6 @@ import { removeMkdocsHeader, rewriteDocLinks, simplifyMkdocsFooter, - scrollIntoAnchor, scrollIntoNavigation, transform as transformer, copyToClipboard, @@ -167,7 +166,6 @@ export const useTechDocsReaderDom = ( const postRender = useCallback( async (transformedElement: Element) => transformer(transformedElement, [ - scrollIntoAnchor(), scrollIntoNavigation(), copyToClipboard(theme), addLinkClickListener({ diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.test.tsx index a3e03b7cf0..d2956ce919 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.test.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ import React from 'react'; -import { act, waitFor } from '@testing-library/react'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; @@ -80,112 +79,77 @@ describe('', () => { getEntityMetadata.mockResolvedValue(mockEntityMetadata); getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); - await act(async () => { - const rendered = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - '/docs': rootRouteRef, - }, + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, + '/docs': rootRouteRef, }, - ); + }, + ); - expect(rendered.container.innerHTML).toContain('header'); + expect(rendered.container.innerHTML).toContain('header'); - await waitFor(() => { - expect(rendered.getAllByText('test-site-name')).toHaveLength(2); - }); + expect(rendered.getAllByText('test-site-name')).toHaveLength(2); + expect(rendered.getByText('test-site-desc')).toBeDefined(); - expect(rendered.getByText('test-site-desc')).toBeDefined(); - }); + expect( + rendered.getByRole('link', { name: 'test:test-namespace/test-name' }), + ).toHaveAttribute('href', '/catalog/test-namespace/test/test-name'); }); it('should render a techdocs page header even if metadata is not loaded', async () => { - await act(async () => { - const rendered = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - '/docs': rootRouteRef, - }, + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, + '/docs': rootRouteRef, }, - ); + }, + ); - expect(rendered.container.innerHTML).toContain('header'); - }); + expect(rendered.container.innerHTML).toContain('header'); }); it('should not render a techdocs page header if entity metadata is missing', async () => { getEntityMetadata.mockResolvedValue(undefined); - await act(async () => { - const rendered = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - '/docs': rootRouteRef, - }, + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, + '/docs': rootRouteRef, }, - ); + }, + ); - await waitFor(() => { - expect(rendered.container.innerHTML).not.toContain('header'); - }); - }); + expect(rendered.container.innerHTML).not.toContain('header'); }); it('should not render a techdocs page header if techdocs metadata is missing', async () => { getTechDocsMetadata.mockResolvedValue(undefined); - await act(async () => { - const rendered = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - '/docs': rootRouteRef, - }, + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name/*': entityRouteRef, + '/docs': rootRouteRef, }, - ); + }, + ); - await waitFor(() => { - expect(rendered.container.innerHTML).not.toContain('header'); - }); - }); - }); - - it('should render a link back to the component page', async () => { - getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); - - await act(async () => { - const rendered = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name/*': entityRouteRef, - '/docs': rootRouteRef, - }, - }, - ); - - await waitFor(() => { - expect( - rendered.getByRole('link', { name: 'test:test-namespace/test-name' }), - ).toHaveAttribute('href', '/catalog/test-namespace/test/test-name'); - }); - }); + expect(rendered.container.innerHTML).not.toContain('header'); }); }); diff --git a/plugins/techdocs/src/reader/components/useReaderState.test.tsx b/plugins/techdocs/src/reader/components/useReaderState.test.tsx index 5f3e2d9662..60898ab288 100644 --- a/plugins/techdocs/src/reader/components/useReaderState.test.tsx +++ b/plugins/techdocs/src/reader/components/useReaderState.test.tsx @@ -16,7 +16,7 @@ import { NotFoundError } from '@backstage/errors'; import { TestApiProvider } from '@backstage/test-utils'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook, waitFor } from '@testing-library/react'; import React from 'react'; import { techdocsStorageApiRef } from '../../api'; import { @@ -284,24 +284,22 @@ describe('useReaderState', () => { return 'cached'; }); - await act(async () => { - const { result, waitForValueToChange } = await renderHook( - () => useReaderState('Component', 'default', 'backstage', '/example'), - { wrapper: Wrapper }, - ); + const { result } = renderHook( + () => useReaderState('Component', 'default', 'backstage', '/example'), + { wrapper: Wrapper }, + ); - expect(result.current).toEqual({ - state: 'CHECKING', - path: '/example', - content: undefined, - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); - - await waitForValueToChange(() => result.current.state); + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_FRESH', path: '/example', @@ -311,20 +309,20 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); - - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/example', - ); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( - { - kind: 'Component', - namespace: 'default', - name: 'backstage', - }, - expect.any(Function), - ); }); + + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/example', + ); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( + { + kind: 'Component', + namespace: 'default', + name: 'backstage', + }, + expect.any(Function), + ); }); it('should reload initially missing content', async () => { @@ -336,6 +334,7 @@ describe('useReaderState', () => { }); techdocsStorageApi.syncEntityDocs.mockImplementation( async (_, logHandler) => { + await 'a tick'; logHandler?.call(this, 'Line 1'); logHandler?.call(this, 'Line 2'); await new Promise(resolve => setTimeout(resolve, 1100)); @@ -343,38 +342,39 @@ describe('useReaderState', () => { }, ); - await act(async () => { - const { result, waitForValueToChange } = await renderHook( - () => useReaderState('Component', 'default', 'backstage', '/example'), - { wrapper: Wrapper }, - ); + const { result } = renderHook( + () => useReaderState('Component', 'default', 'backstage', '/example'), + { wrapper: Wrapper }, + ); - expect(result.current).toEqual({ - state: 'CHECKING', - path: '/example', - content: undefined, - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); - await waitForValueToChange(() => result.current.state, { + await waitFor( + () => { + expect(result.current).toEqual({ + state: 'INITIAL_BUILD', + path: '/example', + content: undefined, + contentErrorMessage: 'NotFoundError: Page Not Found', + syncErrorMessage: undefined, + buildLog: ['Line 1', 'Line 2'], + contentReload: expect.any(Function), + }); + }, + { timeout: 2000, - }); - - expect(result.current).toEqual({ - state: 'INITIAL_BUILD', - path: '/example', - content: undefined, - contentErrorMessage: 'NotFoundError: Page Not Found', - syncErrorMessage: undefined, - buildLog: ['Line 1', 'Line 2'], - contentReload: expect.any(Function), - }); - - await waitForValueToChange(() => result.current.state); + }, + ); + await waitFor(() => { expect(result.current).toEqual({ state: 'CHECKING', path: '/example', @@ -384,9 +384,9 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); + }); - await waitForValueToChange(() => result.current.state); - + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_FRESH', path: '/example', @@ -396,22 +396,22 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); - - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledTimes(2); - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/example', - ); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledTimes(1); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( - { - kind: 'Component', - namespace: 'default', - name: 'backstage', - }, - expect.any(Function), - ); }); + + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledTimes(2); + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/example', + ); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledTimes(1); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( + { + kind: 'Component', + namespace: 'default', + name: 'backstage', + }, + expect.any(Function), + ); }); it('should handle stale content', async () => { @@ -423,6 +423,7 @@ describe('useReaderState', () => { }); techdocsStorageApi.syncEntityDocs.mockImplementation( async (_, logHandler) => { + await 'a tick'; logHandler?.call(this, 'Line 1'); logHandler?.call(this, 'Line 2'); await new Promise(resolve => setTimeout(resolve, 1100)); @@ -430,24 +431,23 @@ describe('useReaderState', () => { }, ); - await act(async () => { - const { result, waitForValueToChange } = await renderHook( - () => useReaderState('Component', 'default', 'backstage', '/example'), - { wrapper: Wrapper }, - ); + const { result } = renderHook( + () => useReaderState('Component', 'default', 'backstage', '/example'), + { wrapper: Wrapper }, + ); - expect(result.current).toEqual({ - state: 'CHECKING', - path: '/example', - content: undefined, - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); - // the content is returned but the sync is in progress - await waitForValueToChange(() => result.current.state); + // the content is returned but the sync is in progress + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_FRESH', path: '/example', @@ -457,9 +457,10 @@ describe('useReaderState', () => { buildLog: ['Line 1', 'Line 2'], contentReload: expect.any(Function), }); + }); - // the sync takes longer than 1 seconds so the refreshing state starts - await waitForValueToChange(() => result.current.state); + // the sync takes longer than 1 seconds so the refreshing state starts + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_STALE_REFRESHING', path: '/example', @@ -469,9 +470,10 @@ describe('useReaderState', () => { buildLog: ['Line 1', 'Line 2'], contentReload: expect.any(Function), }); + }); - // the content is updated but not yet displayed - await waitForValueToChange(() => result.current.state); + // the content is updated but not yet displayed + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_STALE_READY', path: '/example', @@ -481,12 +483,15 @@ describe('useReaderState', () => { buildLog: ['Line 1', 'Line 2'], contentReload: expect.any(Function), }); + }); - // reload the content + // reload the content + await act(async () => { result.current.contentReload(); + }); - // the new content refresh is triggered - await waitForValueToChange(() => result.current.state); + // the new content refresh is triggered + await waitFor(() => { expect(result.current).toEqual({ state: 'CHECKING', path: '/example', @@ -496,35 +501,39 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); - - // the new content is loaded - await waitForValueToChange(() => result.current.state, { - timeout: 2000, - }); - expect(result.current).toEqual({ - state: 'CONTENT_FRESH', - path: '/example', - content: 'my new content', - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); - - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledTimes(2); - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/example', - ); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( - { - kind: 'Component', - namespace: 'default', - name: 'backstage', - }, - expect.any(Function), - ); }); + + // the new content is loaded + await waitFor( + () => { + expect(result.current).toEqual({ + state: 'CONTENT_FRESH', + path: '/example', + content: 'my new content', + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); + }, + { + timeout: 2000, + }, + ); + + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledTimes(2); + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/example', + ); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( + { + kind: 'Component', + namespace: 'default', + name: 'backstage', + }, + expect.any(Function), + ); }); it('should handle navigation', async () => { @@ -537,25 +546,24 @@ describe('useReaderState', () => { .mockRejectedValueOnce(new NotFoundError('Some error description')); techdocsStorageApi.syncEntityDocs.mockResolvedValue('cached'); - await act(async () => { - const { result, waitForValueToChange, rerender } = await renderHook( - ({ path }: { path: string }) => - useReaderState('Component', 'default', 'backstage', path), - { initialProps: { path: '/example' }, wrapper: Wrapper as any }, - ); + const { result, rerender } = renderHook( + ({ path }: { path: string }) => + useReaderState('Component', 'default', 'backstage', path), + { initialProps: { path: '/example' }, wrapper: Wrapper as any }, + ); - expect(result.current).toEqual({ - state: 'CHECKING', - path: '/example', - content: undefined, - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); - // show the content - await waitForValueToChange(() => result.current.state); + // show the content + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_FRESH', path: '/example', @@ -565,11 +573,12 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); + }); - // navigate - rerender({ path: '/new' }); + // navigate + rerender({ path: '/new' }); - await waitForValueToChange(() => result.current.state); + await waitFor(() => { expect(result.current).toEqual({ state: 'CHECKING', path: '/example', @@ -579,24 +588,29 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); + }); - await waitForValueToChange(() => result.current.state, { + await waitFor( + () => { + expect(result.current).toEqual({ + state: 'CONTENT_FRESH', + path: '/new', + content: 'my new content', + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); + }, + { timeout: 2000, - }); - expect(result.current).toEqual({ - state: 'CONTENT_FRESH', - path: '/new', - content: 'my new content', - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); + }, + ); - // navigate - rerender({ path: '/missing' }); + // navigate + rerender({ path: '/missing' }); - await waitForValueToChange(() => result.current.state); + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_NOT_FOUND', path: '/missing', @@ -606,24 +620,24 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); - - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/example', - ); - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/new', - ); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( - { - kind: 'Component', - namespace: 'default', - name: 'backstage', - }, - expect.any(Function), - ); }); + + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/example', + ); + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/new', + ); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( + { + kind: 'Component', + namespace: 'default', + name: 'backstage', + }, + expect.any(Function), + ); }); it('should handle content error', async () => { @@ -632,24 +646,23 @@ describe('useReaderState', () => { ); techdocsStorageApi.syncEntityDocs.mockResolvedValue('cached'); - await act(async () => { - const { result, waitForValueToChange } = await renderHook( - () => useReaderState('Component', 'default', 'backstage', '/example'), - { wrapper: Wrapper }, - ); + const { result } = renderHook( + () => useReaderState('Component', 'default', 'backstage', '/example'), + { wrapper: Wrapper }, + ); - expect(result.current).toEqual({ - state: 'CHECKING', - path: '/example', - content: undefined, - contentErrorMessage: undefined, - syncErrorMessage: undefined, - buildLog: [], - contentReload: expect.any(Function), - }); + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); - // the content loading threw an error - await waitForValueToChange(() => result.current.state); + // the content loading threw an error + await waitFor(() => { expect(result.current).toEqual({ state: 'CONTENT_NOT_FOUND', path: '/example', @@ -659,20 +672,20 @@ describe('useReaderState', () => { buildLog: [], contentReload: expect.any(Function), }); - - expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( - { kind: 'Component', namespace: 'default', name: 'backstage' }, - '/example', - ); - expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( - { - kind: 'Component', - namespace: 'default', - name: 'backstage', - }, - expect.any(Function), - ); }); + + expect(techdocsStorageApi.getEntityDocs).toHaveBeenCalledWith( + { kind: 'Component', namespace: 'default', name: 'backstage' }, + '/example', + ); + expect(techdocsStorageApi.syncEntityDocs).toHaveBeenCalledWith( + { + kind: 'Component', + namespace: 'default', + name: 'backstage', + }, + expect.any(Function), + ); }); }); }); diff --git a/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx b/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx index 2b1f427be3..ed5fbba085 100644 --- a/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx +++ b/plugins/techdocs/src/reader/transformers/html/transformer.test.tsx @@ -15,7 +15,7 @@ */ import React, { FC, PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { ConfigReader } from '@backstage/core-app-api'; import { ConfigApi, configApiRef } from '@backstage/core-plugin-api'; diff --git a/plugins/techdocs/src/reader/transformers/index.ts b/plugins/techdocs/src/reader/transformers/index.ts index ca17261572..7df98f1f26 100644 --- a/plugins/techdocs/src/reader/transformers/index.ts +++ b/plugins/techdocs/src/reader/transformers/index.ts @@ -25,6 +25,5 @@ export * from './copyToClipboard'; export * from './removeMkdocsHeader'; export * from './simplifyMkdocsFooter'; export * from './onCssReady'; -export * from './scrollIntoAnchor'; export * from './scrollIntoNavigation'; export * from './transformer'; diff --git a/plugins/techdocs/src/reader/transformers/renderReactElement.ts b/plugins/techdocs/src/reader/transformers/renderReactElement.ts index 86d44532c5..ff7accf6ba 100644 --- a/plugins/techdocs/src/reader/transformers/renderReactElement.ts +++ b/plugins/techdocs/src/reader/transformers/renderReactElement.ts @@ -14,21 +14,22 @@ * limitations under the License. */ -let ReactDOM: - | typeof import('react-dom') - // TODO: replace with import('react-dom/client') when repo is migrated to 18 - | { createRoot(el: HTMLElement): { render(el: JSX.Element): void } }; +let ReactDOMPromise: Promise< + typeof import('react-dom') | typeof import('react-dom/client') +>; if (process.env.HAS_REACT_DOM_CLIENT) { - ReactDOM = require('react-dom/client'); + ReactDOMPromise = import('react-dom/client'); } else { - ReactDOM = require('react-dom'); + ReactDOMPromise = import('react-dom'); } /** @internal */ export function renderReactElement(element: JSX.Element, root: HTMLElement) { - if ('createRoot' in ReactDOM) { - ReactDOM.createRoot(root).render(element); - } else { - ReactDOM.render(element, root); - } + ReactDOMPromise.then(ReactDOM => { + if ('createRoot' in ReactDOM) { + ReactDOM.createRoot(root).render(element); + } else { + ReactDOM.render(element, root); + } + }); } diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.test.ts b/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.test.ts deleted file mode 100644 index e222c24a4c..0000000000 --- a/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 { scrollIntoAnchor } from '../transformers'; -import { createTestShadowDom } from '../../test-utils'; -import { Transformer } from './transformer'; -import mkdocsIndex from '../../test-utils/fixtures/mkdocs-index'; -import { SHADOW_DOM_STYLE_LOAD_EVENT } from '@backstage/plugin-techdocs-react'; - -describe('scrollIntoAnchor', () => { - const scrollIntoView = jest.fn(); - let querySelectorSpy: jest.SpyInstance; - let addEventListenerSpy: jest.SpyInstance; - let removeEventListenerSpy: jest.SpyInstance; - const applySpies: Transformer = dom => { - querySelectorSpy = jest.spyOn(dom, 'querySelector'); - querySelectorSpy.mockReturnValue({ scrollIntoView }); - addEventListenerSpy = jest.spyOn(dom, 'addEventListener'); - removeEventListenerSpy = jest.spyOn(dom, 'removeEventListener'); - return dom; - }; - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('does nothing if there is no anchor element', async () => { - await createTestShadowDom(mkdocsIndex, { - preTransformers: [], - postTransformers: [applySpies, scrollIntoAnchor()], - }); - expect(querySelectorSpy).not.toHaveBeenCalled(); - expect(addEventListenerSpy).toHaveBeenCalled(); - expect(removeEventListenerSpy).toHaveBeenCalled(); - expect(addEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - expect(removeEventListenerSpy).toHaveBeenCalledTimes(1); - expect(removeEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - // check that the same function is passed to both addEventListener and removeEventListener - expect(addEventListenerSpy.mock.calls[0][1]).toBe( - removeEventListenerSpy.mock.calls[0][1], - ); - }); - - it('scroll to the hash anchor element', async () => { - window.location.hash = '#hash'; - await createTestShadowDom(mkdocsIndex, { - preTransformers: [], - postTransformers: [applySpies, scrollIntoAnchor()], - }); - expect(querySelectorSpy).toHaveBeenCalledWith( - expect.stringMatching('[id="hash"]'), - ); - expect(scrollIntoView).toHaveBeenCalledWith(); - expect(addEventListenerSpy).toHaveBeenCalledTimes(1); - expect(removeEventListenerSpy).toHaveBeenCalledTimes(1); - expect(addEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - expect(removeEventListenerSpy).toHaveBeenCalledTimes(1); - expect(removeEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - // check that the same function is passed to both addEventListener and removeEventListener - expect(addEventListenerSpy.mock.calls[0][1]).toBe( - removeEventListenerSpy.mock.calls[0][1], - ); - window.location.hash = ''; - }); - - it('works for anchor starting with number', async () => { - querySelectorSpy.mockReturnValue({ scrollIntoView }); - window.location.hash = '#1-hash'; - await createTestShadowDom(mkdocsIndex, { - preTransformers: [], - postTransformers: [applySpies, scrollIntoAnchor()], - }); - expect(querySelectorSpy).toHaveBeenCalledWith( - expect.stringMatching('[id="1-hash"]'), - ); - expect(scrollIntoView).toHaveBeenCalledWith(); - expect(addEventListenerSpy).toHaveBeenCalledTimes(1); - expect(addEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - expect(removeEventListenerSpy).toHaveBeenCalledTimes(1); - expect(removeEventListenerSpy).toHaveBeenCalledWith( - SHADOW_DOM_STYLE_LOAD_EVENT, - expect.any(Function), - ); - // check that the same function is passed to both addEventListener and removeEventListener - expect(addEventListenerSpy.mock.calls[0][1]).toBe( - removeEventListenerSpy.mock.calls[0][1], - ); - window.location.hash = ''; - }); -}); diff --git a/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.ts b/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.ts deleted file mode 100644 index 97a18b7241..0000000000 --- a/plugins/techdocs/src/reader/transformers/scrollIntoAnchor.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 type { Transformer } from './transformer'; -import { SHADOW_DOM_STYLE_LOAD_EVENT } from '@backstage/plugin-techdocs-react'; - -export const scrollIntoAnchor = (): Transformer => { - return dom => { - dom.addEventListener( - SHADOW_DOM_STYLE_LOAD_EVENT, - function handleShadowDomStyleLoad() { - if (window.location.hash) { - const hash = window.location.hash.slice(1); - dom?.querySelector(`[id="${hash}"]`)?.scrollIntoView(); - } - dom.removeEventListener( - SHADOW_DOM_STYLE_LOAD_EVENT, - handleShadowDomStyleLoad, - ); - }, - ); - return dom; - }; -}; diff --git a/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts b/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts index 84ba16d6e6..90244e96ad 100644 --- a/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts +++ b/plugins/techdocs/src/reader/transformers/styles/transformer.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useStylesTransformer } from './transformer'; describe('Transformers > Styles', () => { diff --git a/plugins/techdocs/src/setupTests.ts b/plugins/techdocs/src/setupTests.ts index 963c0f188b..6c7fc2d3e3 100644 --- a/plugins/techdocs/src/setupTests.ts +++ b/plugins/techdocs/src/setupTests.ts @@ -15,3 +15,5 @@ */ import '@testing-library/jest-dom'; + +Element.prototype.scrollIntoView = jest.fn(); diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index cb782356f8..6edbe92aa7 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-todo-backend +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/integration@1.7.1 + - @backstage/plugin-catalog-node@1.4.7 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-openapi-utils@0.0.5 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/catalog-client@1.4.5 + - @backstage/config@1.1.1 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index 1df098c517..d3296b70f0 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.3.4-next.2", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index b091767889..b30c9d259e 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-todo +## 0.2.28 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.2.28-next.2 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 20fde05ff2..ec27528d72 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.28-next.2", + "version": "0.2.28", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -55,7 +55,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 9554c73992..53e8a6f30f 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-user-settings-backend +## 0.2.4 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.8 + - @backstage/plugin-auth-node@0.4.0 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/backend-plugin-api@0.6.6 + - @backstage/types@1.1.1 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index eb1d08bbe2..c72f349301 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.2.4-next.2", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,6 +33,7 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/types": "workspace:^", diff --git a/plugins/user-settings-backend/src/service/standaloneServer.ts b/plugins/user-settings-backend/src/service/standaloneServer.ts index 6dd8c7f72d..48a640636f 100644 --- a/plugins/user-settings-backend/src/service/standaloneServer.ts +++ b/plugins/user-settings-backend/src/service/standaloneServer.ts @@ -14,10 +14,13 @@ * limitations under the License. */ -import { createServiceBuilder, useHotMemoize } from '@backstage/backend-common'; +import { + createServiceBuilder, + DatabaseManager, +} from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { Server } from 'http'; -import Knex from 'knex'; import { Logger } from 'winston'; import { DatabaseUserSettingsStore } from '../database/DatabaseUserSettingsStore'; import { createRouterInternal } from './router'; @@ -33,13 +36,14 @@ export async function startStandaloneServer( ): Promise { const logger = options.logger.child({ service: 'storage-backend' }); - const database = useHotMemoize(module, () => { - return Knex({ - client: 'better-sqlite3', - connection: ':memory:', - useNullAsDefault: true, - }); - }); + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }), + ); + const database = manager.forPlugin('user-settings'); logger.debug('Starting application server...'); @@ -58,9 +62,7 @@ export async function startStandaloneServer( }; const router = await createRouterInternal({ - userSettingsStore: await DatabaseUserSettingsStore.create({ - database: { getClient: async () => database }, - }), + userSettingsStore: await DatabaseUserSettingsStore.create({ database }), identity: identityMock, }); diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 3ba16ac03d..3353f23a79 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-user-settings +## 0.7.11 + +### Patch Changes + +- 18c8dee6f5: Added experimental support for declarative integration via the `/alpha` subpath. +- d1b637d005: Fixed a bug where the theme icons would not be colored according to their active state. +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/frontend-plugin-api@0.2.0 + - @backstage/core-app-api@1.11.0 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + - @backstage/types@1.1.1 + ## 0.7.11-next.2 ### Patch Changes diff --git a/plugins/user-settings/alpha-api-report.md b/plugins/user-settings/alpha-api-report.md index 8a3e109e5b..f375eadbee 100644 --- a/plugins/user-settings/alpha-api-report.md +++ b/plugins/user-settings/alpha-api-report.md @@ -3,19 +3,19 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AnyExternalRoutes } from '@backstage/core-plugin-api'; -import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin< + { + root: RouteRef; + }, + {} +>; export default _default; -// @alpha (undocumented) -export const userSettingsRouteRef: RouteRef; - // @alpha (undocumented) export const userSettingsTranslationRef: TranslationRef< 'user-settings', diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 8937cb7dc1..264521ee45 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.7.11-next.2", + "version": "0.7.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,8 +62,8 @@ "zen-observable": "^0.10.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -73,7 +73,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", "msw": "^1.0.0" diff --git a/plugins/user-settings/src/alpha.tsx b/plugins/user-settings/src/alpha.tsx index 8d68ccf259..07cc8ce547 100644 --- a/plugins/user-settings/src/alpha.tsx +++ b/plugins/user-settings/src/alpha.tsx @@ -13,29 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createRouteRef } from '@backstage/core-plugin-api'; import { coreExtensionData, createExtensionInput, createPageExtension, createPlugin, } from '@backstage/frontend-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { settingsRouteRef } from './plugin'; import React from 'react'; export * from './translation'; -/** - * @alpha - */ -export const userSettingsRouteRef = createRouteRef({ - id: 'plugin.user-settings.page', -}); - const UserSettingsPage = createPageExtension({ id: 'plugin.user-settings.page', defaultPath: '/settings', - routeRef: userSettingsRouteRef, + routeRef: convertLegacyRouteRef(settingsRouteRef), inputs: { providerSettings: createExtensionInput( { @@ -56,4 +50,7 @@ const UserSettingsPage = createPageExtension({ export default createPlugin({ id: 'user-settings', extensions: [UserSettingsPage], + routes: { + root: convertLegacyRouteRef(settingsRouteRef), + }, }); diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 2664187ac0..d623adcf33 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-vault-backend +## 0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.11 + - @backstage/backend-common@0.19.8 + - @backstage/errors@1.2.3 + - @backstage/config@1.1.1 + ## 0.3.11-next.2 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index e27a8d0524..883bb5281b 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.3.11-next.2", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index c2037ad665..37ed1eb14e 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-vault +## 0.1.20 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5 + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.1.20-next.2 ### Patch Changes diff --git a/plugins/vault/package.json b/plugins/vault/package.json index 5eef7bca88..055d38073a 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.20-next.2", + "version": "0.1.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,8 +47,8 @@ "react-use": "^17.2.4" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -58,7 +58,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 19f23149bd..9682aa6411 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-xcmetrics +## 0.2.44 + +### Patch Changes + +- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`. +- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0 + - @backstage/core-components@0.13.6 + - @backstage/errors@1.2.3 + - @backstage/theme@0.4.3 + ## 0.2.44-next.2 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 7a67fd4d5e..97887eb2ea 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.44-next.2", + "version": "0.2.44", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,8 +44,8 @@ "recharts": "^2.5.0" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { @@ -55,7 +55,7 @@ "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.3", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "@types/luxon": "^3.0.0", "msw": "^1.0.0" diff --git a/storybook/package.json b/storybook/package.json index 6a86cd90bd..46cf09dc79 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "@swc/core": "^1.3.46", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", "react-hot-loader": "^4.13.0", "swc-loader": "^0.2.3" }, diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 9a533c46c0..00ec6908f0 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -9592,16 +9592,15 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^17.0.2": - version: 17.0.2 - resolution: "react-dom@npm:17.0.2" +"react-dom@npm:^18.0.2": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - scheduler: ^0.20.2 + scheduler: ^0.23.0 peerDependencies: - react: 17.0.2 - checksum: 1c1eaa3bca7c7228d24b70932e3d7c99e70d1d04e13bb0843bbf321582bc25d7961d6b8a6978a58a598af2af496d1cedcfb1bf65f6b0960a0a8161cb8dab743c + react: ^18.2.0 + checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc languageName: node linkType: hard @@ -9710,13 +9709,12 @@ __metadata: languageName: node linkType: hard -"react@npm:^17.0.2": - version: 17.0.2 - resolution: "react@npm:17.0.2" +"react@npm:^18.0.2": + version: 18.2.0 + resolution: "react@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: b254cc17ce3011788330f7bbf383ab653c6848902d7936a87b09d835d091e3f295f7e9dd1597c6daac5dc80f90e778c8230218ba8ad599f74adcc11e33b9d61b + checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b languageName: node linkType: hard @@ -10149,13 +10147,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.20.2": - version: 0.20.2 - resolution: "scheduler@npm:0.20.2" +"scheduler@npm:^0.23.0": + version: 0.23.0 + resolution: "scheduler@npm:0.23.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: c4b35cf967c8f0d3e65753252d0f260271f81a81e427241295c5a7b783abf4ea9e905f22f815ab66676f5313be0a25f47be582254db8f9241b259213e999b8fc + checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a languageName: node linkType: hard @@ -10682,8 +10679,8 @@ __metadata: "@storybook/react": ^6.5.9 "@storybook/testing-library": ^0.2.0 "@swc/core": ^1.3.46 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.2 + react-dom: ^18.0.2 react-hot-loader: ^4.13.0 storybook-dark-mode: ^1.1.0 swc-loader: ^0.2.3 diff --git a/yarn.lock b/yarn.lock index 2533a51f32..deb4f1a532 100644 --- a/yarn.lock +++ b/yarn.lock @@ -103,8 +103,8 @@ __metadata: linkType: hard "@apollo/client@npm:^3.0.0": - version: 3.8.5 - resolution: "@apollo/client@npm:3.8.5" + version: 3.8.6 + resolution: "@apollo/client@npm:3.8.6" dependencies: "@graphql-typed-document-node/core": ^3.1.1 "@wry/context": ^0.7.3 @@ -134,7 +134,7 @@ __metadata: optional: true subscriptions-transport-ws: optional: true - checksum: 242db8340d5f04ff8f2c9ad6a0dc6ab6d596fb5c763865b0d392f6e5771d55de28faa981dcadaea80ee8b21d4ff40bfa51152a10bcae4158ecf035e47b0d17c4 + checksum: 34a917d3456c1f728834eaaee00a98f82c7f60de8e0e0c62154667f7e95a635740a2d43fe43f51f85950eb2abe06a3d326f32393a48dd4afc6e4fb4357876dc1 languageName: node linkType: hard @@ -1800,13 +1800,13 @@ __metadata: languageName: node linkType: hard -"@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.22.10, @babel/code-frame@npm:^7.22.5, @babel/code-frame@npm:^7.8.3": - version: 7.22.10 - resolution: "@babel/code-frame@npm:7.22.10" +"@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.22.13, @babel/code-frame@npm:^7.8.3": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" dependencies: - "@babel/highlight": ^7.22.10 + "@babel/highlight": ^7.22.13 chalk: ^2.4.2 - checksum: 89a06534ad19759da6203a71bad120b1d7b2ddc016c8e07d4c56b35dea25e7396c6da60a754e8532a86733092b131ae7f661dbe6ba5d165ea777555daa2ed3c9 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 languageName: node linkType: hard @@ -1817,38 +1817,38 @@ __metadata: languageName: node linkType: hard -"@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.19.6": - version: 7.22.11 - resolution: "@babel/core@npm:7.22.11" +"@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.19.6, @babel/core@npm:^7.22.20": + version: 7.23.0 + resolution: "@babel/core@npm:7.23.0" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.10 - "@babel/generator": ^7.22.10 - "@babel/helper-compilation-targets": ^7.22.10 - "@babel/helper-module-transforms": ^7.22.9 - "@babel/helpers": ^7.22.11 - "@babel/parser": ^7.22.11 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.11 - "@babel/types": ^7.22.11 - convert-source-map: ^1.7.0 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helpers": ^7.23.0 + "@babel/parser": ^7.23.0 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.0 + "@babel/types": ^7.23.0 + convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.3 semver: ^6.3.1 - checksum: f258b2539ea2e5bfe55a708c2f3e1093a1b4744f12becc35abeb896037b66210de9a8ad6296a706046d5dc3a24e564362b73a9b814e5bfe500c8baab60c22d2e + checksum: cebd9b48dbc970a7548522f207f245c69567e5ea17ebb1a4e4de563823cf20a01177fe8d2fe19b6e1461361f92fa169fd0b29f8ee9d44eeec84842be1feee5f2 languageName: node linkType: hard -"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.22.10, @babel/generator@npm:^7.7.2": - version: 7.22.10 - resolution: "@babel/generator@npm:7.22.10" +"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.23.0, @babel/generator@npm:^7.7.2": + version: 7.23.0 + resolution: "@babel/generator@npm:7.23.0" dependencies: - "@babel/types": ^7.22.10 + "@babel/types": ^7.23.0 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 59a79730abdff9070692834bd3af179e7a9413fa2ff7f83dff3eb888765aeaeb2bfc7b0238a49613ed56e1af05956eff303cc139f2407eda8df974813e486074 + checksum: 8efe24adad34300f1f8ea2add420b28171a646edc70f2a1b3e1683842f23b8b7ffa7e35ef0119294e1901f45bfea5b3dc70abe1f10a1917ccdfb41bed69be5f1 languageName: node linkType: hard @@ -1870,16 +1870,16 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.22.10, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6": - version: 7.22.10 - resolution: "@babel/helper-compilation-targets@npm:7.22.10" +"@babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.22.10, @babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6": + version: 7.22.15 + resolution: "@babel/helper-compilation-targets@npm:7.22.15" dependencies: "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 browserslist: ^4.21.9 lru-cache: ^5.1.1 semver: ^6.3.1 - checksum: f6f1896816392bcff671bbe6e277307729aee53befb4a66ea126e2a91eda78d819a70d06fa384c74ef46c1595544b94dca50bef6c78438d9ffd31776dafbd435 + checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 languageName: node linkType: hard @@ -1930,20 +1930,20 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-environment-visitor@npm:7.22.5" - checksum: 248532077d732a34cd0844eb7b078ff917c3a8ec81a7f133593f71a860a582f05b60f818dc5049c2212e5baa12289c27889a4b81d56ef409b4863db49646c4b1 +"@babel/helper-environment-visitor@npm:^7.22.20, @babel/helper-environment-visitor@npm:^7.22.5": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-function-name@npm:7.22.5" +"@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" dependencies: - "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 languageName: node linkType: hard @@ -1965,27 +1965,27 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-imports@npm:7.22.5" +"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" dependencies: - "@babel/types": ^7.22.5 - checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-module-transforms@npm:7.22.9" +"@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9, @babel/helper-module-transforms@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-module-transforms@npm:7.23.0" dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 "@babel/helper-simple-access": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 peerDependencies: "@babel/core": ^7.0.0 - checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + checksum: 6e2afffb058cf3f8ce92f5116f710dda4341c81cfcd872f9a0197ea594f7ce0ab3cb940b0590af2fe99e60d2e5448bfba6bca8156ed70a2ed4be2adc8586c891 languageName: node linkType: hard @@ -2065,17 +2065,17 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea +"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.22.5": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.16.7, @babel/helper-validator-option@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-option@npm:7.22.5" - checksum: bbeca8a85ee86990215c0424997438b388b8d642d69b9f86c375a174d3cdeb270efafd1ff128bc7a1d370923d13b6e45829ba8581c027620e83e3a80c5c414b3 +"@babel/helper-validator-option@npm:^7.16.7, @babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-validator-option@npm:7.22.15" + checksum: 68da52b1e10002a543161494c4bc0f4d0398c8fdf361d5f7f4272e95c45d5b32d974896d44f6a0ea7378c9204988879d73613ca683e13bd1304e46d25ff67a8d languageName: node linkType: hard @@ -2090,34 +2090,34 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/helpers@npm:7.22.11" +"@babel/helpers@npm:^7.23.0": + version: 7.23.1 + resolution: "@babel/helpers@npm:7.23.1" dependencies: - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.11 - "@babel/types": ^7.22.11 - checksum: 93186544228b5e371486466ec3b86a77cce91beeff24a5670ca8ec46d50328f7700dab82d532351286e9d68624dc51d6d71589b051dd9535e44be077a43ec013 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.0 + "@babel/types": ^7.23.0 + checksum: acfc345102045c24ea2a4d60e00dcf8220e215af3add4520e2167700661338e6a80bd56baf44bb764af05ec6621101c9afc315dc107e18c61fa6da8acbdbb893 languageName: node linkType: hard -"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/highlight@npm:7.22.10" +"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.22.13": + version: 7.22.20 + resolution: "@babel/highlight@npm:7.22.20" dependencies: - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 chalk: ^2.4.2 js-tokens: ^4.0.0 - checksum: f714a1e1a72dd9d72f6383f4f30fd342e21a8df32d984a4ea8f5eab691bb6ba6db2f8823d4b4cf135d98869e7a98925b81306aa32ee3c429f8cfa52c75889e1b + checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 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.8, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.22.11, @babel/parser@npm:^7.22.5": - version: 7.22.11 - resolution: "@babel/parser@npm:7.22.11" +"@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.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/parser@npm:7.23.0" bin: parser: ./bin/babel-parser.js - checksum: 332079ed09794d3685343e9fc39c6a12dcb6ea589119f2135952cdef2424296786bb609a33f6dfa9be271797bbf8339f1865118418ea50b32a0c701734c96664 + checksum: 453fdf8b9e2c2b7d7b02139e0ce003d1af21947bbc03eb350fb248ee335c9b85e4ab41697ddbdd97079698de825a265e45a0846bb2ed47a2c7c1df833f42a354 languageName: node linkType: hard @@ -2959,6 +2959,28 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-self@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 671eebfabd14a0c7d6ae805fff7e289dfdb7ba984bb100ea2ef6dad1d6a665ebbb09199ab2e64fca7bc78bd0fdc80ca897b07996cf215fafc32c67bc564309af + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4ca2bd62ca14f8bbdcda9139f3f799e1c1c1bae504b67c1ca9bca142c53d81926d1a2b811f66a625f20999b2d352131053d886601f1ba3c1e9378c104d884277 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx@npm:^7.0.0, @babel/plugin-transform-react-jsx@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-react-jsx@npm:7.22.5" @@ -3314,43 +3336,43 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.18.10, @babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3": - version: 7.22.5 - resolution: "@babel/template@npm:7.22.5" +"@babel/template@npm:^7.18.10, @babel/template@npm:^7.22.15, @babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd languageName: node linkType: hard -"@babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.22.11, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": - version: 7.22.11 - resolution: "@babel/traverse@npm:7.22.11" +"@babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.23.0, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": + version: 7.23.0 + resolution: "@babel/traverse@npm:7.23.0" dependencies: - "@babel/code-frame": ^7.22.10 - "@babel/generator": ^7.22.10 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 "@babel/helper-hoist-variables": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.22.11 - "@babel/types": ^7.22.11 + "@babel/parser": ^7.23.0 + "@babel/types": ^7.23.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: 4ad62d548ca8b95dbf45bae16cc167428f174f3c837d55a5878b1f17bdbc8b384d6df741dc7c461b62c04d881cf25644d3ab885909ba46e3ac43224e2b15b504 + checksum: 0b17fae53269e1af2cd3edba00892bc2975ad5df9eea7b84815dab07dfec2928c451066d51bc65b4be61d8499e77db7e547ce69ef2a7b0eca3f96269cb43a0b0 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.0, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.11, @babel/types@npm:^7.22.5, @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.22.11 - resolution: "@babel/types@npm:7.22.11" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @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.23.0 + resolution: "@babel/types@npm:7.23.0" dependencies: "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 to-fast-properties: ^2.0.0 - checksum: 431a6446896adb62c876d0fe75263835735d3c974aae05356a87eb55f087c20a777028cf08eadcace7993e058bbafe3b21ce2119363222c6cef9eedd7a204810 + checksum: 215fe04bd7feef79eeb4d33374b39909ce9cad1611c4135a4f7fdf41fe3280594105af6d7094354751514625ea92d0875aba355f53e86a92600f290e77b0e604 languageName: node linkType: hard @@ -3368,11 +3390,11 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -3650,17 +3672,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@npm:^1.4.4": - version: 1.4.4 - resolution: "@backstage/catalog-client@npm:1.4.4" - dependencies: - "@backstage/catalog-model": ^1.4.2 - "@backstage/errors": ^1.2.2 - cross-fetch: ^3.1.5 - checksum: 3f821ee7450b192bf750a0275d095a96f7ce137283cecd0353cef817a43fd7f55141d828268cf839b3cfbfc41cea0d6519c4c4411b297b7423728dc7018f68ed - 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" @@ -3673,22 +3684,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@npm:^1.1.5, @backstage/catalog-model@npm:^1.4.2": - version: 1.4.2 - resolution: "@backstage/catalog-model@npm:1.4.2" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/errors": ^1.2.2 - "@backstage/types": ^1.1.1 - ajv: ^8.10.0 - json-schema: ^0.4.0 - lodash: ^4.17.21 - uuid: ^8.0.0 - checksum: 7e0d8cfb7fc6bab02803201552a24b73a3d7b502f7ba22e3408e86400e2a4f8937e0e91dea9a063d1f8bc128064400e93d05301611772502811feea10e8ad4e9 - languageName: node - linkType: hard - -"@backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.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: @@ -3752,8 +3748,6 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" - "@esbuild-kit/cjs-loader": ^2.4.1 - "@esbuild-kit/esm-loader": ^2.5.5 "@manypkg/get-packages": ^1.1.3 "@octokit/graphql": ^5.0.0 "@octokit/graphql-schema": ^13.7.0 @@ -3778,6 +3772,7 @@ __metadata: "@swc/jest": ^0.2.22 "@types/cross-spawn": ^6.0.2 "@types/diff": ^5.0.0 + "@types/ejs": ^3.1.3 "@types/express": ^4.17.6 "@types/fs-extra": ^9.0.1 "@types/http-proxy": ^1.17.4 @@ -3863,6 +3858,7 @@ __metadata: tar: ^6.1.12 terser-webpack-plugin: ^5.1.3 ts-node: ^10.0.0 + tsx: ^3.14.0 type-fest: ^2.19.0 util: ^0.12.3 webpack: ^5.70.0 @@ -3874,9 +3870,21 @@ __metadata: zod: ^3.21.4 peerDependencies: "@microsoft/api-extractor": ^7.21.2 + "@vitejs/plugin-react": ^4.0.4 + vite: ^4.4.9 + vite-plugin-html: ^3.2.0 + vite-plugin-node-polyfills: ^0.14.1 peerDependenciesMeta: "@microsoft/api-extractor": optional: true + "@vitejs/plugin-react": + optional: true + vite: + optional: true + vite-plugin-html: + optional: true + vite-plugin-node-polyfills: + optional: true bin: backstage-cli: bin/backstage-cli languageName: unknown @@ -3929,18 +3937,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@npm:^1.0.6, @backstage/config@npm:^1.0.7, @backstage/config@npm:^1.1.0": - version: 1.1.0 - resolution: "@backstage/config@npm:1.1.0" - dependencies: - "@backstage/errors": ^1.2.2 - "@backstage/types": ^1.1.1 - lodash: ^4.17.21 - checksum: 9c17ab41b3e4bd6a0ad75caaf46ed3fad198aa8d190cb9a85415140bc9d6506022a4d5450ea5810004fc2d7a3f7a0a00583b468af4a0fa1655ce444606283010 - languageName: node - linkType: hard - -"@backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -3964,7 +3961,7 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/react-hooks": ^8.0.0 "@testing-library/user-event": ^14.0.0 "@types/prop-types": ^15.7.3 @@ -3983,8 +3980,101 @@ __metadata: zen-observable: ^0.10.0 zod: ^3.21.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + +"@backstage/core-compat-api@workspace:^, @backstage/core-compat-api@workspace:packages/core-compat-api": + version: 0.0.0-use.local + resolution: "@backstage/core-compat-api@workspace:packages/core-compat-api" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" + "@backstage/plugin-puppetdb": "workspace:^" + "@backstage/plugin-stackstorm": "workspace:^" + "@oriflame/backstage-plugin-score-card": ^0.7.0 + "@testing-library/jest-dom": ^6.0.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + +"@backstage/core-components@^0.13.5, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": + version: 0.0.0-use.local + resolution: "@backstage/core-components@workspace:packages/core-components" + dependencies: + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@backstage/version-bridge": "workspace:^" + "@date-io/core": ^1.3.13 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@react-hookz/web": ^20.0.0 + "@testing-library/dom": ^9.0.0 + "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^14.0.0 + "@testing-library/user-event": ^14.0.0 + "@types/ansi-regex": ^5.0.0 + "@types/classnames": ^2.2.9 + "@types/d3-selection": ^3.0.1 + "@types/d3-shape": ^3.0.1 + "@types/d3-zoom": ^3.0.1 + "@types/dagre": ^0.7.44 + "@types/google-protobuf": ^3.7.2 + "@types/react": ^16.13.1 || ^17.0.0 + "@types/react-helmet": ^6.1.0 + "@types/react-sparklines": ^1.7.0 + "@types/react-syntax-highlighter": ^15.0.0 + "@types/react-text-truncate": ^0.14.0 + "@types/react-virtualized-auto-sizer": ^1.0.1 + "@types/react-window": ^1.8.5 + "@types/zen-observable": ^0.8.0 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + cross-fetch: ^3.1.5 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + history: ^5.0.0 + immer: ^9.0.1 + linkify-react: 4.1.1 + linkifyjs: 4.1.1 + lodash: ^4.17.21 + msw: ^1.0.0 + pluralize: ^8.0.0 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.6.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.21.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4039,157 +4129,7 @@ __metadata: languageName: node linkType: hard -"@backstage/core-components@npm:^0.13.5": - version: 0.13.5 - resolution: "@backstage/core-components@npm:0.13.5" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/core-plugin-api": ^1.6.0 - "@backstage/errors": ^1.2.2 - "@backstage/theme": ^0.4.2 - "@backstage/version-bridge": ^1.0.5 - "@date-io/core": ^1.3.13 - "@material-table/core": ^3.1.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 - "@types/react": ^16.13.1 || ^17.0.0 - "@types/react-sparklines": ^1.7.0 - "@types/react-text-truncate": ^0.14.0 - ansi-regex: ^6.0.1 - classnames: ^2.2.6 - d3-selection: ^3.0.0 - d3-shape: ^3.0.0 - d3-zoom: ^3.0.0 - dagre: ^0.8.5 - history: ^5.0.0 - immer: ^9.0.1 - linkify-react: 4.1.1 - linkifyjs: 4.1.1 - lodash: ^4.17.21 - pluralize: ^8.0.0 - prop-types: ^15.7.2 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.6.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-text-truncate: ^0.19.0 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.21.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: f1c9290fd1358561c9a1098200cdf1d2dc16117aebf4010759f122b0a638acb50a89faa24988ad4a854ace59a74606329550c59fc98ab6281feb4b4f5bfe52c0 - languageName: node - linkType: hard - -"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": - version: 0.0.0-use.local - resolution: "@backstage/core-components@workspace:packages/core-components" - dependencies: - "@backstage/catalog-model": "workspace:^" - "@backstage/cli": "workspace:^" - "@backstage/config": "workspace:^" - "@backstage/core-app-api": "workspace:^" - "@backstage/core-plugin-api": "workspace:^" - "@backstage/errors": "workspace:^" - "@backstage/plugin-catalog-react": "workspace:^" - "@backstage/test-utils": "workspace:^" - "@backstage/theme": "workspace:^" - "@backstage/version-bridge": "workspace:^" - "@date-io/core": ^1.3.13 - "@material-table/core": ^3.1.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^20.0.0 - "@testing-library/dom": ^9.0.0 - "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 - "@testing-library/user-event": ^14.0.0 - "@types/ansi-regex": ^5.0.0 - "@types/classnames": ^2.2.9 - "@types/d3-selection": ^3.0.1 - "@types/d3-shape": ^3.0.1 - "@types/d3-zoom": ^3.0.1 - "@types/dagre": ^0.7.44 - "@types/google-protobuf": ^3.7.2 - "@types/react": ^16.13.1 || ^17.0.0 - "@types/react-helmet": ^6.1.0 - "@types/react-sparklines": ^1.7.0 - "@types/react-syntax-highlighter": ^15.0.0 - "@types/react-text-truncate": ^0.14.0 - "@types/react-virtualized-auto-sizer": ^1.0.1 - "@types/react-window": ^1.8.5 - "@types/zen-observable": ^0.8.0 - ansi-regex: ^6.0.1 - classnames: ^2.2.6 - cross-fetch: ^3.1.5 - d3-selection: ^3.0.0 - d3-shape: ^3.0.0 - d3-zoom: ^3.0.0 - dagre: ^0.8.5 - history: ^5.0.0 - immer: ^9.0.1 - linkify-react: 4.1.1 - linkifyjs: 4.1.1 - lodash: ^4.17.21 - msw: ^1.0.0 - pluralize: ^8.0.0 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.6.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-text-truncate: ^0.19.0 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.21.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - languageName: unknown - linkType: soft - -"@backstage/core-plugin-api@npm:^1.3.0, @backstage/core-plugin-api@npm:^1.5.0, @backstage/core-plugin-api@npm:^1.6.0": - version: 1.6.0 - resolution: "@backstage/core-plugin-api@npm:1.6.0" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.5 - "@types/react": ^16.13.1 || ^17.0.0 - history: ^5.0.0 - i18next: ^22.4.15 - prop-types: ^15.7.2 - zen-observable: ^0.10.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 540deb91d3c143ce1c3736359c3301af64fbd6eccbaae61bfc96f4e180654e7eb025bb1d4ff5be62b7ea3d6dac7ed617e4dba0c176cfdbf865400fde0f987ddb - languageName: node - linkType: hard - -"@backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.6.0, @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: @@ -4201,15 +4141,14 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 history: ^5.0.0 i18next: ^22.4.15 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4259,7 +4198,7 @@ __metadata: "@material-ui/icons": ^4.9.1 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 react-use: ^17.2.4 @@ -4288,18 +4227,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@npm:^1.1.5, @backstage/errors@npm:^1.2.2": - version: 1.2.2 - resolution: "@backstage/errors@npm:1.2.2" - dependencies: - "@backstage/types": ^1.1.1 - cross-fetch: ^3.1.5 - serialize-error: ^8.0.1 - checksum: 2fd323d528023654ac0910a5bd8ea703fa97a4bd62ee34b6c75e1c992d1a78cae661f0929c1ffd72df5465a1bda69c1bcad2682f017e5e52daa73154e6284234 - languageName: node - linkType: hard - -"@backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4338,11 +4266,11 @@ __metadata: "@material-ui/core": ^4.12.4 "@material-ui/icons": ^4.11.3 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 lodash: ^4.17.21 peerDependencies: - react: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4352,18 +4280,22 @@ __metadata: resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api" dependencies: "@backstage/cli": "workspace:^" + "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/frontend-app-api": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" + "@backstage/version-bridge": "workspace:^" + "@material-ui/core": ^4.12.4 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 + history: ^5.3.0 lodash: ^4.17.21 zod: ^3.21.4 zod-to-json-schema: ^3.21.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4387,29 +4319,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.19": - version: 1.1.19 - resolution: "@backstage/integration-react@npm:1.1.19" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/core-components": ^0.13.5 - "@backstage/core-plugin-api": ^1.6.0 - "@backstage/integration": ^1.7.0 - "@backstage/theme": ^0.4.2 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@types/react": ^16.13.1 || ^17.0.0 - react-use: ^17.2.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 8ef2b46bf91b71351aa4b114de147d130e0298d8849cf2fa358ac1559c2026ffbfad10b15f6fa4bf94c7bbb4f4419766c6c66b77d2859fe184a43351f1f5df81 - languageName: node - linkType: hard - -"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@^1.1.19, @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: @@ -4427,29 +4337,12 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft -"@backstage/integration@npm:^1.7.0": - version: 1.7.0 - resolution: "@backstage/integration@npm:1.7.0" - dependencies: - "@azure/identity": ^3.2.1 - "@backstage/config": ^1.1.0 - "@backstage/errors": ^1.2.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: f02516b7bdb7adb0516b49b90802e588f09c43b4db66bcce68314518c46b9c6fb8ca76ac7a55d4a80cdd414bb6876475b42eb6256b2efda9824ad3667ffa8f54 - languageName: node - linkType: hard - "@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" @@ -4534,7 +4427,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/git-url-parse": ^9.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -4545,8 +4438,8 @@ __metadata: react-use: ^17.2.4 remark-gfm: ^3.0.1 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4590,14 +4483,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4620,14 +4513,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4646,7 +4539,7 @@ __metadata: "@backstage/theme": "workspace:^" "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/jest": ^28.1.3 "@types/react": ^16.13.1 || ^17.0.0 @@ -4654,8 +4547,8 @@ __metadata: react-ga4: ^2.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4677,15 +4570,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-ga: ^3.3.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4703,12 +4596,12 @@ __metadata: "@backstage/test-utils": "workspace:^" "@newrelic/browser-agent": ^1.236.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 languageName: unknown linkType: soft @@ -4727,7 +4620,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -4735,8 +4628,8 @@ __metadata: qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4750,8 +4643,8 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 grpc-docs: ^1.1.2 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4776,7 +4669,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/swagger-ui-react": ^4.18.0 @@ -4789,8 +4682,8 @@ __metadata: react-use: ^17.2.4 swagger-ui-react: ^5.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -4811,15 +4704,15 @@ __metadata: "@material-ui/icons": ^4.9.1 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 use-deep-compare-effect: ^1.8.1 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5150,7 +5043,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 humanize-duration: ^3.27.0 @@ -5158,8 +5051,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5213,15 +5106,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^3.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5275,8 +5168,8 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5327,8 +5220,8 @@ __metadata: react-hook-form: ^7.13.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5364,7 +5257,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/recharts": ^1.8.15 @@ -5375,8 +5268,8 @@ __metadata: react-use: ^17.2.4 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5831,18 +5724,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@npm:^1.0.10, @backstage/plugin-catalog-common@npm:^1.0.16": - version: 1.0.16 - resolution: "@backstage/plugin-catalog-common@npm:1.0.16" - dependencies: - "@backstage/catalog-model": ^1.4.2 - "@backstage/plugin-permission-common": ^0.7.8 - "@backstage/plugin-search-common": ^1.2.6 - checksum: 0dd21c3b704abff78fb091c4c35b0217e557d9a7298fe4227c3a58aa7b2a906ba2d7b7aefce9534ad03d152502dec465d30c07873409f8f803929d62acef9594 - languageName: node - linkType: hard - -"@backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.10, @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: @@ -5874,8 +5756,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 classnames: ^2.3.1 @@ -5884,8 +5765,8 @@ __metadata: qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5915,8 +5796,8 @@ __metadata: node-fetch: ^2.6.7 winston: ^3.2.1 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5934,6 +5815,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" @@ -5945,8 +5827,7 @@ __metadata: "@octokit/rest": ^19.0.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 git-url-parse: ^13.0.0 @@ -5957,8 +5838,8 @@ __metadata: react-use: ^17.2.4 yaml: ^2.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -5979,44 +5860,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.8.4": - version: 1.8.4 - resolution: "@backstage/plugin-catalog-react@npm:1.8.4" - dependencies: - "@backstage/catalog-client": ^1.4.4 - "@backstage/catalog-model": ^1.4.2 - "@backstage/core-components": ^0.13.5 - "@backstage/core-plugin-api": ^1.6.0 - "@backstage/errors": ^1.2.2 - "@backstage/integration": ^1.7.0 - "@backstage/plugin-catalog-common": ^1.0.16 - "@backstage/plugin-permission-common": ^0.7.8 - "@backstage/plugin-permission-react": ^0.4.15 - "@backstage/theme": ^0.4.2 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.5 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^23.0.0 - "@types/react": ^16.13.1 || ^17.0.0 - classnames: ^2.2.6 - jwt-decode: ^3.1.0 - lodash: ^4.17.21 - material-ui-popup-state: ^1.9.3 - qs: ^6.9.4 - react-use: ^17.2.4 - yaml: ^2.0.0 - zen-observable: ^0.10.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 6434741a60e4f53604a958c121d283d3d8b2756e1013d3a9b32659ae41b58359cbc3bee0791a95a35c847f43a76de9f9d2ea1f8e5fa6697adfc9115b5042a57e - languageName: node - linkType: hard - -"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.4, @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: @@ -6027,6 +5871,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" @@ -6042,8 +5887,7 @@ __metadata: "@react-hookz/web": ^23.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/zen-observable": ^0.8.0 @@ -6056,8 +5900,8 @@ __metadata: yaml: ^2.0.0 zen-observable: ^0.10.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6079,14 +5923,14 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6119,7 +5963,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 history: ^5.0.0 @@ -6128,8 +5972,8 @@ __metadata: react-use: ^17.2.4 zen-observable: ^0.10.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6148,8 +5992,8 @@ __metadata: luxon: ^3.0.0 p-limit: ^4.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6176,8 +6020,8 @@ __metadata: react-use: ^17.3.1 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6200,7 +6044,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/humanize-duration": ^3.25.1 "@types/react": ^16.13.1 || ^17.0.0 @@ -6212,8 +6056,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6236,7 +6080,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -6245,8 +6089,8 @@ __metadata: qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6268,7 +6112,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/humanize-duration": ^3.27.1 "@types/luxon": ^3.0.0 @@ -6278,8 +6122,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6334,7 +6178,7 @@ __metadata: "@material-ui/styles": ^4.11.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/highlightjs": ^10.1.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -6345,8 +6189,8 @@ __metadata: react-use: ^17.2.4 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6369,15 +6213,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 rc-progress: 3.5.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6401,7 +6245,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 jsonschema: ^1.2.6 @@ -6409,8 +6253,8 @@ __metadata: react-use: ^17.2.4 zen-observable: ^0.10.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6444,7 +6288,7 @@ __metadata: "@material-ui/styles": ^4.9.6 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/pluralize": ^0.0.31 "@types/react": ^16.13.1 || ^17.0.0 @@ -6464,8 +6308,8 @@ __metadata: regression: ^2.0.1 yup: ^0.32.9 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6537,7 +6381,7 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.57 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 cross-fetch: ^3.1.5 msw: ^1.0.0 @@ -6545,8 +6389,8 @@ __metadata: react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6568,7 +6412,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 express: ^4.18.1 @@ -6576,8 +6420,8 @@ __metadata: react-use: ^17.2.4 peerDependencies: "@backstage/plugin-catalog-react": "workspace:^" - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6636,15 +6480,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.1 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6674,7 +6517,7 @@ __metadata: "@react-hookz/web": ^20.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@uiw/react-codemirror": ^4.9.3 @@ -6683,8 +6526,8 @@ __metadata: react-use: ^17.2.4 yaml: ^2.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6863,14 +6706,14 @@ __metadata: "@backstage/test-utils": "workspace:^" "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 msw: ^1.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6900,7 +6743,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 classnames: ^2.2.6 @@ -6909,8 +6752,8 @@ __metadata: pluralize: ^8.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6933,15 +6776,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^3.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6965,7 +6808,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -6974,8 +6817,8 @@ __metadata: p-limit: ^3.0.2 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -6999,7 +6842,7 @@ __metadata: "@tanstack/react-query": ^4.1.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/dompurify": ^2.3.3 "@types/react": ^16.13.1 || ^17.0.0 @@ -7013,8 +6856,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7036,14 +6879,14 @@ __metadata: "@react-hookz/web": ^20.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 msw: ^1.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7066,8 +6909,7 @@ __metadata: "@octokit/rest": ^19.0.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/recharts": ^1.8.15 @@ -7077,8 +6919,8 @@ __metadata: react-use: ^17.2.4 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7104,7 +6946,7 @@ __metadata: "@octokit/rest": ^19.0.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -7113,8 +6955,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7141,15 +6983,15 @@ __metadata: "@octokit/graphql": ^5.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^3.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7174,7 +7016,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^3.0.0 @@ -7182,8 +7024,8 @@ __metadata: octokit: ^2.0.4 react-use: ^17.4.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7207,7 +7049,7 @@ __metadata: "@octokit/rest": ^19.0.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^3.0.0 @@ -7215,8 +7057,8 @@ __metadata: p-limit: ^4.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7238,15 +7080,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7270,7 +7112,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/lodash": ^4.14.173 "@types/luxon": ^3.0.0 @@ -7281,8 +7123,8 @@ __metadata: qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7304,7 +7146,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/codemirror": ^5.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -7315,8 +7157,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7362,38 +7204,20 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 graphql-voyager: ^1.0.0-rc.31 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft -"@backstage/plugin-home-react@npm:^0.1.3": - version: 0.1.3 - resolution: "@backstage/plugin-home-react@npm:0.1.3" - dependencies: - "@backstage/core-components": ^0.13.5 - "@backstage/core-plugin-api": ^1.6.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@rjsf/utils": 5.13.0 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: e87c9fd44c65aa1a768555812f32f42b1d2dc7ab1097c283cae37105d1f17a7b1b198c85d39d72258551015161f317c8e4538a652f6e8ebe9800c3a365f6ebc3 - languageName: node - linkType: hard - -"@backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": +"@backstage/plugin-home-react@^0.1.3, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": version: 0.0.0-use.local resolution: "@backstage/plugin-home-react@workspace:plugins/home-react" dependencies: @@ -7408,15 +7232,15 @@ __metadata: "@rjsf/utils": 5.13.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/react-grid-layout": ^1.3.2 cross-fetch: ^3.1.5 msw: ^1.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7432,6 +7256,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-home-react": "workspace:^" "@backstage/test-utils": "workspace:^" @@ -7440,14 +7265,13 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@rjsf/core-v5": "npm:@rjsf/core@5.13.0" - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0" + "@rjsf/core": 5.13.0 + "@rjsf/material-ui": 5.13.0 "@rjsf/utils": 5.13.0 "@rjsf/validator-ajv8": 5.13.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.1 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/react-grid-layout": ^1.3.2 @@ -7459,8 +7283,8 @@ __metadata: react-use: ^17.2.4 zod: ^3.21.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7486,7 +7310,7 @@ __metadata: "@material-ui/pickers": ^3.3.10 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 humanize-duration: ^3.26.0 @@ -7494,8 +7318,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7560,7 +7384,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/testing-library__jest-dom": ^5.9.1 @@ -7569,8 +7393,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7617,16 +7441,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 jest-when: ^3.1.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7707,8 +7530,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 @@ -7720,8 +7542,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7777,8 +7599,7 @@ __metadata: "@material-ui/icons": ^4.11.3 "@material-ui/lab": ^4.0.0-alpha.61 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.1 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cronstrue: ^2.32.0 jest-websocket-mock: ^2.5.0 @@ -7792,7 +7613,7 @@ __metadata: xterm-addon-attach: ^0.9.0 xterm-addon-fit: ^0.8.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 languageName: unknown linkType: soft @@ -7822,8 +7643,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cronstrue: ^2.2.0 @@ -7838,8 +7658,8 @@ __metadata: xterm-addon-attach: ^0.9.0 xterm-addon-fit: ^0.8.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7891,15 +7711,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7967,7 +7786,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 luxon: ^2.0.2 @@ -7975,8 +7794,8 @@ __metadata: react-use: ^17.2.4 slugify: ^1.6.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -7999,7 +7818,7 @@ __metadata: "@tanstack/react-query": ^4.1.3 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 classnames: ^2.3.1 @@ -8010,8 +7829,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8035,8 +7854,8 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8058,7 +7877,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/parse-link-header": ^2.0.1 "@types/react": ^16.13.1 || ^17.0.0 @@ -8067,8 +7886,8 @@ __metadata: parse-link-header: ^2.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8112,7 +7931,7 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -8120,8 +7939,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8144,14 +7963,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8174,7 +7993,7 @@ __metadata: "@material-ui/pickers": ^3.3.10 "@material-ui/styles": ^4.11.5 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 axios: ^1.4.0 @@ -8185,7 +8004,7 @@ __metadata: react-use: ^17.2.4 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: "*" languageName: unknown linkType: soft @@ -8209,14 +8028,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8243,8 +8062,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.1 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 lodash: ^4.17.21 @@ -8254,8 +8072,8 @@ __metadata: qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8280,7 +8098,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 classnames: ^2.2.6 @@ -8288,8 +8106,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8333,7 +8151,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -8341,8 +8159,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8389,20 +8207,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@npm:^0.7.8": - version: 0.7.8 - resolution: "@backstage/plugin-permission-common@npm:0.7.8" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/errors": ^1.2.2 - "@backstage/types": ^1.1.1 - cross-fetch: ^3.1.5 - uuid: ^8.0.0 - zod: ^3.21.4 - checksum: 495f92d0360ab36bb707b0de527e31f42d699b177875c2ed4e8519c9721745ec1b67be547cd5862162e5d48e240ed07d9ab179c022adaf8367f03ef7ded6459e - 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" @@ -8441,25 +8245,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@npm:^0.4.15": - version: 0.4.15 - resolution: "@backstage/plugin-permission-react@npm:0.4.15" - dependencies: - "@backstage/config": ^1.1.0 - "@backstage/core-plugin-api": ^1.6.0 - "@backstage/plugin-permission-common": ^0.7.8 - "@types/react": ^16.13.1 || ^17.0.0 - cross-fetch: ^3.1.5 - react-use: ^17.2.4 - swr: ^2.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 5f11264a7d46bee0924b9a00133e756e38d3cce5ce842104546963e08b8bfc6445e28ac4b2b75878fd5407631353e964e5f0b399bc958a76aaa732741b80a52a - 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" @@ -8470,14 +8255,14 @@ __metadata: "@backstage/plugin-permission-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 react-use: ^17.2.4 swr: ^2.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8547,8 +8332,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 lodash: ^4.17.21 @@ -8559,8 +8343,8 @@ __metadata: react-use: ^17.2.4 swr: ^2.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8612,14 +8396,14 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.57 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8667,8 +8451,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -8677,8 +8460,8 @@ __metadata: react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8710,6 +8493,7 @@ __metadata: resolution: "@backstage/plugin-scaffolder-backend-module-cookiecutter@workspace:plugins/scaffolder-backend-module-cookiecutter" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" @@ -8718,10 +8502,8 @@ __metadata: "@backstage/types": "workspace:^" "@types/command-exists": ^1.2.0 "@types/fs-extra": ^9.0.1 - "@types/mock-fs": ^4.13.0 command-exists: ^1.2.9 fs-extra: 10.1.0 - mock-fs: ^5.2.0 msw: ^1.0.0 winston: ^3.2.1 yn: ^4.0.0 @@ -8749,6 +8531,7 @@ __metadata: resolution: "@backstage/plugin-scaffolder-backend-module-rails@workspace:plugins/scaffolder-backend-module-rails" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" @@ -8757,12 +8540,10 @@ __metadata: "@backstage/types": "workspace:^" "@types/command-exists": ^1.2.0 "@types/fs-extra": ^9.0.1 - "@types/mock-fs": ^4.13.0 "@types/node": ^18.17.8 command-exists: ^1.2.9 fs-extra: ^10.0.1 jest-when: ^3.1.0 - mock-fs: ^5.2.0 languageName: unknown linkType: soft @@ -8920,16 +8701,13 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 - "@rjsf/core": ^3.2.1 - "@rjsf/core-v5": "npm:@rjsf/core@5.13.0" - "@rjsf/material-ui": ^3.2.1 - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0" + "@rjsf/core": 5.13.0 + "@rjsf/material-ui": 5.13.0 "@rjsf/utils": 5.13.0 "@rjsf/validator-ajv8": 5.13.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/humanize-duration": ^3.18.1 "@types/json-schema": ^7.0.9 @@ -8949,8 +8727,8 @@ __metadata: zod: ^3.21.4 zod-to-json-schema: ^3.20.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -8986,14 +8764,13 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 - "@rjsf/core": ^3.2.1 - "@rjsf/material-ui": ^3.2.1 + "@rjsf/core": 5.13.0 + "@rjsf/material-ui": 5.13.0 "@rjsf/utils": 5.13.0 "@rjsf/validator-ajv8": 5.13.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/humanize-duration": ^3.18.1 "@types/json-schema": ^7.0.9 @@ -9017,8 +8794,8 @@ __metadata: zod: ^3.21.4 zod-to-json-schema: ^3.20.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9105,6 +8882,25 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-backend-module-stack-overflow-collator@workspace:^, @backstage/plugin-search-backend-module-stack-overflow-collator@workspace:plugins/search-backend-module-stack-overflow-collator": + version: 0.0.0-use.local + resolution: "@backstage/plugin-search-backend-module-stack-overflow-collator@workspace:plugins/search-backend-module-stack-overflow-collator" + dependencies: + "@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-search-backend-node": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + msw: ^1.2.1 + node-fetch: ^2.6.7 + qs: ^6.9.4 + winston: ^3.2.1 + languageName: unknown + linkType: soft + "@backstage/plugin-search-backend-module-techdocs@workspace:^, @backstage/plugin-search-backend-module-techdocs@workspace:plugins/search-backend-module-techdocs": version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-techdocs@workspace:plugins/search-backend-module-techdocs" @@ -9184,16 +8980,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-search-common@npm:^1.2.6": - version: 1.2.6 - resolution: "@backstage/plugin-search-common@npm:1.2.6" - dependencies: - "@backstage/plugin-permission-common": ^0.7.8 - "@backstage/types": ^1.1.1 - checksum: 19ee6ef72ce75fce6c0e3da5e978419fd01f795db3e701460da652e8581e3eb53fba800c56d518147d03bd4e1e3889fa18e1d11a82a38c26a304fdc3bc5438bc - 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" @@ -9224,16 +9010,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 lodash: ^4.17.21 qs: ^6.9.4 react-use: ^17.3.2 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9263,8 +9048,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 history: ^5.0.0 @@ -9272,8 +9056,8 @@ __metadata: qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9298,7 +9082,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -9308,8 +9092,8 @@ __metadata: react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9331,7 +9115,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/zen-observable": ^0.8.2 @@ -9341,8 +9125,8 @@ __metadata: uuid: ^8.3.2 zen-observable: ^0.10.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9378,8 +9162,8 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@types/react": ^16.13.1 || ^17.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9404,7 +9188,7 @@ __metadata: "@material-ui/styles": ^4.10.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -9413,8 +9197,8 @@ __metadata: rc-progress: 3.5.1 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9437,7 +9221,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -9446,8 +9230,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9460,6 +9244,7 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/plugin-search-backend-module-stack-overflow-collator": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" msw: ^1.0.0 @@ -9479,6 +9264,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-home-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" @@ -9488,7 +9274,7 @@ __metadata: "@material-ui/icons": ^4.9.1 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -9497,8 +9283,8 @@ __metadata: qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9519,14 +9305,14 @@ __metadata: "@material-ui/icons": ^4.9.1 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9630,15 +9416,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9660,7 +9446,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/color": ^3.0.1 "@types/d3-force": ^3.0.0 @@ -9671,8 +9457,8 @@ __metadata: msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9698,15 +9484,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 testing-library__dom: ^7.29.4-beta.1 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9767,7 +9553,7 @@ __metadata: "@react-hookz/web": ^20.0.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 git-url-parse: ^13.0.0 @@ -9775,8 +9561,8 @@ __metadata: photoswipe: ^5.3.7 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9840,16 +9626,15 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.11.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 jss: ~10.10.0 lodash: ^4.17.21 react-helmet: 6.1.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9882,8 +9667,7 @@ __metadata: "@material-ui/styles": ^4.10.0 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/dompurify": ^2.2.2 "@types/event-source-polyfill": ^1.0.0 @@ -9950,14 +9734,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -9971,6 +9755,7 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/types": "workspace:^" @@ -10006,7 +9791,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -10014,8 +9799,8 @@ __metadata: react-use: ^17.2.4 zen-observable: ^0.10.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -10066,14 +9851,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -10095,7 +9880,7 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -10105,8 +9890,8 @@ __metadata: react-use: ^17.2.4 recharts: ^2.5.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -10202,6 +9987,23 @@ __metadata: languageName: unknown linkType: soft +"@backstage/theme@^0.4.2, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": + version: 0.0.0-use.local + resolution: "@backstage/theme@workspace:packages/theme" + dependencies: + "@backstage/cli": "workspace:^" + "@emotion/react": ^11.10.5 + "@emotion/styled": ^11.10.5 + "@mui/material": ^5.12.2 + "@types/react": ^16.13.1 || ^17.0.0 + peerDependencies: + "@material-ui/core": ^4.12.2 + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + languageName: unknown + linkType: soft + "@backstage/theme@npm:^0.2.16, @backstage/theme@npm:^0.2.18": version: 0.2.19 resolution: "@backstage/theme@npm:0.2.19" @@ -10214,40 +10016,7 @@ __metadata: languageName: node linkType: hard -"@backstage/theme@npm:^0.4.2": - version: 0.4.2 - resolution: "@backstage/theme@npm:0.4.2" - dependencies: - "@emotion/react": ^11.10.5 - "@emotion/styled": ^11.10.5 - "@mui/material": ^5.12.2 - peerDependencies: - "@material-ui/core": ^4.12.2 - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - checksum: 22371c3159ed4d2f6d53925d48318d5f8f66ac9d6df6ff32f34b4b52e070e88ada25031b2a8fc3264cb352a24f4128fa1295b1302d1d3f12df3bcb76c785f605 - languageName: node - linkType: hard - -"@backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": - version: 0.0.0-use.local - resolution: "@backstage/theme@workspace:packages/theme" - dependencies: - "@backstage/cli": "workspace:^" - "@emotion/react": ^11.10.5 - "@emotion/styled": ^11.10.5 - "@mui/material": ^5.12.2 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - "@material-ui/core": ^4.12.2 - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - languageName: unknown - linkType: soft - -"@backstage/types@^1.0.2, @backstage/types@^1.1.1, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/types@^1.0.2, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: @@ -10258,18 +10027,17 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@^1.0.5, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: "@backstage/cli": "workspace:^" "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 - "@testing-library/react-hooks": ^8.0.0 + "@testing-library/react": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -10907,36 +10675,6 @@ __metadata: languageName: node linkType: hard -"@esbuild-kit/cjs-loader@npm:^2.4.1": - version: 2.4.2 - resolution: "@esbuild-kit/cjs-loader@npm:2.4.2" - dependencies: - "@esbuild-kit/core-utils": ^3.0.0 - get-tsconfig: ^4.4.0 - checksum: e346e339bfc7eff5c52c270fd0ec06a7f2341b624adfb69f84b7d83f119c35070420906f2761a0b4604e0a0ec90e35eaf12544585476c428ed6d6ee3b250c0fe - languageName: node - linkType: hard - -"@esbuild-kit/core-utils@npm:^3.0.0, @esbuild-kit/core-utils@npm:^3.3.2": - version: 3.3.2 - resolution: "@esbuild-kit/core-utils@npm:3.3.2" - dependencies: - esbuild: ~0.18.20 - source-map-support: ^0.5.21 - checksum: 62f3b97457fa4ef39d752bd2ad1c8adac08929b50c411f5259f105cc74896f1fdb3429a540aa423e8eae37f32ef44656ca21ccb9a723cd9955d65a820960ab1f - languageName: node - linkType: hard - -"@esbuild-kit/esm-loader@npm:^2.5.5": - version: 2.6.5 - resolution: "@esbuild-kit/esm-loader@npm:2.6.5" - dependencies: - "@esbuild-kit/core-utils": ^3.3.2 - get-tsconfig: ^4.7.0 - checksum: 88a27203898f14bd69f03244ae2b3bae727e00243d7801292c4da8caba69813b0978fb8245a55b83bc9b907f475ed634f094a1f44cc590c0754993f4a924cc22 - languageName: node - linkType: hard - "@esbuild/android-arm64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/android-arm64@npm:0.16.17" @@ -12588,14 +12326,14 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 msw: ^1.0.0 react-use: ^17.2.4 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -12982,13 +12720,20 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": +"@jridgewell/sourcemap-codec@npm:1.4.14": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 languageName: node linkType: hard +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:0.3.9": version: 0.3.9 resolution: "@jridgewell/trace-mapping@npm:0.3.9" @@ -13382,7 +13127,7 @@ __metadata: languageName: node linkType: hard -"@material-ui/pickers@npm:^3.2.10, @material-ui/pickers@npm:^3.3.10": +"@material-ui/pickers@npm:3.3.11": version: 3.3.11 resolution: "@material-ui/pickers@npm:3.3.11" dependencies: @@ -13402,6 +13147,26 @@ __metadata: languageName: node linkType: hard +"@material-ui/pickers@patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch::locator=root%40workspace%3A.": + version: 3.3.11 + resolution: "@material-ui/pickers@patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch::version=3.3.11&hash=c18f79&locator=root%40workspace%3A." + dependencies: + "@babel/runtime": ^7.6.0 + "@date-io/core": 1.x + "@types/styled-jsx": ^2.2.8 + clsx: ^1.0.2 + react-transition-group: ^4.0.0 + rifm: ^0.7.0 + peerDependencies: + "@date-io/core": ^1.3.6 + "@material-ui/core": ^4.0.0 + prop-types: ^15.6.0 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + checksum: e736e4d53f1b660f4a338e8ca3537dc86638ed41ed988f42baebb18d35d5eab19e4b35952217a46032128639a9af59b354f78dbccc02d90971b844bc5a8cdcf0 + languageName: node + linkType: hard + "@material-ui/styles@npm:^4.10.0, @material-ui/styles@npm:^4.11.0, @material-ui/styles@npm:^4.11.4, @material-ui/styles@npm:^4.11.5, @material-ui/styles@npm:^4.9.6": version: 4.11.5 resolution: "@material-ui/styles@npm:4.11.5" @@ -14904,7 +14669,7 @@ __metadata: languageName: node linkType: hard -"@rjsf/core-v5@npm:@rjsf/core@5.13.0": +"@rjsf/core@npm:5.13.0": version: 5.13.0 resolution: "@rjsf/core@npm:5.13.0" dependencies: @@ -14920,26 +14685,7 @@ __metadata: languageName: node linkType: hard -"@rjsf/core@npm:^3.2.1": - version: 3.2.1 - resolution: "@rjsf/core@npm:3.2.1" - dependencies: - "@types/json-schema": ^7.0.7 - ajv: ^6.7.0 - core-js-pure: ^3.6.5 - json-schema-merge-allof: ^0.6.0 - jsonpointer: ^5.0.0 - lodash: ^4.17.15 - nanoid: ^3.1.23 - prop-types: ^15.7.2 - react-is: ^16.9.0 - peerDependencies: - react: ">=16" - checksum: 2142d4a31229ea242b79aca4ed93e2fe89e75f15ce93111457c3017d3ab295cae8f53e4dd870c619afa571959d00f46b3c19085c6a336f522c891fc07ecc46f1 - languageName: node - linkType: hard - -"@rjsf/material-ui-v5@npm:@rjsf/material-ui@5.13.0": +"@rjsf/material-ui@npm:5.13.0": version: 5.13.0 resolution: "@rjsf/material-ui@npm:5.13.0" peerDependencies: @@ -14952,18 +14698,6 @@ __metadata: languageName: node linkType: hard -"@rjsf/material-ui@npm:^3.2.1": - version: 3.2.1 - resolution: "@rjsf/material-ui@npm:3.2.1" - peerDependencies: - "@material-ui/core": ^4.2.0 - "@material-ui/icons": ^4.2.1 - "@rjsf/core": ^3.0.0 - react: ">=16" - checksum: bd25cd9f2e2d568c653755e7268fe3e53279e1ae675e39bccd85f65557623d2052b706763e017a949f897751e25a16d0f2c8b995508bb56907be6786b09e2b1e - languageName: node - linkType: hard - "@rjsf/utils@npm:5.13.0": version: 5.13.0 resolution: "@rjsf/utils@npm:5.13.0" @@ -15119,6 +14853,22 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-inject@npm:^5.0.3": + version: 5.0.3 + resolution: "@rollup/plugin-inject@npm:5.0.3" + dependencies: + "@rollup/pluginutils": ^5.0.1 + estree-walker: ^2.0.2 + magic-string: ^0.27.0 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: d8458b11af3447710ce200fe2886faff07bb054e1269a4f06f5f3c1a1b83019b6ce7761badfa116ca96fbb9c49f16b94ad02d1a72c2fb64dc68cb7dd81331cb7 + languageName: node + linkType: hard + "@rollup/plugin-json@npm:^5.0.0": version: 5.0.2 resolution: "@rollup/plugin-json@npm:5.0.2" @@ -15178,7 +14928,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^4.1.1, @rollup/pluginutils@npm:^4.2.1": +"@rollup/pluginutils@npm:^4.1.1, @rollup/pluginutils@npm:^4.2.0, @rollup/pluginutils@npm:^4.2.1": version: 4.2.1 resolution: "@rollup/pluginutils@npm:4.2.1" dependencies: @@ -15189,8 +14939,8 @@ __metadata: linkType: hard "@rollup/pluginutils@npm:^5.0.1": - version: 5.0.2 - resolution: "@rollup/pluginutils@npm:5.0.2" + version: 5.0.4 + resolution: "@rollup/pluginutils@npm:5.0.4" dependencies: "@types/estree": ^1.0.0 estree-walker: ^2.0.2 @@ -15200,7 +14950,7 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce + checksum: 893d5805ac4121fc704926963a0ae4e79e9e2bc8d736c3b28499ab69a404cce5119ca3a4e0c3d3a81d62f1beb3966f35285c36935d94b061794f26e94fed4cd1 languageName: node linkType: hard @@ -17002,22 +16752,6 @@ __metadata: languageName: unknown linkType: soft -"@testing-library/dom@npm:^8.0.0": - version: 8.20.1 - resolution: "@testing-library/dom@npm:8.20.1" - dependencies: - "@babel/code-frame": ^7.10.4 - "@babel/runtime": ^7.12.5 - "@types/aria-query": ^5.0.1 - aria-query: 5.1.3 - chalk: ^4.1.0 - dom-accessibility-api: ^0.5.9 - lz-string: ^1.5.0 - pretty-format: ^27.0.2 - checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 - languageName: node - linkType: hard - "@testing-library/dom@npm:^9.0.0": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" @@ -17064,7 +16798,7 @@ __metadata: languageName: node linkType: hard -"@testing-library/react-hooks@npm:^8.0.0, @testing-library/react-hooks@npm:^8.0.1": +"@testing-library/react-hooks@npm:^8.0.0": version: 8.0.1 resolution: "@testing-library/react-hooks@npm:8.0.1" dependencies: @@ -17086,17 +16820,17 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:^12.1.3": - version: 12.1.5 - resolution: "@testing-library/react@npm:12.1.5" +"@testing-library/react@npm:^14.0.0": + version: 14.0.0 + resolution: "@testing-library/react@npm:14.0.0" dependencies: "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.0.0 - "@types/react-dom": <18.0.0 + "@testing-library/dom": ^9.0.0 + "@types/react-dom": ^18.0.0 peerDependencies: - react: <18.0.0 - react-dom: <18.0.0 - checksum: 4abd0490405e709a7df584a0db604e508a4612398bb1326e8fa32dd9393b15badc826dcf6d2f7525437886d507871f719f127b9860ed69ddd204d1fa834f576a + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 4a54c8f56cc4a39b50803205f84f06280bb76521d6d5d4b3b36651d760c7c7752ef142d857d52aaf4fad4848ed7a8be49afc793a5dda105955d2f8bef24901ac languageName: node linkType: hard @@ -17237,16 +16971,16 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": - version: 7.1.18 - resolution: "@types/babel__core@npm:7.1.18" +"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.2": + version: 7.20.2 + resolution: "@types/babel__core@npm:7.20.2" dependencies: - "@babel/parser": ^7.1.0 - "@babel/types": ^7.0.0 + "@babel/parser": ^7.20.7 + "@babel/types": ^7.20.7 "@types/babel__generator": "*" "@types/babel__template": "*" "@types/babel__traverse": "*" - checksum: 2e5b5d7c84f347d3789575486e58b0df5c91613abc3d27e716274aba3048518e07e1f068250ba829e2ed58532ccc88da595ce95ba2688e7bbcd7c25a3c6627ed + checksum: 564fbaa8ff1305d50807ada0ec227c3e7528bebb2f8fe6b2ed88db0735a31511a74ad18729679c43eeed8025ed29d408f53059289719e95ab1352ed559a100bd languageName: node linkType: hard @@ -17632,9 +17366,9 @@ __metadata: linkType: hard "@types/diff@npm:^5.0.0": - version: 5.0.5 - resolution: "@types/diff@npm:5.0.5" - checksum: 5f093341d5488cd33079400d4b2ff463dfd4f589bf0a54fbb25f7c87a7bdc16bd1e6125f252c081fa9a3ad44fc78b156c0a5f38bd8128edceb40ba084e051885 + version: 5.0.6 + resolution: "@types/diff@npm:5.0.6" + checksum: 8ce79492a89d568b54792a8491d01b1ff69526e19560670ef2de078c467738cdc0aae81fc4f895e49f915a2b9bbf694f6f95a2e5544e7c0989448956eba9ff66 languageName: node linkType: hard @@ -17667,6 +17401,13 @@ __metadata: languageName: node linkType: hard +"@types/ejs@npm:^3.1.3": + version: 3.1.3 + resolution: "@types/ejs@npm:3.1.3" + checksum: b1b1c6c9d331d237523ebc410789f42edcdbb1d4cdd4a7a37ac61d2ce9c3fbcfbfe7d7f1a7f61c9334812347a0036afd52258ad2198f85545ebfb26d63475a75 + languageName: node + linkType: hard + "@types/es-aggregate-error@npm:^1.0.2": version: 1.0.2 resolution: "@types/es-aggregate-error@npm:1.0.2" @@ -18281,9 +18022,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1": - version: 20.8.3 - resolution: "@types/node@npm:20.8.3" - checksum: bfb88b341faeb19f8fd37306a3bf433721b876c6491d10fcb0b13fd26601fa36ee45113dd82b1e1c23e3c957dff5b99f81a16493cefa03abe797e41a2487a4f7 + version: 20.8.6 + resolution: "@types/node@npm:20.8.6" + dependencies: + undici-types: ~5.25.1 + checksum: ccfb7ac482c5a96edeb239893c5c099f5257fcc2ed9ae62fefdfbc782b79e16dbc2af9a85b379665237bf759904b44ca2be68e75d239e0297882aad42f61905c languageName: node linkType: hard @@ -18309,9 +18052,9 @@ __metadata: linkType: hard "@types/node@npm:^18.17.8": - version: 18.18.4 - resolution: "@types/node@npm:18.18.4" - checksum: 4901e91c4cc479bb58acbcd79236a97a0ad6db4a53cb1f4ba4cf32af15324c61b16faa6e31c1b09bf538a20feb5f5274239157ce5237f5741db0b9ab71e69c52 + version: 18.18.5 + resolution: "@types/node@npm:18.18.5" + checksum: fc8c9b2bf226270cf9085a7dac76ce09dd7c3519ec9b687ee2b50385954ab3709c45ca82d002d1536e24286803cd194d7ab7008acebdcd6681b8b19d4277fa5c languageName: node linkType: hard @@ -18511,12 +18254,12 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^17": - version: 17.0.21 - resolution: "@types/react-dom@npm:17.0.21" +"@types/react-dom@npm:^18": + version: 18.2.13 + resolution: "@types/react-dom@npm:18.2.13" dependencies: - "@types/react": ^17 - checksum: a2e3f068c1374601856b63bc57f3f436cf6270c1ba5c5cef0776def6de296c8bdd31c39b5be9e9e77f4652e923bef1e71ae377a2b038f4a81bfd0fec8d10d0d0 + "@types/react": "*" + checksum: 22ba066b141dca5a5a9227fae0afc7c94b470fff8e8a38ade72649da57a8ea04d0cb2ba3e22005e7d8e772d49bddd28855b1dd98e6defd033bba6afb6edff883 languageName: node linkType: hard @@ -18613,14 +18356,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^17": - version: 17.0.68 - resolution: "@types/react@npm:17.0.68" +"@types/react@npm:^18": + version: 18.2.28 + resolution: "@types/react@npm:18.2.28" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: c6ca4415b53b1abe91162b29af541a1797a56a6f462ef796e8ebda3eaa4d0609205f4f17b3fce8d9a12235d4ffd8a67c47b5e018ed85c2f3bee0fba8f54638c1 + checksum: 81381bedeba83278f4c9febb0b83e0bd3f42a25897a50b9cb36ef53651d34b3d50f87ebf11211ea57ea575131f85d31e93e496ce46478a00b0f9bf7b26b5917a languageName: node linkType: hard @@ -19357,6 +19100,21 @@ __metadata: languageName: node linkType: hard +"@vitejs/plugin-react@npm:^4.0.4": + version: 4.1.0 + resolution: "@vitejs/plugin-react@npm:4.1.0" + dependencies: + "@babel/core": ^7.22.20 + "@babel/plugin-transform-react-jsx-self": ^7.22.5 + "@babel/plugin-transform-react-jsx-source": ^7.22.5 + "@types/babel__core": ^7.20.2 + react-refresh: ^0.14.0 + peerDependencies: + vite: ^4.2.0 + checksum: 73dd403f5bca4f3f99f0bd3dcbb0cc0ecf88f758b886fb599711be744ca93f20adafe1af3574a998ac7cbd24aaf67ac7fe06983d87088cbdf535540ab402d496 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.11.6, @webassemblyjs/ast@npm:^1.11.5": version: 1.11.6 resolution: "@webassemblyjs/ast@npm:1.11.6" @@ -19768,11 +19526,11 @@ __metadata: linkType: hard "acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.9.0": - version: 8.9.0 - resolution: "acorn@npm:8.9.0" + version: 8.10.0 + resolution: "acorn@npm:8.10.0" bin: acorn: bin/acorn - checksum: 25dfb94952386ecfb847e61934de04a4e7c2dc21c2e700fc4e2ef27ce78cb717700c4c4f279cd630bb4774948633c3859fc16063ec8573bda4568e0a312e6744 + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d languageName: node linkType: hard @@ -19892,7 +19650,7 @@ __metadata: languageName: node linkType: hard -"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": +"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.12.6": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -20054,8 +19812,8 @@ __metadata: cross-fetch: ^3.1.5 msw: ^1.0.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 languageName: unknown linkType: soft @@ -21217,6 +20975,15 @@ __metadata: languageName: node linkType: hard +"browser-resolve@npm:^2.0.0": + version: 2.0.0 + resolution: "browser-resolve@npm:2.0.0" + dependencies: + resolve: ^1.17.0 + checksum: 69225e73b555bd6d2a08fb93c7342cfcf3b5058b975099c52649cd5c3cec84c2066c5385084d190faedfb849684d9dabe10129f0cd401d1883572f2e6650f440 + languageName: node + linkType: hard + "browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4": version: 1.2.0 resolution: "browserify-aes@npm:1.2.0" @@ -21339,6 +21106,16 @@ __metadata: languageName: node linkType: hard +"buffer-polyfill@npm:buffer@^6.0.3, buffer@npm:^6.0.3": + version: 6.0.3 + resolution: "buffer@npm:6.0.3" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.2.1 + checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 + languageName: node + linkType: hard + "buffer-writer@npm:2.0.0": version: 2.0.0 resolution: "buffer-writer@npm:2.0.0" @@ -21374,7 +21151,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.5.0": +"buffer@npm:^5.5.0, buffer@npm:^5.7.1": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -21384,16 +21161,6 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^6.0.3": - version: 6.0.3 - resolution: "buffer@npm:6.0.3" - dependencies: - base64-js: ^1.3.1 - ieee754: ^1.2.1 - checksum: 5ad23293d9a731e4318e420025800b42bf0d264004c0286c8cc010af7a270c7a0f6522e84f54b9ad65cbd6db20b8badbfd8d2ebf4f80fa03dab093b89e68c3f9 - languageName: node - linkType: hard - "builtin-modules@npm:^3.0.0": version: 3.2.0 resolution: "builtin-modules@npm:3.2.0" @@ -22551,7 +22318,7 @@ __metadata: languageName: node linkType: hard -"compute-lcm@npm:^1.1.0, compute-lcm@npm:^1.1.2": +"compute-lcm@npm:^1.1.2": version: 1.1.2 resolution: "compute-lcm@npm:1.1.2" dependencies: @@ -22641,6 +22408,13 @@ __metadata: languageName: node linkType: hard +"connect-history-api-fallback@npm:^1.6.0": + version: 1.6.0 + resolution: "connect-history-api-fallback@npm:1.6.0" + checksum: 804ca2be28c999032ecd37a9f71405e5d7b7a4b3defcebbe41077bb8c5a0a150d7b59f51dcc33b2de30bc7e217a31d10f8cfad27e8e74c2fc7655eeba82d6e7e + languageName: node + linkType: hard + "connect-history-api-fallback@npm:^2.0.0": version: 2.0.0 resolution: "connect-history-api-fallback@npm:2.0.0" @@ -22658,7 +22432,7 @@ __metadata: languageName: node linkType: hard -"consola@npm:^2.15.0": +"consola@npm:^2.15.0, consola@npm:^2.15.3": version: 2.15.3 resolution: "consola@npm:2.15.3" checksum: 8ef7a09b703ec67ac5c389a372a33b6dc97eda6c9876443a60d76a3076eea0259e7f67a4e54fd5a52f97df73690822d090cf8b7e102b5761348afef7c6d03e28 @@ -22740,7 +22514,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.6.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 @@ -22817,7 +22591,7 @@ __metadata: languageName: node linkType: hard -"core-js-pure@npm:^3.23.3, core-js-pure@npm:^3.30.2, core-js-pure@npm:^3.6.5": +"core-js-pure@npm:^3.23.3, core-js-pure@npm:^3.30.2": version: 3.31.0 resolution: "core-js-pure@npm:3.31.0" checksum: 2bc5d2f6c3c9732fd5c066529b8d41fae9c746206ddf7614712dc4120a9efd47bf894df4fc600fde8c04324171c1999869798b48b23fca128eff5f09f58cd2f6 @@ -22969,7 +22743,7 @@ __metadata: languageName: node linkType: hard -"create-require@npm:^1.1.0": +"create-require@npm:^1.1.0, create-require@npm:^1.1.1": version: 1.1.1 resolution: "create-require@npm:1.1.1" checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff @@ -23130,16 +22904,16 @@ __metadata: languageName: node linkType: hard -"css-select@npm:^4.1.3": - version: 4.1.3 - resolution: "css-select@npm:4.1.3" +"css-select@npm:^4.1.3, css-select@npm:^4.2.1": + version: 4.3.0 + resolution: "css-select@npm:4.3.0" dependencies: boolbase: ^1.0.0 - css-what: ^5.0.0 - domhandler: ^4.2.0 - domutils: ^2.6.0 - nth-check: ^2.0.0 - checksum: 40928f1aa6c71faf36430e7f26bcbb8ab51d07b98b754caacb71906400a195df5e6c7020a94f2982f02e52027b9bd57c99419220cf7020968c3415f14e4be5f8 + css-what: ^6.0.1 + domhandler: ^4.3.1 + domutils: ^2.8.0 + nth-check: ^2.0.1 + checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 languageName: node linkType: hard @@ -23203,14 +22977,7 @@ __metadata: languageName: node linkType: hard -"css-what@npm:^5.0.0": - version: 5.1.0 - resolution: "css-what@npm:5.1.0" - checksum: 0b75d1bac95c885c168573c85744a6c6843d8c33345f54f717218b37ea6296b0e99bb12105930ea170fd4a921990392a7c790c16c585c1d8960c49e2b7ec39f7 - languageName: node - linkType: hard - -"css-what@npm:^6.1.0": +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe @@ -24193,6 +23960,13 @@ __metadata: languageName: node linkType: hard +"domain-browser@npm:^4.22.0": + version: 4.22.0 + resolution: "domain-browser@npm:4.22.0" + checksum: e7ce1c19073e17dec35cfde050a3ddaac437d3ba8b870adabf9d5682e665eab3084df05de432dedf25b34303f0a2c71ac30f1cdba61b1aea018047b10de3d988 + languageName: node + linkType: hard + "domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" @@ -24218,12 +23992,12 @@ __metadata: languageName: node linkType: hard -"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0": - version: 4.3.0 - resolution: "domhandler@npm:4.3.0" +"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": + version: 4.3.1 + resolution: "domhandler@npm:4.3.1" dependencies: domelementtype: ^2.2.0 - checksum: d2a2dbf40dd99abf936b65ad83c6b530afdb3605a87cad37a11b5d9220e68423ebef1b86c89e0f6d93ffaf315cc327cf1a988652e7a9a95cce539e3984f4c64d + checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa languageName: node linkType: hard @@ -24250,7 +24024,7 @@ __metadata: languageName: node linkType: hard -"domutils@npm:^2.5.2, domutils@npm:^2.6.0": +"domutils@npm:^2.5.2, domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" dependencies: @@ -24291,6 +24065,13 @@ __metadata: languageName: node linkType: hard +"dotenv-expand@npm:^8.0.2": + version: 8.0.3 + resolution: "dotenv-expand@npm:8.0.3" + checksum: 128ce90ac825b543de3ece0154a51b056ab0dc36bb26d97a68cd0b8707327ecd3c182fb6ac63b26a0fcdfa85064419906a1065cb634f1f9dc08ad311375f1fc0 + languageName: node + linkType: hard + "dotenv@npm:^16.0.0": version: 16.0.0 resolution: "dotenv@npm:16.0.0" @@ -24412,13 +24193,13 @@ __metadata: linkType: hard "ejs@npm:^3.1.6": - version: 3.1.7 - resolution: "ejs@npm:3.1.7" + version: 3.1.9 + resolution: "ejs@npm:3.1.9" dependencies: jake: ^10.8.5 bin: ejs: bin/cli.js - checksum: fe40764af39955ce8f8b116716fc8b911959946698edb49ecab85df597746c07aa65d5b74ead28a1e2ffa75b0f92d9bedd752f1c29437da6137b3518271e988c + checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f languageName: node linkType: hard @@ -24868,6 +24649,83 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.18.10, esbuild@npm:~0.18.20": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 + dependenciesMeta: + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b + languageName: node + linkType: hard + "esbuild@npm:^0.19.0": version: 0.19.4 resolution: "esbuild@npm:0.19.4" @@ -24945,83 +24803,6 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:~0.18.20": - version: 0.18.20 - resolution: "esbuild@npm:0.18.20" - dependencies: - "@esbuild/android-arm": 0.18.20 - "@esbuild/android-arm64": 0.18.20 - "@esbuild/android-x64": 0.18.20 - "@esbuild/darwin-arm64": 0.18.20 - "@esbuild/darwin-x64": 0.18.20 - "@esbuild/freebsd-arm64": 0.18.20 - "@esbuild/freebsd-x64": 0.18.20 - "@esbuild/linux-arm": 0.18.20 - "@esbuild/linux-arm64": 0.18.20 - "@esbuild/linux-ia32": 0.18.20 - "@esbuild/linux-loong64": 0.18.20 - "@esbuild/linux-mips64el": 0.18.20 - "@esbuild/linux-ppc64": 0.18.20 - "@esbuild/linux-riscv64": 0.18.20 - "@esbuild/linux-s390x": 0.18.20 - "@esbuild/linux-x64": 0.18.20 - "@esbuild/netbsd-x64": 0.18.20 - "@esbuild/openbsd-x64": 0.18.20 - "@esbuild/sunos-x64": 0.18.20 - "@esbuild/win32-arm64": 0.18.20 - "@esbuild/win32-ia32": 0.18.20 - "@esbuild/win32-x64": 0.18.20 - dependenciesMeta: - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b - languageName: node - linkType: hard - "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -25571,6 +25352,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" + "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/frontend-app-api": "workspace:^" @@ -25626,7 +25408,6 @@ __metadata: "@backstage/plugin-search-react": "workspace:^" "@backstage/plugin-sentry": "workspace:^" "@backstage/plugin-shortcuts": "workspace:^" - "@backstage/plugin-stack-overflow": "workspace:^" "@backstage/plugin-stackstorm": "workspace:^" "@backstage/plugin-tech-insights": "workspace:^" "@backstage/plugin-tech-radar": "workspace:^" @@ -25648,7 +25429,7 @@ __metadata: "@roadiehq/backstage-plugin-travis-ci": ^2.0.5 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/jquery": ^3.3.34 "@types/react": "*" @@ -25658,8 +25439,8 @@ __metadata: cross-env: ^7.0.0 history: ^5.0.0 lodash: ^4.17.21 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.2 + react-dom: ^18.0.2 react-router: ^6.3.0 react-router-dom: ^6.3.0 react-use: ^17.2.4 @@ -25761,19 +25542,23 @@ __metadata: "@roadiehq/backstage-plugin-travis-ci": ^2.0.5 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/jquery": ^3.3.34 "@types/react": "*" "@types/react-dom": "*" "@types/zen-observable": ^0.8.0 + "@vitejs/plugin-react": ^4.0.4 cross-env: ^7.0.0 history: ^5.0.0 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.2 + react-dom: ^18.0.2 react-router: ^6.3.0 react-router-dom: ^6.3.0 react-use: ^17.2.4 + vite: ^4.4.9 + vite-plugin-html: ^3.2.0 + vite-plugin-node-polyfills: ^0.14.1 zen-observable: ^0.10.0 languageName: unknown linkType: soft @@ -26943,7 +26728,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -26953,7 +26738,17 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: latest + checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=18f3a7" dependencies: @@ -26962,6 +26757,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=18f3a7" + dependencies: + node-gyp: latest + conditions: os=darwin + languageName: node + linkType: hard + "function-bind@npm:^1.1.1": version: 1.1.1 resolution: "function-bind@npm:1.1.1" @@ -27152,7 +26956,7 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.4.0, get-tsconfig@npm:^4.7.0": +"get-tsconfig@npm:^4.7.2": version: 4.7.2 resolution: "get-tsconfig@npm:4.7.2" dependencies: @@ -27925,7 +27729,7 @@ __metadata: languageName: node linkType: hard -"history@npm:^5.0.0": +"history@npm:^5.0.0, history@npm:^5.3.0": version: 5.3.0 resolution: "history@npm:5.3.0" dependencies: @@ -28042,7 +27846,7 @@ __metadata: languageName: node linkType: hard -"html-minifier-terser@npm:^6.0.2": +"html-minifier-terser@npm:^6.0.2, html-minifier-terser@npm:^6.1.0": version: 6.1.0 resolution: "html-minifier-terser@npm:6.1.0" dependencies: @@ -28422,12 +28226,12 @@ __metadata: linkType: hard "import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": - version: 3.2.1 - resolution: "import-fresh@npm:3.2.1" + version: 3.3.0 + resolution: "import-fresh@npm:3.3.0" dependencies: parent-module: ^1.0.0 resolve-from: ^4.0.0 - checksum: caef42418a087c3951fb676943a7f21ba8971aa07f9b622dff4af7edcef4160e1b172dccd85a88d7eb109cf41406a4592f70259e6b3b33aeafd042bb61f81d96 + checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa languageName: node linkType: hard @@ -29484,6 +29288,13 @@ __metadata: languageName: node linkType: hard +"isomorphic-timers-promises@npm:^1.0.1": + version: 1.0.1 + resolution: "isomorphic-timers-promises@npm:1.0.1" + checksum: 16ef59f0fbcceba1a037c74b5f7195d252ae058724ccd3e53b37ad034e8498f5532084e8ab18e7940ba3fa8fca2f21403d00eed15802ab1f7cab7c099cba62a8 + languageName: node + linkType: hard + "isomorphic-ws@npm:5.0.0, isomorphic-ws@npm:^5.0.0": version: 5.0.0 resolution: "isomorphic-ws@npm:5.0.0" @@ -30597,17 +30408,6 @@ __metadata: languageName: node linkType: hard -"json-schema-merge-allof@npm:^0.6.0": - version: 0.6.0 - resolution: "json-schema-merge-allof@npm:0.6.0" - dependencies: - compute-lcm: ^1.1.0 - json-schema-compare: ^0.2.2 - lodash: ^4.17.4 - checksum: 2008aede3f5d05d7870e7d5e554e5c6a5b451cfff1357d34d3d8b34e2ba57468a97c76aa5b967bdb411d91b98c734f19f350de578d25b2a0a27cd4e1ca92bd1d - languageName: node - linkType: hard - "json-schema-merge-allof@npm:^0.8.1": version: 0.8.1 resolution: "json-schema-merge-allof@npm:0.8.1" @@ -33524,7 +33324,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.6": +"nanoid@npm:^3.3.6": version: 3.3.6 resolution: "nanoid@npm:3.3.6" bin: @@ -33787,6 +33587,16 @@ __metadata: languageName: node linkType: hard +"node-html-parser@npm:^5.3.3": + version: 5.4.2 + resolution: "node-html-parser@npm:5.4.2" + dependencies: + css-select: ^4.2.1 + he: 1.2.0 + checksum: 2d2391147c83b402786eeab95d23ea4e24ca8608e0e70a2823bfd4f2a248be13a8cc31acfd55a0109e051131e4f0c17d7ada8d999ce70ff2e342ab0110f5da59 + languageName: node + linkType: hard + "node-html-parser@npm:^6.1.1": version: 6.1.5 resolution: "node-html-parser@npm:6.1.5" @@ -33852,6 +33662,41 @@ __metadata: languageName: node linkType: hard +"node-stdlib-browser@npm:^1.2.0": + version: 1.2.0 + resolution: "node-stdlib-browser@npm:1.2.0" + dependencies: + assert: ^2.0.0 + browser-resolve: ^2.0.0 + browserify-zlib: ^0.2.0 + buffer: ^5.7.1 + console-browserify: ^1.1.0 + constants-browserify: ^1.0.0 + create-require: ^1.1.1 + crypto-browserify: ^3.11.0 + domain-browser: ^4.22.0 + events: ^3.0.0 + https-browserify: ^1.0.0 + isomorphic-timers-promises: ^1.0.1 + os-browserify: ^0.3.0 + path-browserify: ^1.0.1 + pkg-dir: ^5.0.0 + process: ^0.11.10 + punycode: ^1.4.1 + querystring-es3: ^0.2.1 + readable-stream: ^3.6.0 + stream-browserify: ^3.0.0 + stream-http: ^3.2.0 + string_decoder: ^1.0.0 + timers-browserify: ^2.0.4 + tty-browserify: 0.0.1 + url: ^0.11.0 + util: ^0.12.4 + vm-browserify: ^1.0.1 + checksum: fe491f0839319fd9bb95964c6f7da81fc7fde4c3ac9062aa367f19bc5a6060d0d9e423d3de4196cb51f8259d6aaf6cf380048c48a86eb3721c6223dd0dcc5bfd + languageName: node + linkType: hard + "nodemon@npm:^3.0.1": version: 3.0.1 resolution: "nodemon@npm:3.0.1" @@ -34095,7 +33940,7 @@ __metadata: languageName: node linkType: hard -"nth-check@npm:^2.0.0, nth-check@npm:^2.0.1": +"nth-check@npm:^2.0.1": version: 2.1.1 resolution: "nth-check@npm:2.1.1" dependencies: @@ -35208,6 +35053,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^0.2.0": + version: 0.2.0 + resolution: "pathe@npm:0.2.0" + checksum: 9a8149ce152088f30d15b0b03a7c128ba21f16b4dc1f3f90fe38eee9f6d0f1d6da8e4e47bd2a4f9e14aaac7c30ed01cfc86216479011de2bdc598b65e6f19f41 + languageName: node + linkType: hard + "pause@npm:0.0.1": version: 0.0.1 resolution: "pause@npm:0.0.1" @@ -35500,6 +35352,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^5.0.0": + version: 5.0.0 + resolution: "pkg-dir@npm:5.0.0" + dependencies: + find-up: ^5.0.0 + checksum: b167bb8dac7bbf22b1d5e30ec223e6b064b84b63010c9d49384619a36734caf95ed23ad23d4f9bd975e8e8082b60a83395f43a89bb192df53a7c25a38ecb57d9 + languageName: node + linkType: hard + "pkg-up@npm:^3.1.0": version: 3.1.0 resolution: "pkg-up@npm:3.1.0" @@ -35983,7 +35844,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.1.0, postcss@npm:^8.4.21": +"postcss@npm:^8.1.0, postcss@npm:^8.4.21, postcss@npm:^8.4.27": version: 8.4.31 resolution: "postcss@npm:8.4.31" dependencies: @@ -36477,7 +36338,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^1.2.4, punycode@npm:^1.3.2": +"punycode@npm:^1.2.4, punycode@npm:^1.3.2, punycode@npm:^1.4.1": version: 1.4.1 resolution: "punycode@npm:1.4.1" checksum: fa6e698cb53db45e4628559e557ddaf554103d2a96a1d62892c8f4032cd3bc8871796cae9eabc1bc700e2b6677611521ce5bb1d9a27700086039965d0cf34518 @@ -36558,7 +36419,7 @@ __metadata: languageName: node linkType: hard -"querystring-es3@npm:^0.2.0": +"querystring-es3@npm:^0.2.0, querystring-es3@npm:^0.2.1": version: 0.2.1 resolution: "querystring-es3@npm:0.2.1" checksum: 691e8d6b8b157e7cd49ae8e83fcf86de39ab3ba948c25abaa94fba84c0986c641aa2f597770848c64abce290ed17a39c9df6df737dfa7e87c3b63acc7d225d61 @@ -36870,16 +36731,15 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^17.0.2": - version: 17.0.2 - resolution: "react-dom@npm:17.0.2" +"react-dom@npm:^18.0.2": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - scheduler: ^0.20.2 + scheduler: ^0.23.0 peerDependencies: - react: 17.0.2 - checksum: 1c1eaa3bca7c7228d24b70932e3d7c99e70d1d04e13bb0843bbf321582bc25d7961d6b8a6978a58a598af2af496d1cedcfb1bf65f6b0960a0a8161cb8dab743c + react: ^18.2.0 + checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc languageName: node linkType: hard @@ -37041,7 +36901,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.10.2, react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.3, react-is@npm:^16.7.0, react-is@npm:^16.8.0, react-is@npm:^16.8.6, react-is@npm:^16.9.0": +"react-is@npm:^16.10.2, react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.3, react-is@npm:^16.7.0, react-is@npm:^16.8.0, react-is@npm:^16.8.6": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -37445,13 +37305,12 @@ __metadata: languageName: node linkType: hard -"react@npm:^17.0.2": - version: 17.0.2 - resolution: "react@npm:17.0.2" +"react@npm:^18.0.2": + version: 18.2.0 + resolution: "react@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: b254cc17ce3011788330f7bbf383ab653c6848902d7936a87b09d835d091e3f295f7e9dd1597c6daac5dc80f90e778c8230218ba8ad599f74adcc11e33b9d61b + checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b languageName: node linkType: hard @@ -38107,16 +37966,16 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:~1.22.1": - version: 1.22.4 - resolution: "resolve@npm:1.22.4" +"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.1, resolve@npm:~1.22.1": + version: 1.22.6 + resolution: "resolve@npm:1.22.6" dependencies: is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124 + checksum: d13bf66d4e2ee30d291491f16f2fa44edd4e0cefb85d53249dd6f93e70b2b8c20ec62f01b18662e3cd40e50a7528f18c4087a99490048992a3bb954cf3201a5b languageName: node linkType: hard @@ -38143,16 +38002,16 @@ __metadata: languageName: node linkType: hard -"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.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@~1.22.1#~builtin": - version: 1.22.4 - resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=07638b" +"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.1#~builtin, resolve@patch:resolve@~1.22.1#~builtin": + version: 1.22.6 + resolution: "resolve@patch:resolve@npm%3A1.22.6#~builtin::version=1.22.6&hash=07638b" dependencies: is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc + checksum: 9d3b3c67aefd12cecbe5f10ca4d1f51ea190891096497c43f301b086883b426466918c3a64f1bbf1788fabb52b579d58809614006c5d0b49186702b3b8fb746a languageName: node linkType: hard @@ -38459,6 +38318,20 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^3.27.1": + version: 3.29.4 + resolution: "rollup@npm:3.29.4" + dependencies: + fsevents: ~2.3.2 + dependenciesMeta: + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 8bb20a39c8d91130825159c3823eccf4dc2295c9a0a5c4ed851a5bf2167dbf24d9a29f23461a54c955e5506395e6cc188eafc8ab0e20399d7489fb33793b184e + languageName: node + linkType: hard + "root@workspace:.": version: 0.0.0-use.local resolution: "root@workspace:." @@ -38708,13 +38581,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.20.2": - version: 0.20.2 - resolution: "scheduler@npm:0.20.2" +"scheduler@npm:^0.23.0": + version: 0.23.0 + resolution: "scheduler@npm:0.23.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: c4b35cf967c8f0d3e65753252d0f260271f81a81e427241295c5a7b783abf4ea9e905f22f815ab66676f5313be0a25f47be582254db8f9241b259213e999b8fc + checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a languageName: node linkType: hard @@ -39784,7 +39656,7 @@ __metadata: languageName: node linkType: hard -"stream-browserify@npm:3.0.0": +"stream-browserify@npm:3.0.0, stream-browserify@npm:^3.0.0": version: 3.0.0 resolution: "stream-browserify@npm:3.0.0" dependencies: @@ -39833,6 +39705,18 @@ __metadata: languageName: node linkType: hard +"stream-http@npm:^3.2.0": + version: 3.2.0 + resolution: "stream-http@npm:3.2.0" + dependencies: + builtin-status-codes: ^3.0.0 + inherits: ^2.0.4 + readable-stream: ^3.6.0 + xtend: ^4.0.2 + checksum: c9b78453aeb0c84fcc59555518ac62bacab9fa98e323e7b7666e5f9f58af8f3155e34481078509b02929bd1268427f664d186604cdccee95abc446099b339f83 + languageName: node + linkType: hard + "stream-shift@npm:^1.0.0": version: 1.0.1 resolution: "stream-shift@npm:1.0.1" @@ -40563,14 +40447,14 @@ __metadata: "@material-ui/icons": ^4.9.1 "@testing-library/dom": ^9.0.0 "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^12.1.3 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 "@types/react": "*" "@types/react-dom": "*" cross-env: ^7.0.0 history: ^5.0.0 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.2 + react-dom: ^18.0.2 react-router-dom: ^6.3.0 react-use: ^17.2.4 languageName: unknown @@ -41186,6 +41070,23 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^3.14.0": + version: 3.14.0 + resolution: "tsx@npm:3.14.0" + dependencies: + esbuild: ~0.18.20 + fsevents: ~2.3.3 + get-tsconfig: ^4.7.2 + source-map-support: ^0.5.21 + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: afcef5d9b90b5800cf1ffb749e943f63042d78a4c0d9eef6e13e43f4ecab465d45e2c9812a2c515cbdc2ee913ff1cd01bf5c606a48013dd3ce2214a631b45557 + languageName: node + linkType: hard + "tty-browserify@npm:0.0.0": version: 0.0.0 resolution: "tty-browserify@npm:0.0.0" @@ -41193,6 +41094,13 @@ __metadata: languageName: node linkType: hard +"tty-browserify@npm:0.0.1": + version: 0.0.1 + resolution: "tty-browserify@npm:0.0.1" + checksum: 93b745d43fa5a7d2b948fa23be8d313576d1d884b48acd957c07710bac1c0d8ac34c0556ad4c57c73d36e11741763ef66b3fb4fb97b06b7e4d525315a3cd45f5 + languageName: node + linkType: hard + "tty-table@npm:^4.1.5": version: 4.1.6 resolution: "tty-table@npm:4.1.6" @@ -41544,12 +41452,19 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~5.25.1": + version: 5.25.3 + resolution: "undici-types@npm:5.25.3" + checksum: ec9d2cc36520cbd9fbe3b3b6c682a87fe5be214699e1f57d1e3d9a2cb5be422e62735f06e0067dc325fd3dd7404c697e4d479f9147dc8a804e049e29f357f2ff + languageName: node + linkType: hard + "undici@npm:^5.12.0, undici@npm:^5.24.0, undici@npm:^5.8.0": - version: 5.25.4 - resolution: "undici@npm:5.25.4" + version: 5.26.3 + resolution: "undici@npm:5.26.3" dependencies: "@fastify/busboy": ^2.0.0 - checksum: 654da161687de893127a685be61a19cb5bae42f4595c316ebf633929d871ac3bcd33edcb74156cea90655dfcd100bfe9b53a4f4749d52fc6ad2232f49a6ca8ab + checksum: aaa9aadb712cf80e1a9cea2377e4842670105e00abbc184a21770ea5a8b77e4e2eadc200eac62442e74a1cd3b16a840c6f73b112b9e886bd3c1a125eb22e4f21 languageName: node linkType: hard @@ -41980,7 +41895,7 @@ __metadata: languageName: node linkType: hard -"util@npm:^0.12.0, util@npm:^0.12.3": +"util@npm:^0.12.0, util@npm:^0.12.3, util@npm:^0.12.4": version: 0.12.5 resolution: "util@npm:0.12.5" dependencies: @@ -42258,6 +42173,82 @@ __metadata: languageName: node linkType: hard +"vite-plugin-html@npm:^3.2.0": + version: 3.2.0 + resolution: "vite-plugin-html@npm:3.2.0" + dependencies: + "@rollup/pluginutils": ^4.2.0 + colorette: ^2.0.16 + connect-history-api-fallback: ^1.6.0 + consola: ^2.15.3 + dotenv: ^16.0.0 + dotenv-expand: ^8.0.2 + ejs: ^3.1.6 + fast-glob: ^3.2.11 + fs-extra: ^10.0.1 + html-minifier-terser: ^6.1.0 + node-html-parser: ^5.3.3 + pathe: ^0.2.0 + peerDependencies: + vite: ">=2.0.0" + checksum: f5222247b65da1c36215f0b2f509fd3975a7426b8d44546beb49f3ba51ee87b3a6b6e6afc9e7567a0d8bd1016631f2db3f934808f62a7c8f7f83fa83d8561d2d + languageName: node + linkType: hard + +"vite-plugin-node-polyfills@npm:^0.14.1": + version: 0.14.1 + resolution: "vite-plugin-node-polyfills@npm:0.14.1" + dependencies: + "@rollup/plugin-inject": ^5.0.3 + buffer-polyfill: "npm:buffer@^6.0.3" + node-stdlib-browser: ^1.2.0 + process: ^0.11.10 + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 + checksum: 1dd6e4ff500a69ff78c8d7d967e74790b704e3ccb117fc4f8841f2e5d0e339422a15d9c6c0607d1fed4df5a7a77c56d245769b22572d4e905771b37ff8801915 + languageName: node + linkType: hard + +"vite@npm:^4.4.9": + version: 4.4.11 + resolution: "vite@npm:4.4.11" + dependencies: + esbuild: ^0.18.10 + fsevents: ~2.3.2 + postcss: ^8.4.27 + rollup: ^3.27.1 + peerDependencies: + "@types/node": ">= 14" + less: "*" + lightningcss: ^1.21.0 + sass: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: c22145c8385343a629cd546054b9da6eee60327540102bdfd1ad897fd2e78e0763ce6a18a9d84fdefde9da8fd2427d3bec9eb2697b47cf4068c7b4b52f7e3e6a + languageName: node + linkType: hard + "viz.js@npm:2.1.2": version: 2.1.2 resolution: "viz.js@npm:2.1.2" @@ -43054,7 +43045,7 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:~4.0.1": +"xtend@npm:^4.0.0, xtend@npm:^4.0.2, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a