diff --git a/.changeset/afraid-items-drum.md b/.changeset/afraid-items-drum.md deleted file mode 100644 index 94ddd608cd..0000000000 --- a/.changeset/afraid-items-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli-node': patch ---- - -Updated to use new utilities from `@backstage/cli-common`. diff --git a/.changeset/alert-api-replay.md b/.changeset/alert-api-replay.md deleted file mode 100644 index b41ec091a3..0000000000 --- a/.changeset/alert-api-replay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Added replay functionality to `AlertApiForwarder` to buffer and replay recent alerts to new subscribers, preventing missed alerts that were posted before subscription. diff --git a/.changeset/all-socks-taste.md b/.changeset/all-socks-taste.md deleted file mode 100644 index 377782c2f9..0000000000 --- a/.changeset/all-socks-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': minor ---- - -In the `gitlabRepoPush` action, add 'auto' possibility for `commitAction` input. diff --git a/.changeset/angry-views-win.md b/.changeset/angry-views-win.md deleted file mode 100644 index 9d406280a7..0000000000 --- a/.changeset/angry-views-win.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-kafka': minor ---- - -Added support for multiple named instances in `kafkaConsumingEventPublisher` configuration. The previous single configuration format is still supported for backward compatibility. diff --git a/.changeset/better-ghosts-tell.md b/.changeset/better-ghosts-tell.md new file mode 100644 index 0000000000..af66b4fc6e --- /dev/null +++ b/.changeset/better-ghosts-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Fixes app background color on dark mode. diff --git a/.changeset/blue-signs-fry.md b/.changeset/blue-signs-fry.md deleted file mode 100644 index 26861e3b7e..0000000000 --- a/.changeset/blue-signs-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-mcp-actions-backend': patch ---- - -Added `@cfworker/json-schema` as a dependency to this package part of the `@modelcontextprotocol/sdk` bump as it's required in the types diff --git a/.changeset/bright-lions-unite.md b/.changeset/bright-lions-unite.md deleted file mode 100644 index e9bef02e10..0000000000 --- a/.changeset/bright-lions-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Provide `--no-node-snapshot` by default when running the `package start` or `package test`. You can disable this behavior by providing `NODE_OPTIONS='--node-snapshot'`. diff --git a/.changeset/bumpy-pens-swim.md b/.changeset/bumpy-pens-swim.md deleted file mode 100644 index 462045e462..0000000000 --- a/.changeset/bumpy-pens-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Added support for using a GitHub App installation to generate tokens for public repository access when the `publicAccess` option is enabled. When all other authentication methods fail (e.g., the app is not installed in that organization), the provider will now use an available installation to generate a token that can be used to access public repositories as read only. diff --git a/.changeset/bumpy-planets-go.md b/.changeset/bumpy-planets-go.md deleted file mode 100644 index 5477711c1a..0000000000 --- a/.changeset/bumpy-planets-go.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed Checkbox indicator showing checkmark color when unchecked. - -Affected components: Checkbox diff --git a/.changeset/chatty-sides-wear.md b/.changeset/chatty-sides-wear.md deleted file mode 100644 index 33937a1286..0000000000 --- a/.changeset/chatty-sides-wear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-graph': patch ---- - -Fixed zoom out description (replace `&` with &) diff --git a/.changeset/chilly-bikes-rule.md b/.changeset/chilly-bikes-rule.md deleted file mode 100644 index 894999cf56..0000000000 --- a/.changeset/chilly-bikes-rule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@techdocs/cli': patch ---- - -Updated to use new utilities from `@backstage/cli-common`. diff --git a/.changeset/chilly-hotels-walk.md b/.changeset/chilly-hotels-walk.md deleted file mode 100644 index e9b1ff66ba..0000000000 --- a/.changeset/chilly-hotels-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-node': minor ---- - -Improving method that search tokenizer breaks apart entity names diff --git a/.changeset/chilly-waves-relate.md b/.changeset/chilly-waves-relate.md deleted file mode 100644 index 2e78f9245e..0000000000 --- a/.changeset/chilly-waves-relate.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Switched the default module resolution to `bundler` and the `module` setting to `ES2020`. - -You may need to bump some dependencies as part of this change and fix imports in code. The most common source of this is that type checking will now consider the `exports` field in `package.json` when resolving imports. This in turn can break older versions of packages that had incompatible `exports` fields. Generally these issues will have already been fixed in the upstream packages. - -You might be tempted to use `--skipLibCheck` to hide issues due to this change, but it will weaken the type safety of your project. If you run into a large number of issues and want to keep the old behavior, you can reset the `moduleResolution` and `module` settings your own `tsconfig.json` file to `node` and `ESNext` respectively. But keep in mind that the `node` option will be removed in future versions of TypeScript. - -A future version of Backstage will make these new settings mandatory, as we move to rely on the `exports` field for type resolution in packages, rather than the `typesVersions` field. diff --git a/.changeset/clean-toys-reply.md b/.changeset/clean-toys-reply.md deleted file mode 100644 index 66002903ab..0000000000 --- a/.changeset/clean-toys-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -remove leading dot in auth cookie cleanup call diff --git a/.changeset/early-doors-visit.md b/.changeset/clever-streets-roll.md similarity index 50% rename from .changeset/early-doors-visit.md rename to .changeset/clever-streets-roll.md index 41cd9e92b8..7efa961533 100644 --- a/.changeset/early-doors-visit.md +++ b/.changeset/clever-streets-roll.md @@ -2,4 +2,4 @@ '@backstage/backend-defaults': patch --- -Allow configuration of the `referrerPolicy` +Implementing `readTree` for `GoogleGcsReader` diff --git a/.changeset/cold-dogs-study.md b/.changeset/cold-dogs-study.md new file mode 100644 index 0000000000..a27309fc15 --- /dev/null +++ b/.changeset/cold-dogs-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-backend': patch +--- + +Some AWS `publisher` config options such as `region`, `endpoint`, `accountId` are now marked as `@visibility backend` instead of `secret`. diff --git a/.changeset/common-coins-stare.md b/.changeset/common-coins-stare.md deleted file mode 100644 index 0bd0078cf9..0000000000 --- a/.changeset/common-coins-stare.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed `ButtonIcon` incorrectly applying `className` to inner elements instead of only the root element. - -Affected components: ButtonIcon diff --git a/.changeset/crazy-hornets-spend.md b/.changeset/crazy-hornets-spend.md deleted file mode 100644 index 4db99675ac..0000000000 --- a/.changeset/crazy-hornets-spend.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-search': patch -'@backstage/plugin-app': patch -'@backstage/plugin-org': patch ---- - -Minor extension type updates after frontend API bump diff --git a/.changeset/create-app-1764689798.md b/.changeset/create-app-1766498726.md similarity index 100% rename from .changeset/create-app-1764689798.md rename to .changeset/create-app-1766498726.md diff --git a/.changeset/create-app-1767101113.md b/.changeset/create-app-1767101113.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1767101113.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/curvy-things-call.md b/.changeset/curvy-things-call.md deleted file mode 100644 index d64f1a14fa..0000000000 --- a/.changeset/curvy-things-call.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-email': patch ---- - -SES config for the notification email processor now supports utilizing an ARN for the SES identity when sending an email after the SES SDK V2 update. - -The `sesConfig.fromArn` will set the `fromEmailAddressIdentityArn` option for the SES `SendEmailCommand`. The `sesConfig.sourceArn` field is removed since no equivalent option is available in the send email command options. Setting `sesConfig.sourceArn` will have no effect and log a warning. Example changes: - -```diff -notifications: - processors: - email: - transportConfig: - transport: "ses" - region: "us-west-2" - sender: "sender@mycompany.com" - replyTo: "no-reply@mycompany.com" - sesConfig: -- sourceArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" - fromArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" -``` diff --git a/.changeset/dependabot-0d8f6de.md b/.changeset/dependabot-0d8f6de.md deleted file mode 100644 index b0a3955f2d..0000000000 --- a/.changeset/dependabot-0d8f6de.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/backend-dynamic-feature-service': patch -'@backstage/backend-openapi-utils': patch -'@backstage/backend-test-utils': patch -'@backstage/cli': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-app-node': patch -'@backstage/plugin-auth-backend-module-atlassian-provider': patch -'@backstage/plugin-auth-backend-module-auth0-provider': patch -'@backstage/plugin-auth-backend-module-aws-alb-provider': patch -'@backstage/plugin-auth-backend-module-azure-easyauth-provider': patch -'@backstage/plugin-auth-backend-module-bitbucket-provider': patch -'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch -'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch -'@backstage/plugin-auth-backend-module-gitlab-provider': patch -'@backstage/plugin-auth-backend-module-guest-provider': patch -'@backstage/plugin-auth-backend-module-microsoft-provider': patch -'@backstage/plugin-auth-backend-module-oidc-provider': patch -'@backstage/plugin-auth-backend-module-okta-provider': patch -'@backstage/plugin-auth-backend-module-onelogin-provider': patch -'@backstage/plugin-auth-backend-module-openshift-provider': patch -'@backstage/plugin-auth-backend-module-pinniped-provider': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-devtools-backend': patch -'@backstage/plugin-events-backend': patch -'@backstage/plugin-events-node': patch -'@backstage/plugin-gateway-backend': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-mcp-actions-backend': patch -'@backstage/plugin-notifications-backend': patch -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-node': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-search-backend': patch -'@backstage/plugin-signals-backend': patch -'@backstage/plugin-signals-node': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs-node': patch -'@backstage/plugin-user-settings-backend': patch ---- - -chore(deps): bump `express` from 4.21.2 to 4.22.0 diff --git a/.changeset/dependabot-5e654fe.md b/.changeset/dependabot-5e654fe.md deleted file mode 100644 index 93563cffc6..0000000000 --- a/.changeset/dependabot-5e654fe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -build(deps): bump `node-forge` from 1.3.1 to 1.3.2 diff --git a/.changeset/dependabot-aed8e01.md b/.changeset/dependabot-aed8e01.md new file mode 100644 index 0000000000..8606ea8b91 --- /dev/null +++ b/.changeset/dependabot-aed8e01.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +build(deps-dev): bump `storybook` from 10.1.9 to 10.1.10 diff --git a/.changeset/early-carpets-rush.md b/.changeset/early-carpets-rush.md deleted file mode 100644 index dbdc5410c9..0000000000 --- a/.changeset/early-carpets-rush.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add missing peer/dev dependencies to the frontend plugin template. - -`react-dom` was not declared as a peer dependency, causing module resolution -errors when generating plugins outside a Backstage monorepo. This adds -`react-dom` to `peerDependencies` (for consuming apps) and `devDependencies` -(for local development). `react-router-dom` is also added to `peerDependencies` (for consuming apps) and `devDependencies` -to support routing during plugin development. - -Fixes: - -- Module not found: Can't resolve 'react-dom' -- Module not found: Can't resolve 'react-router-dom' diff --git a/.changeset/error-boundary-api.md b/.changeset/error-boundary-api.md deleted file mode 100644 index 74803f1dc0..0000000000 --- a/.changeset/error-boundary-api.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Added a new `errorPresentation` prop to `ExtensionBoundary` to control how errors are presented to the user. The default is `'error-display'`, which is the current behavior of showing the error in the `ErrorDisplay` component. The new option is `'error-api'`, posts errors to the `ErrorApi` and does not allow retries. - -The `AppRootElementBlueprint` now wraps its element in an `ErrorBoundary` using the new `'error-api'` presentation mode. diff --git a/.changeset/every-bears-add.md b/.changeset/every-bears-add.md new file mode 100644 index 0000000000..83c6d6b06d --- /dev/null +++ b/.changeset/every-bears-add.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Bump `@swc/core` to support `ES2023` and `ES2024` diff --git a/.changeset/fair-lines-warn.md b/.changeset/fair-lines-warn.md deleted file mode 100644 index ffd387efbf..0000000000 --- a/.changeset/fair-lines-warn.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-github-provider': minor -'@backstage/plugin-catalog-backend-module-github': minor ---- - -Added the `github.com/user-id` annotation to store GitHub's user ID (immutable) in user entities. Also includes addition of the `userIdMatchingUserEntityAnnotation` sign-in resolver that matches users by the new ID. diff --git a/.changeset/famous-jars-lose.md b/.changeset/famous-jars-lose.md deleted file mode 100644 index 4070701e4e..0000000000 --- a/.changeset/famous-jars-lose.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed Table Row component to correctly handle cases where no `href` is provided, preventing unnecessary router provider wrapping and fixing the cursor incorrectly showing as a pointer despite the element not being a link. - -Affected components: Row diff --git a/.changeset/fifty-coats-feel.md b/.changeset/fifty-coats-feel.md deleted file mode 100644 index 0e3425a505..0000000000 --- a/.changeset/fifty-coats-feel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -Enabled a pod terminal at GKE diff --git a/.changeset/fifty-lights-marry.md b/.changeset/fifty-lights-marry.md deleted file mode 100644 index 423ef89721..0000000000 --- a/.changeset/fifty-lights-marry.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-kubernetes-backend': patch -'@backstage/backend-defaults': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/integration': patch ---- - -Updated luxon types diff --git a/.changeset/fine-eagles-sleep.md b/.changeset/fine-eagles-sleep.md deleted file mode 100644 index 0af6d0dfc0..0000000000 --- a/.changeset/fine-eagles-sleep.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-app-api': minor ---- - -Introduced backend startup result tracking and error handling. The `Backend.start()` method now returns a `BackendStartupResult` with detailed success/failure status and timing information for all plugins and modules. When startup fails, a `BackendStartupError` is thrown that includes the complete startup results, making it easier to diagnose which plugins or modules failed. - -This also improves the default error message when backend startup fails, and of course makes it possible to craft your own custom error reporting based on the startup results. diff --git a/.changeset/flat-pillows-rush.md b/.changeset/flat-pillows-rush.md deleted file mode 100644 index bb64013f62..0000000000 --- a/.changeset/flat-pillows-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Fixed a versioning conflict that could result in a `.withContext` is not a function error. diff --git a/.changeset/floppy-bobcats-serve.md b/.changeset/floppy-bobcats-serve.md deleted file mode 100644 index d698e1482c..0000000000 --- a/.changeset/floppy-bobcats-serve.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed bug in the `LogViewer` component where shift + click always opened a new window instead of just changing the selection. - -In addition, improved the `LogViewer` component by a few usability enhancements: - -- Added support for multiple selections using cmd/ctrl + click -- Improved the generated hash that is added to the URL to also support ranges & multiple selections -- Added an hover effect & info tooltip to the "Copy to clipboard" button to indicate its functionality -- Added some color and a separator to the line numbers to improve readability diff --git a/.changeset/four-peaches-train.md b/.changeset/four-peaches-train.md deleted file mode 100644 index 81b35589c1..0000000000 --- a/.changeset/four-peaches-train.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/backend-plugin-api': patch ---- - -**BREAKING ALPHA**: The old `instanceMetadataService` has been removed from alpha. Please switch over to using the stable `coreServices.rootInstanceMetadata` and related types instead, available from `@backstage/backend-plugin-api`. diff --git a/.changeset/fruity-rivers-arrive.md b/.changeset/fruity-rivers-arrive.md deleted file mode 100644 index a816946bcc..0000000000 --- a/.changeset/fruity-rivers-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Add `defaultEnvironment` config to scaffolder to enable more flexible and custom templates. Now it's possible enable access to default parameters and secrets in templates, improving security and reducing complexity. diff --git a/.changeset/fruity-words-melt.md b/.changeset/fruity-words-melt.md deleted file mode 100644 index 0f02acee2b..0000000000 --- a/.changeset/fruity-words-melt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-module-addons-contrib': patch ---- - -Updated tests to match test-utils change diff --git a/.changeset/full-needles-drive.md b/.changeset/full-needles-drive.md deleted file mode 100644 index d0d7a59551..0000000000 --- a/.changeset/full-needles-drive.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': minor -'@backstage/plugin-kubernetes-node': minor ---- - -Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider diff --git a/.changeset/funny-hornets-peel.md b/.changeset/funny-hornets-peel.md deleted file mode 100644 index 2af6702295..0000000000 --- a/.changeset/funny-hornets-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Updated `isolated-vm` to `6.0.1` diff --git a/.changeset/funny-papayas-rest.md b/.changeset/funny-papayas-rest.md deleted file mode 100644 index 95f52966ec..0000000000 --- a/.changeset/funny-papayas-rest.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/repo-tools': patch -'@backstage/codemods': patch ---- - -Updated to use new utilities from `@backstage/cli-common`. diff --git a/.changeset/fuzzy-phones-own.md b/.changeset/fuzzy-phones-own.md deleted file mode 100644 index 61725d1f1d..0000000000 --- a/.changeset/fuzzy-phones-own.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github-org': patch -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Introduce new configuration option to exclude suspended users from GitHub Enterprise instances. - -When it’s set to true, suspended users won’t be returned when querying the organization users for GitHub Enterprise instances. -Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail. diff --git a/.changeset/fuzzy-rivers-travel.md b/.changeset/fuzzy-rivers-travel.md deleted file mode 100644 index fa2c08a671..0000000000 --- a/.changeset/fuzzy-rivers-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Made the return type of `.withOverrides` to be simplified. diff --git a/.changeset/fuzzy-trees-live.md b/.changeset/fuzzy-trees-live.md deleted file mode 100644 index 84cec56fab..0000000000 --- a/.changeset/fuzzy-trees-live.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -long words like urls now breaks to new line on warning panels instead of overflowing the container diff --git a/.changeset/gentle-results-lie.md b/.changeset/gentle-results-lie.md deleted file mode 100644 index 0c53407db3..0000000000 --- a/.changeset/gentle-results-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fixed schema type for additionalAllowedURIProtocols diff --git a/.changeset/gentle-singers-love.md b/.changeset/gentle-singers-love.md deleted file mode 100644 index ed4372ee06..0000000000 --- a/.changeset/gentle-singers-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app': patch ---- - -Support to set `defaultLanguage` and `availableLanguages` for the app language API in the new frontend system diff --git a/.changeset/gentle-trains-juggle.md b/.changeset/gentle-trains-juggle.md deleted file mode 100644 index e8b1397180..0000000000 --- a/.changeset/gentle-trains-juggle.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch ---- - -Replace `@aws-sdk/signature-v4` with `@smithy/signature-v4`, -as stated in the [package documentation](https://www.npmjs.com/package/@aws-sdk/signature-v4?activeTab=readme) diff --git a/.changeset/great-files-shave.md b/.changeset/great-files-shave.md deleted file mode 100644 index 271a8e8955..0000000000 --- a/.changeset/great-files-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Fixed an issue where `EntityOwnerPicker` failed to filter options when the input text contained uppercase characters. diff --git a/.changeset/green-lizards-boil.md b/.changeset/green-lizards-boil.md deleted file mode 100644 index 640699e001..0000000000 --- a/.changeset/green-lizards-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Use a versioned context for `useEntityList`, to better work with mixed `@backstage/plugin-catalog-react` versions. diff --git a/.changeset/happy-bottles-invite.md b/.changeset/happy-bottles-invite.md deleted file mode 100644 index 07fc222cad..0000000000 --- a/.changeset/happy-bottles-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': minor ---- - -Move `better-sqlite3` from dependencies to peer dependencies diff --git a/.changeset/happy-streets-dress.md b/.changeset/happy-streets-dress.md deleted file mode 100644 index 46f4d798ed..0000000000 --- a/.changeset/happy-streets-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated engines to support Node 22 or 24 diff --git a/.changeset/honest-bears-itch.md b/.changeset/honest-bears-itch.md deleted file mode 100644 index 4c0cd5f47e..0000000000 --- a/.changeset/honest-bears-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Switched `textextensions` dependency for `text-extensions`. diff --git a/.changeset/hot-colts-float.md b/.changeset/hot-colts-float.md new file mode 100644 index 0000000000..093dcfb12a --- /dev/null +++ b/.changeset/hot-colts-float.md @@ -0,0 +1,7 @@ +--- +'@backstage/ui': patch +--- + +Fixed SearchField `startCollapsed` prop not working correctly in Backstage UI. The field now properly starts in a collapsed state, expands when clicked and focused, and collapses back when unfocused with no input. Also fixed CSS logic to work correctly in all layout contexts (flex row, flex column, and regular containers). + +Affected components: SearchField diff --git a/.changeset/hungry-mugs-fall.md b/.changeset/hungry-mugs-fall.md new file mode 100644 index 0000000000..4332d92cc3 --- /dev/null +++ b/.changeset/hungry-mugs-fall.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Implementing `ScmIntegration` for `GoogleGcs` diff --git a/.changeset/kind-hoops-double.md b/.changeset/kind-hoops-double.md deleted file mode 100644 index fd2f9f023f..0000000000 --- a/.changeset/kind-hoops-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Made the github urls case insensitive. diff --git a/.changeset/large-planes-punch.md b/.changeset/large-planes-punch.md deleted file mode 100644 index 3216653eb9..0000000000 --- a/.changeset/large-planes-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Fix for `jose` types diff --git a/.changeset/legal-cloths-spend.md b/.changeset/legal-cloths-spend.md deleted file mode 100644 index 50d965307a..0000000000 --- a/.changeset/legal-cloths-spend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-mcp-actions-backend': patch ---- - -Clarify error handling in readme and update handleError.ts to include all backstage/errors diff --git a/.changeset/legal-otters-punch.md b/.changeset/legal-otters-punch.md deleted file mode 100644 index 2003492e29..0000000000 --- a/.changeset/legal-otters-punch.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch -'@backstage/plugin-kubernetes-common': patch -'@backstage/plugin-kubernetes-react': patch ---- - -Add Kubernetes Plugin Secrets Accordion with masked secret datas diff --git a/.changeset/lemon-corners-hug.md b/.changeset/lemon-corners-hug.md deleted file mode 100644 index b41c09c928..0000000000 --- a/.changeset/lemon-corners-hug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-node': patch ---- - -There was an issue in the uploading of large size files to the AWS S3. We have modified the logic by adding retry along with multipart uploading functionality. diff --git a/.changeset/loose-pets-slide.md b/.changeset/loose-pets-slide.md deleted file mode 100644 index b8ec201f1c..0000000000 --- a/.changeset/loose-pets-slide.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Updates OpenAPI generator templates to preserve original property names (like 'group-name', 'user-id') from OpenAPI specs when propertyNaming=original is specified. Previously, these were always converted to camelCase regardless of the propertyNaming setting. - -- Updates modelGeneric.mustache templates in both client and server generators -- Updates modelTaggedUnion.mustache templates in both client and server generators -- Uses {{baseName}} when available, falls back to {{name}} for backward compatibility -- Maintains backward compatibility - no changes when propertyNaming=original is not used diff --git a/.changeset/loud-yaks-watch.md b/.changeset/loud-yaks-watch.md deleted file mode 100644 index b7ad65b9eb..0000000000 --- a/.changeset/loud-yaks-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Bump `@microsoft/api-documenter` and `@microsoft/api-extractor` to latest versions. diff --git a/.changeset/lucky-days-hug.md b/.changeset/lucky-days-hug.md deleted file mode 100644 index 4d76caa098..0000000000 --- a/.changeset/lucky-days-hug.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-kubernetes': patch ---- - -add missing i18n support for kubernetes and kubernetes-react diff --git a/.changeset/major-mangos-shine.md b/.changeset/major-mangos-shine.md new file mode 100644 index 0000000000..f42fcf5d0e --- /dev/null +++ b/.changeset/major-mangos-shine.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-openapi-utils': patch +--- + +Internal update to use native feature from our request validation library for handling base path determination. diff --git a/.changeset/many-planes-join.md b/.changeset/many-planes-join.md deleted file mode 100644 index 66107cd370..0000000000 --- a/.changeset/many-planes-join.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/test-utils': patch ---- - -Internal update of translation imports. diff --git a/.changeset/metal-boxes-laugh.md b/.changeset/metal-boxes-laugh.md deleted file mode 100644 index 9a5ab24e0e..0000000000 --- a/.changeset/metal-boxes-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -The `useApp` and `useRouteRef` functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs. diff --git a/.changeset/metal-humans-lose.md b/.changeset/metal-humans-lose.md deleted file mode 100644 index f96d33a779..0000000000 --- a/.changeset/metal-humans-lose.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@backstage/plugin-catalog-unprocessed-entities': patch -'@backstage/plugin-app-visualizer': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-notifications': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-search': patch -'@backstage/plugin-home': patch -'@backstage/plugin-app': patch -'@backstage/plugin-org': patch ---- - -Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. diff --git a/.changeset/modern-taxes-start.md b/.changeset/modern-taxes-start.md deleted file mode 100644 index 9fd7645570..0000000000 --- a/.changeset/modern-taxes-start.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli-common': patch ---- - -Added new `run`, `runOutput`, and `runCheck` utilities to help run child processes in a safe and portable way. diff --git a/.changeset/neat-pens-clean.md b/.changeset/neat-pens-clean.md deleted file mode 100644 index aff67a2a10..0000000000 --- a/.changeset/neat-pens-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Properly create workspace in OS temporary directory for `generate-patch` command diff --git a/.changeset/nice-humans-cry.md b/.changeset/nice-humans-cry.md deleted file mode 100644 index c6119702b4..0000000000 --- a/.changeset/nice-humans-cry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch -'@backstage/backend-defaults': patch ---- - -Internal change to support new versions of the `logform` library diff --git a/.changeset/nice-trams-shake.md b/.changeset/nice-trams-shake.md deleted file mode 100644 index b58c03200f..0000000000 --- a/.changeset/nice-trams-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Fixed bug where custom `review.name` values were incorrectly formatted by `startCase`, preserving them exactly as written. diff --git a/.changeset/old-cats-shake.md b/.changeset/old-cats-shake.md deleted file mode 100644 index 3ca30a0421..0000000000 --- a/.changeset/old-cats-shake.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-defaults': patch -'@backstage/backend-plugin-api': minor ---- - -Adds a new experimental `RootSystemMetadataService` for tracking the collection of Backstage instances that may be deployed at any one time. It currently offers a single API, `getInstalledPlugins` that returns a list of installed plugins based on config you have set up in `discovery.endpoints` as well as the plugins installed on the instance you're calling the API with. It does not handle wildcard values or fallback values. The intention is for this plugin to provide plugin authors with a simple interface to fetch a trustworthy list of all installed plugins. diff --git a/.changeset/old-parks-smell.md b/.changeset/old-parks-smell.md deleted file mode 100644 index f089c7da21..0000000000 --- a/.changeset/old-parks-smell.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/plugin-techdocs-addons-test-utils': major ---- - -**BREAKING**: `TechDocsAddonTester.renderWithEffects()` no longer returns a screen; this means that you can no longer grab assertions such as `getByText` from its return value. - -Newer versions of `@testing-library` recommends using the `screen` export for assertions - and removing this from the addon tester contract allows us to more freely iterate on which underlying version of the testing library is being used. - -One notable effect of this, however, is that the `@testing-library` `screen` does NOT support assertions on the shadow DOM, which techdocs relies on. You will therefore want to add a dependency on [the `shadow-dom-testing-library` package](https://github.com/konnorrogers/shadow-dom-testing-library/) in your tests, and using its `screen` and its dedicated `*Shadow*` methods. As an example, if you keep doing `getByText` you will not get matches inside the shadow DOM - switch to `getByShadowText` instead. - -```ts -import { screen } from 'shadow-dom-testing-library'; - -// ... render the addon ... -await TechDocsAddonTester.buildAddonsInTechDocs([]) - .withDom(TEST_CONTENT) - .renderWithEffects(); - -expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument(); -``` diff --git a/.changeset/open-points-beam.md b/.changeset/open-points-beam.md deleted file mode 100644 index b58bf2b3d5..0000000000 --- a/.changeset/open-points-beam.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@backstage/ui': minor ---- - -**Breaking change** The `Cell` component has been refactored to be a generic wrapper component that accepts `children` for custom cell content. The text-specific functionality (previously part of `Cell`) has been moved to a new `CellText` component. - -### Migration Guide - -If you were using `Cell` with text-specific props (`title`, `description`, `leadingIcon`, `href`), you need to update your code to use `CellText` instead: - -**Before:** - -```tsx -} - href="/path" -/> -``` - -**After:** - -```tsx -} - href="/path" -/> -``` - -For custom cell content, use the new generic `Cell` component: - -```tsx -{/* Your custom content */} -``` diff --git a/.changeset/polite-pillows-accept.md b/.changeset/polite-pillows-accept.md new file mode 100644 index 0000000000..ece7c02ee1 --- /dev/null +++ b/.changeset/polite-pillows-accept.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Rollback the lowercase replacing in GitHub integration config diff --git a/.changeset/pre.json b/.changeset/pre.json index 3419f9dbb2..8b1cbc3ad4 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,298 +1,227 @@ { - "mode": "exit", + "mode": "pre", "tag": "next", "initialVersions": { - "example-app": "0.2.115", - "@backstage/app-defaults": "1.7.2", - "example-app-next": "0.0.29", - "app-next-example-plugin": "0.0.29", - "example-backend": "0.0.44", - "@backstage/backend-app-api": "1.3.0", - "@backstage/backend-defaults": "0.13.1", - "@backstage/backend-dev-utils": "0.1.5", - "@backstage/backend-dynamic-feature-service": "0.7.6", - "@backstage/backend-openapi-utils": "0.6.3", - "@backstage/backend-plugin-api": "1.5.0", - "@backstage/backend-test-utils": "1.10.0", + "example-app": "0.2.116", + "@backstage/app-defaults": "1.7.3", + "example-app-next": "0.0.30", + "app-next-example-plugin": "0.0.30", + "example-backend": "0.0.45", + "@backstage/backend-app-api": "1.4.0", + "@backstage/backend-defaults": "0.14.0", + "@backstage/backend-dev-utils": "0.1.6", + "@backstage/backend-dynamic-feature-service": "0.7.7", + "@backstage/backend-openapi-utils": "0.6.4", + "@backstage/backend-plugin-api": "1.6.0", + "@backstage/backend-test-utils": "1.10.2", "@backstage/catalog-client": "1.12.1", "@backstage/catalog-model": "1.7.6", - "@backstage/cli": "0.34.5", - "@backstage/cli-common": "0.1.15", - "@backstage/cli-node": "0.2.15", - "@backstage/codemods": "0.1.52", + "@backstage/cli": "0.35.0", + "@backstage/cli-common": "0.1.16", + "@backstage/cli-node": "0.2.16", + "@backstage/codemods": "0.1.53", "@backstage/config": "1.3.6", - "@backstage/config-loader": "1.10.6", - "@backstage/core-app-api": "1.19.2", - "@backstage/core-compat-api": "0.5.4", - "@backstage/core-components": "0.18.3", - "@backstage/core-plugin-api": "1.12.0", - "@backstage/create-app": "0.7.6", - "@backstage/dev-utils": "1.1.17", - "e2e-test": "0.2.34", + "@backstage/config-loader": "1.10.7", + "@backstage/core-app-api": "1.19.3", + "@backstage/core-compat-api": "0.5.5", + "@backstage/core-components": "0.18.4", + "@backstage/core-plugin-api": "1.12.1", + "@backstage/create-app": "0.7.7", + "@backstage/dev-utils": "1.1.18", + "e2e-test": "0.2.35", "@backstage/e2e-test-utils": "0.1.1", "@backstage/errors": "1.2.7", "@backstage/eslint-plugin": "0.2.0", - "@backstage/frontend-app-api": "0.13.2", - "@backstage/frontend-defaults": "0.3.3", - "@backstage/frontend-dynamic-feature-loader": "0.1.7", - "@internal/frontend": "0.0.15", - "@backstage/frontend-plugin-api": "0.13.0", - "@backstage/frontend-test-utils": "0.4.1", - "@backstage/integration": "1.18.2", + "@backstage/frontend-app-api": "0.13.3", + "@backstage/frontend-defaults": "0.3.4", + "@backstage/frontend-dynamic-feature-loader": "0.1.8", + "@internal/frontend": "0.0.16", + "@backstage/frontend-plugin-api": "0.13.2", + "@backstage/frontend-test-utils": "0.4.2", + "@backstage/integration": "1.19.0", "@backstage/integration-aws-node": "0.1.19", - "@backstage/integration-react": "1.2.12", + "@backstage/integration-react": "1.2.13", "@internal/opaque": "0.0.1", "@backstage/release-manifests": "0.0.13", - "@backstage/repo-tools": "0.16.0", - "@internal/scaffolder": "0.0.15", - "@techdocs/cli": "1.10.2", - "techdocs-cli-embedded-app": "0.2.114", - "@backstage/test-utils": "1.7.13", - "@backstage/theme": "0.7.0", + "@backstage/repo-tools": "0.16.1", + "@internal/scaffolder": "0.0.16", + "@techdocs/cli": "1.10.3", + "techdocs-cli-embedded-app": "0.2.115", + "@backstage/test-utils": "1.7.14", + "@backstage/theme": "0.7.1", "@backstage/types": "1.2.2", - "@backstage/ui": "0.9.0", + "@backstage/ui": "0.10.0", "@backstage/version-bridge": "1.0.11", - "yarn-plugin-backstage": "0.0.7", - "@backstage/plugin-api-docs": "0.13.1", + "yarn-plugin-backstage": "0.0.8", + "@backstage/plugin-api-docs": "0.13.2", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.10", - "@backstage/plugin-app": "0.3.2", - "@backstage/plugin-app-backend": "0.5.8", - "@backstage/plugin-app-node": "0.1.39", - "@backstage/plugin-app-visualizer": "0.1.25", - "@backstage/plugin-auth": "0.1.2", - "@backstage/plugin-auth-backend": "0.25.6", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-auth0-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-github-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-google-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-guest-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.14", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.9", - "@backstage/plugin-auth-backend-module-okta-provider": "0.2.9", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-openshift-provider": "0.1.2", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.9", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.9", - "@backstage/plugin-auth-node": "0.6.9", - "@backstage/plugin-auth-react": "0.1.21", - "@backstage/plugin-bitbucket-cloud-common": "0.3.4", - "@backstage/plugin-catalog": "1.32.0", - "@backstage/plugin-catalog-backend": "3.2.0", - "@backstage/plugin-catalog-backend-module-aws": "0.4.17", - "@backstage/plugin-catalog-backend-module-azure": "0.3.11", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.8", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.5", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.5", - "@backstage/plugin-catalog-backend-module-gcp": "0.3.14", - "@backstage/plugin-catalog-backend-module-gerrit": "0.3.8", - "@backstage/plugin-catalog-backend-module-gitea": "0.1.6", - "@backstage/plugin-catalog-backend-module-github": "0.11.2", - "@backstage/plugin-catalog-backend-module-github-org": "0.3.16", - "@backstage/plugin-catalog-backend-module-gitlab": "0.7.5", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.15", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.6", - "@backstage/plugin-catalog-backend-module-ldap": "0.12.0", - "@backstage/plugin-catalog-backend-module-logs": "0.1.16", - "@backstage/plugin-catalog-backend-module-msgraph": "0.8.2", - "@backstage/plugin-catalog-backend-module-openapi": "0.2.16", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.16", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.14", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.6", + "@backstage/plugin-app": "0.3.3", + "@backstage/plugin-app-backend": "0.5.9", + "@backstage/plugin-app-node": "0.1.40", + "@backstage/plugin-app-visualizer": "0.1.26", + "@backstage/plugin-auth": "0.1.3", + "@backstage/plugin-auth-backend": "0.25.7", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-auth0-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.15", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-github-provider": "0.4.0", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-google-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-guest-provider": "0.2.15", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.15", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.4.10", + "@backstage/plugin-auth-backend-module-okta-provider": "0.2.10", + "@backstage/plugin-auth-backend-module-onelogin-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-openshift-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.3.10", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.5.10", + "@backstage/plugin-auth-node": "0.6.10", + "@backstage/plugin-auth-react": "0.1.22", + "@backstage/plugin-bitbucket-cloud-common": "0.3.5", + "@backstage/plugin-catalog": "1.32.1", + "@backstage/plugin-catalog-backend": "3.3.0", + "@backstage/plugin-catalog-backend-module-aws": "0.4.18", + "@backstage/plugin-catalog-backend-module-azure": "0.3.12", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.5.9", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.5.6", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.5.6", + "@backstage/plugin-catalog-backend-module-gcp": "0.3.15", + "@backstage/plugin-catalog-backend-module-gerrit": "0.3.9", + "@backstage/plugin-catalog-backend-module-gitea": "0.1.7", + "@backstage/plugin-catalog-backend-module-github": "0.12.0", + "@backstage/plugin-catalog-backend-module-github-org": "0.3.17", + "@backstage/plugin-catalog-backend-module-gitlab": "0.7.6", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.16", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.7.7", + "@backstage/plugin-catalog-backend-module-ldap": "0.12.1", + "@backstage/plugin-catalog-backend-module-logs": "0.1.17", + "@backstage/plugin-catalog-backend-module-msgraph": "0.8.3", + "@backstage/plugin-catalog-backend-module-openapi": "0.2.17", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.17", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.15", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.6.7", "@backstage/plugin-catalog-common": "1.1.7", - "@backstage/plugin-catalog-graph": "0.5.3", - "@backstage/plugin-catalog-import": "0.13.7", - "@backstage/plugin-catalog-node": "1.20.0", - "@backstage/plugin-catalog-react": "1.21.3", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.23", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.11", - "@backstage/plugin-config-schema": "0.1.74", - "@backstage/plugin-devtools": "0.1.33", - "@backstage/plugin-devtools-backend": "0.5.11", - "@backstage/plugin-devtools-common": "0.1.19", - "@backstage/plugin-events-backend": "0.5.8", - "@backstage/plugin-events-backend-module-aws-sqs": "0.4.17", - "@backstage/plugin-events-backend-module-azure": "0.2.26", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.26", - "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.7", - "@backstage/plugin-events-backend-module-gerrit": "0.2.26", - "@backstage/plugin-events-backend-module-github": "0.4.6", - "@backstage/plugin-events-backend-module-gitlab": "0.3.7", - "@backstage/plugin-events-backend-module-google-pubsub": "0.1.6", - "@backstage/plugin-events-backend-module-kafka": "0.1.5", - "@backstage/plugin-events-backend-test-utils": "0.1.50", - "@backstage/plugin-events-node": "0.4.17", - "@internal/plugin-todo-list": "1.0.45", - "@internal/plugin-todo-list-backend": "1.0.45", + "@backstage/plugin-catalog-graph": "0.5.4", + "@backstage/plugin-catalog-import": "0.13.8", + "@backstage/plugin-catalog-node": "1.20.1", + "@backstage/plugin-catalog-react": "1.21.4", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.24", + "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.12", + "@backstage/plugin-config-schema": "0.1.75", + "@backstage/plugin-devtools": "0.1.34", + "@backstage/plugin-devtools-backend": "0.5.12", + "@backstage/plugin-devtools-common": "0.1.20", + "@backstage/plugin-events-backend": "0.5.9", + "@backstage/plugin-events-backend-module-aws-sqs": "0.4.18", + "@backstage/plugin-events-backend-module-azure": "0.2.27", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.27", + "@backstage/plugin-events-backend-module-bitbucket-server": "0.1.8", + "@backstage/plugin-events-backend-module-gerrit": "0.2.27", + "@backstage/plugin-events-backend-module-github": "0.4.7", + "@backstage/plugin-events-backend-module-gitlab": "0.3.8", + "@backstage/plugin-events-backend-module-google-pubsub": "0.1.7", + "@backstage/plugin-events-backend-module-kafka": "0.2.0", + "@backstage/plugin-events-backend-test-utils": "0.1.51", + "@backstage/plugin-events-node": "0.4.18", + "@internal/plugin-todo-list": "1.0.46", + "@internal/plugin-todo-list-backend": "1.0.46", "@internal/plugin-todo-list-common": "1.0.28", - "@backstage/plugin-gateway-backend": "1.1.0", - "@backstage/plugin-home": "0.8.14", - "@backstage/plugin-home-react": "0.1.32", - "@backstage/plugin-kubernetes": "0.12.13", - "@backstage/plugin-kubernetes-backend": "0.20.4", - "@backstage/plugin-kubernetes-cluster": "0.0.31", - "@backstage/plugin-kubernetes-common": "0.9.8", - "@backstage/plugin-kubernetes-node": "0.3.6", - "@backstage/plugin-kubernetes-react": "0.5.13", - "@backstage/plugin-mcp-actions-backend": "0.1.5", - "@backstage/plugin-mui-to-bui": "0.2.1", - "@backstage/plugin-notifications": "0.5.11", - "@backstage/plugin-notifications-backend": "0.6.0", - "@backstage/plugin-notifications-backend-module-email": "0.3.16", - "@backstage/plugin-notifications-backend-module-slack": "0.2.1", + "@backstage/plugin-gateway-backend": "1.1.1", + "@backstage/plugin-home": "0.8.15", + "@backstage/plugin-home-react": "0.1.33", + "@backstage/plugin-kubernetes": "0.12.14", + "@backstage/plugin-kubernetes-backend": "0.21.0", + "@backstage/plugin-kubernetes-cluster": "0.0.32", + "@backstage/plugin-kubernetes-common": "0.9.9", + "@backstage/plugin-kubernetes-node": "0.4.0", + "@backstage/plugin-kubernetes-react": "0.5.14", + "@backstage/plugin-mcp-actions-backend": "0.1.6", + "@backstage/plugin-mui-to-bui": "0.2.2", + "@backstage/plugin-notifications": "0.5.12", + "@backstage/plugin-notifications-backend": "0.6.1", + "@backstage/plugin-notifications-backend-module-email": "0.3.17", + "@backstage/plugin-notifications-backend-module-slack": "0.3.0", "@backstage/plugin-notifications-common": "0.2.0", - "@backstage/plugin-notifications-node": "0.2.21", - "@backstage/plugin-org": "0.6.46", - "@backstage/plugin-org-react": "0.1.44", - "@backstage/plugin-permission-backend": "0.7.6", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.14", + "@backstage/plugin-notifications-node": "0.2.22", + "@backstage/plugin-org": "0.6.47", + "@backstage/plugin-org-react": "0.1.45", + "@backstage/plugin-permission-backend": "0.7.7", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.15", "@backstage/plugin-permission-common": "0.9.3", - "@backstage/plugin-permission-node": "0.10.6", - "@backstage/plugin-permission-react": "0.4.38", - "@backstage/plugin-proxy-backend": "0.6.8", - "@backstage/plugin-proxy-node": "0.1.10", - "@backstage/plugin-scaffolder": "1.34.3", - "@backstage/plugin-scaffolder-backend": "3.0.1", - "@backstage/plugin-scaffolder-backend-module-azure": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.16", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.15", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.17", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-github": "0.9.2", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.10.0", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.16", - "@backstage/plugin-scaffolder-backend-module-rails": "0.5.15", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.15", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.16", - "@backstage/plugin-scaffolder-common": "1.7.3", - "@backstage/plugin-scaffolder-node": "0.12.1", - "@backstage/plugin-scaffolder-node-test-utils": "0.3.5", - "@backstage/plugin-scaffolder-react": "1.19.3", - "@backstage/plugin-search": "1.5.0", - "@backstage/plugin-search-backend": "2.0.8", - "@backstage/plugin-search-backend-module-catalog": "0.3.10", - "@backstage/plugin-search-backend-module-elasticsearch": "1.7.8", - "@backstage/plugin-search-backend-module-explore": "0.3.9", - "@backstage/plugin-search-backend-module-pg": "0.5.50", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.15", - "@backstage/plugin-search-backend-module-techdocs": "0.4.8", - "@backstage/plugin-search-backend-node": "1.3.17", + "@backstage/plugin-permission-node": "0.10.7", + "@backstage/plugin-permission-react": "0.4.39", + "@backstage/plugin-proxy-backend": "0.6.9", + "@backstage/plugin-proxy-node": "0.1.11", + "@backstage/plugin-scaffolder": "1.35.0", + "@backstage/plugin-scaffolder-backend": "3.1.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.17", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.3.0", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.16", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.18", + "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-github": "0.9.3", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.11.0", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.17", + "@backstage/plugin-scaffolder-backend-module-rails": "0.5.16", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.16", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.17", + "@backstage/plugin-scaffolder-common": "1.7.4", + "@backstage/plugin-scaffolder-node": "0.12.2", + "@backstage/plugin-scaffolder-node-test-utils": "0.3.6", + "@backstage/plugin-scaffolder-react": "1.19.4", + "@backstage/plugin-search": "1.5.1", + "@backstage/plugin-search-backend": "2.0.9", + "@backstage/plugin-search-backend-module-catalog": "0.3.11", + "@backstage/plugin-search-backend-module-elasticsearch": "1.7.9", + "@backstage/plugin-search-backend-module-explore": "0.3.10", + "@backstage/plugin-search-backend-module-pg": "0.5.51", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.16", + "@backstage/plugin-search-backend-module-techdocs": "0.4.9", + "@backstage/plugin-search-backend-node": "1.4.0", "@backstage/plugin-search-common": "1.2.21", - "@backstage/plugin-search-react": "1.10.0", - "@backstage/plugin-signals": "0.0.25", - "@backstage/plugin-signals-backend": "0.3.10", - "@backstage/plugin-signals-node": "0.1.26", - "@backstage/plugin-signals-react": "0.0.17", - "@backstage/plugin-techdocs": "1.16.0", - "@backstage/plugin-techdocs-addons-test-utils": "1.1.2", - "@backstage/plugin-techdocs-backend": "2.1.2", + "@backstage/plugin-search-react": "1.10.1", + "@backstage/plugin-signals": "0.0.26", + "@backstage/plugin-signals-backend": "0.3.11", + "@backstage/plugin-signals-node": "0.1.27", + "@backstage/plugin-signals-react": "0.0.18", + "@backstage/plugin-techdocs": "1.16.1", + "@backstage/plugin-techdocs-addons-test-utils": "2.0.0", + "@backstage/plugin-techdocs-backend": "2.1.3", "@backstage/plugin-techdocs-common": "0.1.1", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.30", - "@backstage/plugin-techdocs-node": "1.13.9", - "@backstage/plugin-techdocs-react": "1.3.5", - "@backstage/plugin-user-settings": "0.8.29", - "@backstage/plugin-user-settings-backend": "0.3.8", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.31", + "@backstage/plugin-techdocs-node": "1.13.10", + "@backstage/plugin-techdocs-react": "1.3.6", + "@backstage/plugin-user-settings": "0.8.30", + "@backstage/plugin-user-settings-backend": "0.3.9", "@backstage/plugin-user-settings-common": "0.0.1" }, "changesets": [ - "afraid-items-drum", - "alert-api-replay", - "all-socks-taste", - "blue-signs-fry", - "bumpy-planets-go", - "chatty-sides-wear", - "chilly-bikes-rule", - "chilly-hotels-walk", - "chilly-waves-relate", - "clean-toys-reply", - "common-coins-stare", - "crazy-hornets-spend", - "create-app-1764689798", - "dependabot-0d8f6de", - "dependabot-5e654fe", - "early-doors-visit", - "error-boundary-api", - "famous-jars-lose", - "fifty-coats-feel", - "fifty-lights-marry", - "fine-eagles-sleep", - "flat-pillows-rush", - "floppy-bobcats-serve", - "four-peaches-train", - "fruity-rivers-arrive", - "fruity-words-melt", - "full-needles-drive", - "funny-hornets-peel", - "funny-papayas-rest", - "fuzzy-phones-own", - "fuzzy-rivers-travel", - "fuzzy-trees-live", - "gentle-singers-love", - "gentle-trains-juggle", - "great-files-shave", - "green-lizards-boil", - "happy-bottles-invite", - "happy-streets-dress", - "honest-bears-itch", - "kind-hoops-double", - "large-planes-punch", - "legal-cloths-spend", - "legal-otters-punch", - "lemon-corners-hug", - "loose-pets-slide", - "loud-yaks-watch", - "lucky-days-hug", - "many-planes-join", - "metal-boxes-laugh", - "metal-humans-lose", - "modern-taxes-start", - "neat-pens-clean", - "nice-humans-cry", - "nice-trams-shake", - "old-cats-shake", - "old-parks-smell", - "open-points-beam", - "quiet-hats-sleep", - "rare-rice-throw", - "ready-results-march", - "renovate-7b76d6d", - "renovate-959c095", - "renovate-97eef4b", - "renovate-9ec01ff", - "renovate-a3c2cbd", - "renovate-aa0bb93", - "renovate-ad7bf17", - "renovate-d7ceb06", - "renovate-ea25c93", - "rotten-melons-sleep", - "salty-camels-wash", - "seven-games-rest", - "short-groups-knock", - "slick-books-sleep", - "slick-onions-wash", - "slimy-islands-play", - "slimy-mugs-taste", - "sour-bats-press", - "spicy-teeth-study", - "stale-eagles-rush", - "stupid-cases-fold", - "tall-ideas-lead", - "tame-mirrors-sit", - "tender-dancers-hunt", - "tired-dogs-remain", - "tough-lies-grow", - "twenty-ducks-relate" + "better-ghosts-tell", + "clever-streets-roll", + "cold-dogs-study", + "create-app-1766498726", + "create-app-1767101113", + "dependabot-aed8e01", + "every-bears-add", + "hot-colts-float", + "hungry-mugs-fall", + "major-mangos-shine", + "polite-pillows-accept", + "proud-streets-switch", + "shaggy-bats-film", + "thin-teams-roll", + "weak-lemons-create", + "wild-toys-retire" ] } diff --git a/.changeset/pretty-breads-speak.md b/.changeset/pretty-breads-speak.md deleted file mode 100644 index 13accd1cd0..0000000000 --- a/.changeset/pretty-breads-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-slack': patch ---- - -Slack notification handler throttling can now be configured with the `concurrencyLimit` and `throttleInterval` options. diff --git a/.changeset/proud-streets-switch.md b/.changeset/proud-streets-switch.md new file mode 100644 index 0000000000..188b66f178 --- /dev/null +++ b/.changeset/proud-streets-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-oidc-provider': patch +--- + +Added support for custom start URL search parameters (with the new `startUrlSearchParams` config property) diff --git a/.changeset/quiet-hats-sleep.md b/.changeset/quiet-hats-sleep.md deleted file mode 100644 index 5f75f22f6c..0000000000 --- a/.changeset/quiet-hats-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fixing OpenAPI definition diff --git a/.changeset/rare-rice-throw.md b/.changeset/rare-rice-throw.md deleted file mode 100644 index 6fa0434f67..0000000000 --- a/.changeset/rare-rice-throw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Add `tooltipClasses` prop to `OverflowTooltip` component to allow customisation of the tooltip diff --git a/.changeset/ready-results-march.md b/.changeset/ready-results-march.md deleted file mode 100644 index c28ade8de9..0000000000 --- a/.changeset/ready-results-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Fixed `catalogAboutEntityCard` to filter icon links before calling useProps(), preventing side effects from hooks in filtered-out links diff --git a/.changeset/renovate-7b76d6d.md b/.changeset/renovate-7b76d6d.md deleted file mode 100644 index 9ccb2dd94b..0000000000 --- a/.changeset/renovate-7b76d6d.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/plugin-scaffolder-backend': patch ---- - -Updated dependency `esbuild` to `^0.27.0`. diff --git a/.changeset/renovate-959c095.md b/.changeset/renovate-959c095.md deleted file mode 100644 index d2370a1c8b..0000000000 --- a/.changeset/renovate-959c095.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `@rjsf/utils` to `5.24.13`. -Updated dependency `@rjsf/core` to `5.24.13`. -Updated dependency `@rjsf/material-ui` to `5.24.13`. -Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. diff --git a/.changeset/renovate-97eef4b.md b/.changeset/renovate-97eef4b.md deleted file mode 100644 index 9b3692bc1c..0000000000 --- a/.changeset/renovate-97eef4b.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Updated dependency `typescript-json-schema` to `^0.67.0`. diff --git a/.changeset/renovate-9ec01ff.md b/.changeset/renovate-9ec01ff.md deleted file mode 100644 index 1ab750c0e6..0000000000 --- a/.changeset/renovate-9ec01ff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-explore': patch ---- - -Updated dependency `@backstage-community/plugin-explore-common` to `^0.9.0`. diff --git a/.changeset/renovate-a3c2cbd.md b/.changeset/renovate-a3c2cbd.md deleted file mode 100644 index 2fde85d39e..0000000000 --- a/.changeset/renovate-a3c2cbd.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Updated dependency `use-immer` to `^0.11.0`. diff --git a/.changeset/renovate-aa0bb93.md b/.changeset/renovate-aa0bb93.md deleted file mode 100644 index 5f40a61fab..0000000000 --- a/.changeset/renovate-aa0bb93.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications-backend-module-email': patch ---- - -Updated dependency `@types/nodemailer` to `^7.0.0`. diff --git a/.changeset/renovate-ad7bf17.md b/.changeset/renovate-ad7bf17.md deleted file mode 100644 index a0f90ff97d..0000000000 --- a/.changeset/renovate-ad7bf17.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Updated dependency `@types/archiver` to `^7.0.0`. diff --git a/.changeset/renovate-d7ceb06.md b/.changeset/renovate-d7ceb06.md deleted file mode 100644 index d22f266301..0000000000 --- a/.changeset/renovate-d7ceb06.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@pmmmwh/react-refresh-webpack-plugin` to `^0.6.0`. diff --git a/.changeset/renovate-ea25c93.md b/.changeset/renovate-ea25c93.md deleted file mode 100644 index 958e032b64..0000000000 --- a/.changeset/renovate-ea25c93.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `webpack` to `~5.103.0`. diff --git a/.changeset/rotten-carrots-relax.md b/.changeset/rotten-carrots-relax.md deleted file mode 100644 index 339a5cdd6b..0000000000 --- a/.changeset/rotten-carrots-relax.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Move long notification descriptions behind `Show more/less` button. - -This improves readability of the notifications list by preventing long descriptions from taking up too much space -or rendering very small scrollable areas. diff --git a/.changeset/rotten-melons-sleep.md b/.changeset/rotten-melons-sleep.md deleted file mode 100644 index c12e0a9669..0000000000 --- a/.changeset/rotten-melons-sleep.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@backstage/plugin-catalog-unprocessed-entities-common': patch -'@backstage/plugin-catalog-unprocessed-entities': patch ---- - -Moved types, API and client to the common package, allowing both frontend and -backend plugins to use the `CatalogUnprocessedEntitiesClient`. - -The following types, clients and interfaces have been deprecated and should be -imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead: -`CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`, -`UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`. - -All those types, clients and interfaces are re-exported temporarily in the -`@backstage/plugin-catalog-unprocessed-entities` package until cleaned up. diff --git a/.changeset/salty-camels-wash.md b/.changeset/salty-camels-wash.md deleted file mode 100644 index 56600db540..0000000000 --- a/.changeset/salty-camels-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed internal usage of `yargs`. diff --git a/.changeset/seven-games-rest.md b/.changeset/seven-games-rest.md deleted file mode 100644 index b498c3b138..0000000000 --- a/.changeset/seven-games-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch ---- - -Corrected `ErrorCallback` type to work with Node 22 types diff --git a/.changeset/shaggy-bats-film.md b/.changeset/shaggy-bats-film.md new file mode 100644 index 0000000000..3e5be9648b --- /dev/null +++ b/.changeset/shaggy-bats-film.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': minor +--- + +**BREAKING**: Renamed CSS variable `--bui-bg` to `--bui-bg-surface-0` for consistency. diff --git a/.changeset/short-cloths-tie.md b/.changeset/short-cloths-tie.md deleted file mode 100644 index fe379fb18d..0000000000 --- a/.changeset/short-cloths-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Don't warn when parsing `storeOptions` for `memory` cache diff --git a/.changeset/short-groups-knock.md b/.changeset/short-groups-knock.md deleted file mode 100644 index 0b622a71ed..0000000000 --- a/.changeset/short-groups-knock.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli-common': patch -'@backstage/create-app': patch -'@backstage/cli': patch ---- - -Add proxy configuration from env-vars to create-app tasks diff --git a/.changeset/short-lizards-find.md b/.changeset/short-lizards-find.md deleted file mode 100644 index 320a4db64d..0000000000 --- a/.changeset/short-lizards-find.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-devtools-common': patch -'@backstage/plugin-devtools-backend': patch -'@backstage/plugin-devtools': patch ---- - -Added scheduled tasks UI feature for the DevTools plugin diff --git a/.changeset/slick-books-sleep.md b/.changeset/slick-books-sleep.md deleted file mode 100644 index 7aa3be5b03..0000000000 --- a/.changeset/slick-books-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/theme': patch ---- - -Added a `themeName` prop to `UnifiedThemeProvider`, enabling Backstage UI `data-theme-name` CSS attribute to be set based on active theme. diff --git a/.changeset/slick-onions-wash.md b/.changeset/slick-onions-wash.md deleted file mode 100644 index 4627d02e81..0000000000 --- a/.changeset/slick-onions-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Add i18n support for LogViewer search control diff --git a/.changeset/slimy-islands-play.md b/.changeset/slimy-islands-play.md deleted file mode 100644 index 497d86761b..0000000000 --- a/.changeset/slimy-islands-play.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Added row selection support with visual state styling for hover, selected, and pressed states. Fixed checkbox rendering to only show for multi-select toggle mode. - -Affected components: Table, TableHeader, Row, Column diff --git a/.changeset/slimy-mugs-taste.md b/.changeset/slimy-mugs-taste.md deleted file mode 100644 index 5773db6853..0000000000 --- a/.changeset/slimy-mugs-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Fix PostgreSQL 18 `TestDatabases` by pinning the data directory diff --git a/.changeset/sour-bats-press.md b/.changeset/sour-bats-press.md deleted file mode 100644 index bfcf3985e6..0000000000 --- a/.changeset/sour-bats-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -fix flawed cookie removal logic with chunked tokens diff --git a/.changeset/spicy-sides-grow.md b/.changeset/spicy-sides-grow.md deleted file mode 100644 index 3f44f35866..0000000000 --- a/.changeset/spicy-sides-grow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -added support for wrapLongLines option in CodeSnippet diff --git a/.changeset/spicy-teeth-study.md b/.changeset/spicy-teeth-study.md deleted file mode 100644 index 03cc8a5440..0000000000 --- a/.changeset/spicy-teeth-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed `useTable` hook to prioritize `providedRowCount` over data length for accurate row count in server-side pagination scenarios. diff --git a/.changeset/stale-eagles-rush.md b/.changeset/stale-eagles-rush.md deleted file mode 100644 index fe640ccd44..0000000000 --- a/.changeset/stale-eagles-rush.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch -'@backstage/core-plugin-api': patch ---- - -Reversed the relationship between the old `@backstage/core-plugin-api` and the new `@backstage/frontend-plugin-api`. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old. diff --git a/.changeset/stale-poets-battle.md b/.changeset/stale-poets-battle.md deleted file mode 100644 index 1725fd2885..0000000000 --- a/.changeset/stale-poets-battle.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-kafka': minor ---- - -Added `KafkaPublishingEventConsumer` to support sending Backstage events to Kafka topics. - -This addition enables Backstage to publish events to external Kafka systems, complementing the existing ability to receive events from Kafka. This allows for better integration with external systems that rely on Kafka for event streaming. diff --git a/.changeset/stupid-cases-fold.md b/.changeset/stupid-cases-fold.md deleted file mode 100644 index 6ee2472746..0000000000 --- a/.changeset/stupid-cases-fold.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Switched compilation target to ES2022 in order to match the new set of supported Node.js versions, which are 22 and 24. - -The TypeScript compilation target has been set to ES2022, because setting it to a higher target will break projects on older TypeScript versions. If you use a newer TypeScript version in your own project, you can bump `compilerOptions.target` to ES2023 or ES2024 in your own `tsconfig.json` file. diff --git a/.changeset/swift-moments-think.md b/.changeset/swift-moments-think.md deleted file mode 100644 index 185fd4ff48..0000000000 --- a/.changeset/swift-moments-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Added configurable `pageSizes` option to `GithubOrgEntityProvider` for GitHub GraphQL API queries to prevent `RESOURCE_LIMITS_EXCEEDED` errors with organizations with large number of teams and members. This aligns the configuration options with `GithubMultiOrgEntityProvider`. diff --git a/.changeset/swift-wolves-judge.md b/.changeset/swift-wolves-judge.md deleted file mode 100644 index 399ed5bad8..0000000000 --- a/.changeset/swift-wolves-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Removed unnecessary dependencies on `@backstage/core-components`, `@backstage/config`, `@material-ui/core`, and `lodash`. diff --git a/.changeset/tall-ideas-lead.md b/.changeset/tall-ideas-lead.md deleted file mode 100644 index 60bef903d8..0000000000 --- a/.changeset/tall-ideas-lead.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch ---- - -Improve error message when provided target branch is missing diff --git a/.changeset/tame-mirrors-sit.md b/.changeset/tame-mirrors-sit.md deleted file mode 100644 index f317185ea2..0000000000 --- a/.changeset/tame-mirrors-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-dev-utils': patch ---- - -Internal update for Node.js v24 support. diff --git a/.changeset/tender-dancers-hunt.md b/.changeset/tender-dancers-hunt.md deleted file mode 100644 index e20ec43ae0..0000000000 --- a/.changeset/tender-dancers-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated to use new utilities from `@backstage/cli-common`. diff --git a/.changeset/thin-teams-roll.md b/.changeset/thin-teams-roll.md new file mode 100644 index 0000000000..f0c395410a --- /dev/null +++ b/.changeset/thin-teams-roll.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Fixed a spelling mistake in root health service shutdown response. diff --git a/.changeset/tired-dogs-remain.md b/.changeset/tired-dogs-remain.md deleted file mode 100644 index 06c193068b..0000000000 --- a/.changeset/tired-dogs-remain.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-rails': patch -'@backstage/plugin-kubernetes-cluster': patch -'@techdocs/cli': patch -'@backstage/cli-common': patch -'@backstage/create-app': patch -'@backstage/repo-tools': patch -'@backstage/codemods': patch -'@backstage/cli': patch ---- - -Bumped dev dependencies `@types/node` diff --git a/.changeset/tough-lies-grow.md b/.changeset/tough-lies-grow.md deleted file mode 100644 index dab952df65..0000000000 --- a/.changeset/tough-lies-grow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-techdocs': patch ---- - -The `techdocs` config is now marked as optional. diff --git a/.changeset/twenty-ducks-relate.md b/.changeset/twenty-ducks-relate.md deleted file mode 100644 index 359eda66f3..0000000000 --- a/.changeset/twenty-ducks-relate.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/ui': patch ---- - -Fixed Table column sorting indicator to show up arrow when no sort is active, correctly indicating that clicking will sort ascending. - -Affected components: Column diff --git a/.changeset/weak-lemons-create.md b/.changeset/weak-lemons-create.md new file mode 100644 index 0000000000..344a6660ce --- /dev/null +++ b/.changeset/weak-lemons-create.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Bump minimum required `@swc/core` to avoid transpilation bug diff --git a/.changeset/wild-toys-retire.md b/.changeset/wild-toys-retire.md new file mode 100644 index 0000000000..f7179e2527 --- /dev/null +++ b/.changeset/wild-toys-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-mui-to-bui': patch +--- + +Updated tokens from `--bui-bg` to `--bui-bg-surface-0` diff --git a/.cursor/rules/general.mdc b/.cursor/rules/general.mdc new file mode 100644 index 0000000000..3a81a0cb5f --- /dev/null +++ b/.cursor/rules/general.mdc @@ -0,0 +1,7 @@ +--- +description: General project guidelines for Backstage development +globs: +alwaysApply: true +--- + +Follow the instructions at /.github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 98073c5128..ee3fe6fda0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,11 +1,22 @@ -This is a TypeScript project structured as a monorepo using Yarn workspaces. +Backstage is an open platform for building developer portals. This is a TypeScript monorepo using Yarn workspaces. + +## Key Directories + +- `/packages`: Core framework packages (prefixed `@backstage/`) +- `/plugins`: Plugin packages (prefixed `@backstage/plugin-*`) +- `/packages/app` and `/packages/backend`: Example app for local development +- `/packages/app-next`: Example app using the new frontend system (NFS) +- `/docs`: Documentation files + +Packages prefixed with `core-` (e.g., `@backstage/core-plugin-api`) are part of the old frontend system. Packages prefixed with `frontend-` (e.g., `@backstage/frontend-plugin-api`) are part of the new frontend system (NFS). Packages prefixed with `backend-` (e.g., `@backstage/backend-plugin-api`) are part of the backend system. ## Code Standards The following files contain guidelines for the project: +- `/CONTRIBUTING.md`: comprehensive contribution guidelines. - `/STYLE.md`: guidelines for code style. -- `/REVIEWING.md`: guidelines for pull requests. +- `/REVIEWING.md`: guidelines for pull requests and writing changesets. - `/SECURITY.md`: guidelines for security. - `/docs/architecture-decisions/`: contains the architecture decisions for the project. @@ -19,10 +30,12 @@ Before any of these commands can be run, you need to run `yarn install` in the p - Code formatting: Use `yarn prettier --write ` to format code. - Lint: Use `yarn lint --fix` in the project root to run the linter. - API reports: Before submitting a pull request with changes to any package in the workspace, run `yarn build:api-reports` in the project root to generate API reports for all packages. +- Dev server: Use `yarn start` to run the example app locally (frontend on :3000, backend on :7007). +- Create: Use `yarn new` to scaffold new plugins, packages, or modules. You MUST NOT create a release by running `yarn changesets version` or `yarn release` as part of any changes. Releases are created by separate workflows. -All changes that affect the published version of packages in the `/packages` and `/plugins` directories must be accompanied by a changeset. See the guidelines in `/REVIEWING.md` for information on how to write good changesets. Changesets are stored in the `/.changeset` directory. Breaking changes must be accompanied by a `minor` version bump for packages that below version `1.0.0`, or a `major` version bump for packages that are at version `1.0.0` or higher. +All changes that affect the published version of packages in the `/packages` and `/plugins` directories must be accompanied by a changeset. Only non-private packages require changesets. See the guidelines in `/CONTRIBUTING.md#creating-changesets` for information on how to write good changesets. Changesets are stored in the `/.changeset` directory. Breaking changes must be accompanied by a `minor` version bump for packages below version `1.0.0`, or a `major` version bump for packages at version `1.0.0` or higher. Never update ESLint, Prettier, or TypeScript configuration files unless specifically requested. diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 6697fad858..22818c0965 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -268,6 +268,7 @@ maintainer's maintainership makefile Matomo +matchers md memcache memoization @@ -576,3 +577,4 @@ zoomable zsh resizable enums +LLMs diff --git a/.github/workflows/sync_patch-release.yml b/.github/workflows/sync_patch-release.yml index e17a229256..bdf93aa8a0 100644 --- a/.github/workflows/sync_patch-release.yml +++ b/.github/workflows/sync_patch-release.yml @@ -36,6 +36,12 @@ jobs: fetch-tags: true token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + - name: Use Node.js 22.x + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22.x + registry-url: https://registry.npmjs.org/ # Needed for auth + - name: Configure Git run: | git config --global user.email noreply@backstage.io diff --git a/.storybook/main.ts b/.storybook/main.ts index 788df83ba9..5453627f34 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,7 +1,13 @@ -import type { StorybookConfig } from '@storybook/react-vite'; +import { defineMain } from '@storybook/react-vite/node'; +import { fileURLToPath } from 'node:url'; +import { createRequire } from 'node:module'; import { join, dirname, posix } from 'path'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const require = createRequire(import.meta.url); + const isChromatic = process.env.STORYBOOK_STORY_SET === 'chromatic'; // All stories for full development @@ -35,13 +41,14 @@ function getAbsolutePath(value: string): any { return dirname(require.resolve(join(value, 'package.json'))); } -const config: StorybookConfig = { +export default defineMain({ stories, addons: [ getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-themes'), getAbsolutePath('@storybook/addon-docs'), getAbsolutePath('@storybook/addon-a11y'), + getAbsolutePath('@storybook/addon-vitest'), ], framework: { name: getAbsolutePath('@storybook/react-vite'), @@ -122,6 +129,4 @@ const config: StorybookConfig = { return config; }, -}; - -export default config; +}); diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 8f987ebab1..4e15677aed 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,8 +1,12 @@ -import React, { useEffect } from 'react'; +import addonA11y from '@storybook/addon-a11y'; +import addonDocs from '@storybook/addon-docs'; +import addonThemes from '@storybook/addon-themes'; +import addonLinks from '@storybook/addon-links'; +import { definePreview } from '@storybook/react-vite'; +import { useEffect } from 'react'; import { TestApiProvider } from '@backstage/test-utils'; import { Content, AlertDisplay } from '@backstage/core-components'; import { apis } from './support/apis'; -import type { Decorator, Preview } from '@storybook/react-vite'; import { useGlobals } from 'storybook/preview-api'; import { UnifiedThemeProvider, themes } from '@backstage/theme'; import { allModes } from './modes'; @@ -16,7 +20,7 @@ import './storybook.css'; // Custom themes import './themes/spotify.css'; -const preview: Preview = { +export default definePreview({ globalTypes: { themeMode: { name: 'Theme Mode', @@ -47,10 +51,12 @@ const preview: Preview = { }, }, }, + initialGlobals: { themeMode: 'light', themeName: 'backstage', }, + parameters: { layout: 'fullscreen', @@ -72,7 +78,7 @@ const preview: Preview = { }, viewport: { - viewports: { + options: { initial: { name: 'Initial', styles: { width: '320px', height: '100%' }, @@ -102,6 +108,7 @@ const preview: Preview = { }, }, }, + decorators: [ Story => { const [globals] = useGlobals(); @@ -121,10 +128,11 @@ const preview: Preview = { }; }, [selectedTheme, selectedThemeName]); - document.body.style.backgroundColor = 'var(--bui-bg)'; + document.body.style.backgroundColor = 'var(--bui-bg-surface-0)'; const docsStoryElements = document.getElementsByClassName('docs-story'); Array.from(docsStoryElements).forEach(element => { - (element as HTMLElement).style.backgroundColor = 'var(--bui-bg)'; + (element as HTMLElement).style.backgroundColor = + 'var(--bui-bg-surface-0)'; }); return ( @@ -140,6 +148,6 @@ const preview: Preview = { ); }, ], -}; -export default preview; + addons: [addonLinks(), addonThemes(), addonDocs(), addonA11y()], +}); diff --git a/.storybook/themes/spotify.css b/.storybook/themes/spotify.css index bcb1ded9ff..db3a0ca16c 100644 --- a/.storybook/themes/spotify.css +++ b/.storybook/themes/spotify.css @@ -216,9 +216,6 @@ } [data-theme-mode='light'][data-theme-name='spotify'] { - --bui-bg: var(--bui-gray-1); - --bui-bg-surface-1: var(--bui-white); - --bui-bg-surface-2: var(--bui-gray-2); --bui-bg-solid: #1ed760; --bui-bg-solid-hover: #3be477; --bui-bg-solid-pressed: #1abc54; @@ -248,9 +245,7 @@ } [data-theme-mode='dark'][data-theme-name='spotify'] { - --bui-bg: var(--bui-black); - --bui-bg-surface-1: var(--bui-gray-1); - --bui-bg-surface-2: var(--bui-gray-2); + --bui-bg-surface-0: var(--bui-black); --bui-bg-solid: #1ed760; --bui-bg-solid-hover: #3be477; --bui-bg-solid-pressed: #1abc54; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba40be86c8..80381417a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,7 @@ If you need help, just jump into our [Discord chatroom](https://discord.gg/backs - [Accessibility](#accessibility) - [Get Started!](#get-started) - [Coding Guidelines](#coding-guidelines) +- [AI Use Policy and Guidelines](#ai-use-policy-and-guidelines) - [Documentation Guidelines](#documentation-guidelines) - [Package Scripts](#package-scripts) - [Local configuration](#local-configuration) @@ -128,6 +129,37 @@ If there are any updates in `markdown` file please make sure to run `yarn run li The Backstage development environment does not require any specific editor, but it is intended to be used with one that has built-in linting and type-checking. The development server does not include any checks by default, but they can be enabled using the `--check` flag. Note that using the flag may consume more system resources and slow things down. +## AI Use Policy and Guidelines + +Our goal in the Backstage project is to develop an excellent software system. This requires careful attention to detail in every change we integrate. Maintainer time and attention is very limited, so it's important that changes you ask us to review represent your _best_ work. + +You are encouraged to use tools that help you write good code, including AI tools. However, you always need to understand and explain the changes you're proposing to make, whether or not you used an LLM as part of your process to produce them. The answer to "Why did you make change X?" should never be "I'm not sure. The AI did it." + +**Do not submit an AI-generated PR you haven't personally understood and tested**, as this wastes maintainers' time. PRs that appear to violate this guideline will be closed without review. If you do submit a largely AI-generated PR, clearly mark it as such in the description—maintainers may still close it without further review if it does not seem worthwhile. + +### Using AI as a Coding Assistant + +1. Don't skip **becoming familiar with the part of the codebase** you're working on. This will let you write better prompts and validate their output if you use an LLM. Code assistants can be a useful search engine/discovery tool in this process, but don't trust claims they make about how Backstage works. LLMs are often wrong, even about details that are clearly answered in the [Backstage documentation](https://backstage.io/docs). +2. Split up your changes into **coherent commits**, even if an LLM generates them all in one go. See our section on [Creating Changesets](#creating-changesets) for guidance on documenting your changes. +3. Don't simply ask an LLM to add **code comments**, as it will likely produce a bunch of text that unnecessarily explains what's already clear from the code. If using an LLM to generate comments, be really specific in your request, demand succinctness, and carefully edit the result. + +### Using AI for Communication + +Backstage contributors are expected to communicate with intention, to avoid wasting maintainer time with long, sloppy writing. We strongly prefer clear and concise communication about points that actually require discussion over long AI-generated comments. + +When you use an LLM to write a message for you, it remains **your responsibility** to read through the whole thing and make sure that it makes sense to you and represents your ideas concisely. A good rule of thumb is that if you can't make yourself carefully read some LLM output that you generated, nobody else wants to read it either. + +Here are some concrete guidelines for using LLMs as part of your communication workflows: + +1. When writing a pull request description, **do not include anything that's obvious** from looking at your changes directly (e.g., files changed, functions updated, etc.). Instead, focus on the _why_ behind your changes. Don't ask an LLM to generate a PR description on your behalf based on your code changes, as it will simply regurgitate the information that's already there. +2. Similarly, when responding to a pull request comment, **explain _your_ reasoning**. Don't prompt an LLM to re-describe what can already be seen from the code. +3. Verify that **everything you write is accurate**, whether or not an LLM generated any part of it. Backstage's maintainers will be unable to review your contributions if you misrepresent your work (e.g., wrongly describing your code changes, their effect, or your testing process). +4. Complete all parts of the **PR description template**, including screenshots and the checklist. Don't simply overwrite the template with LLM output. +5. **Clarity and succinctness** are much more important than perfect grammar, so you shouldn't feel obliged to pass your writing through an LLM. If you do ask an LLM to clean up your writing style, be sure it does _not_ make it longer in the process. Demand succinctness in your prompt. +6. Quoting an LLM answer is usually less helpful than linking to **relevant primary sources**, like source code, [Backstage documentation](https://backstage.io/docs), or reference materials. If you do need to quote an LLM answer in a discussion, clearly distinguish LLM output from your own thoughts. + +If you have questions about AI usage or need help, feel free to ask in [Discord](https://discord.gg/backstage-687207715902193673). + ## Documentation Guidelines Contributing to the docs is one of the best ways to start getting involved with Backstage. The documentation site is often the first stop for anyone using or exploring Backstage, so even small improvements can have a big impact! diff --git a/app-config.yaml b/app-config.yaml index 08c97c1172..54ece44da3 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -109,8 +109,12 @@ integrations: token: ${GITLAB_TOKEN} ### Example for how to add a bitbucket cloud integration # bitbucketCloud: + # # Using API token # - username: ${BITBUCKET_USERNAME} # token: ${BITBUCKET_API_TOKEN} + # # Using OAuth + # - clientId: ${BITBUCKET_CLIENT_ID} + # clientSecret: ${BITBUCKET_CLIENT_SECRET} ### Example for how to add your bitbucket server instance using the API: # - host: server.bitbucket.com # apiBaseUrl: server.bitbucket.com diff --git a/docs-ui/package.json b/docs-ui/package.json index d6dcb4830a..2f17987107 100644 --- a/docs-ui/package.json +++ b/docs-ui/package.json @@ -38,7 +38,7 @@ "react": "19.1.1", "react-dom": "19.1.1", "shiki": "^3.13.0", - "storybook": "^8.6.12" + "storybook": "^8.6.15" }, "devDependencies": { "@octokit/rest": "^22.0.1", diff --git a/docs-ui/public/theme-backstage.css b/docs-ui/public/theme-backstage.css index 59a5b986be..9b59448c11 100644 --- a/docs-ui/public/theme-backstage.css +++ b/docs-ui/public/theme-backstage.css @@ -1 +1 @@ -@layer tokens{:root{--bui-font-regular:system-ui;--bui-font-monospace:ui-monospace,"Menlo","Monaco","Consolas","Liberation Mono","Courier New",monospace;--bui-font-weight-regular:400;--bui-font-weight-bold:600;--bui-font-size-1:.625rem;--bui-font-size-2:.75rem;--bui-font-size-3:.875rem;--bui-font-size-4:1rem;--bui-font-size-5:1.25rem;--bui-font-size-6:1.5rem;--bui-font-size-7:2rem;--bui-font-size-8:3rem;--bui-font-size-9:4rem;--bui-font-size-10:5.75rem;--bui-space:.25rem;--bui-space-0_5:calc(var(--bui-space)*.5);--bui-space-1:var(--bui-space);--bui-space-1_5:calc(var(--bui-space)*1.5);--bui-space-2:calc(var(--bui-space)*2);--bui-space-3:calc(var(--bui-space)*3);--bui-space-4:calc(var(--bui-space)*4);--bui-space-5:calc(var(--bui-space)*5);--bui-space-6:calc(var(--bui-space)*6);--bui-space-7:calc(var(--bui-space)*7);--bui-space-8:calc(var(--bui-space)*8);--bui-space-9:calc(var(--bui-space)*9);--bui-space-10:calc(var(--bui-space)*10);--bui-space-11:calc(var(--bui-space)*11);--bui-space-12:calc(var(--bui-space)*12);--bui-space-13:calc(var(--bui-space)*13);--bui-space-14:calc(var(--bui-space)*14);--bui-radius-1:calc(.125rem);--bui-radius-2:calc(.25rem);--bui-radius-3:calc(.5rem);--bui-radius-4:calc(.75rem);--bui-radius-5:calc(1rem);--bui-radius-6:calc(1.25rem);--bui-radius-full:9999px;--bui-black:#000;--bui-white:#fff;--bui-gray-1:#f8f8f8;--bui-gray-2:#ececec;--bui-gray-3:#d9d9d9;--bui-gray-4:#c1c1c1;--bui-gray-5:#9e9e9e;--bui-gray-6:#8c8c8c;--bui-gray-7:#757575;--bui-gray-8:#595959;--bui-bg:var(--bui-gray-1);--bui-bg-surface-1:var(--bui-white);--bui-bg-surface-2:var(--bui-gray-2);--bui-bg-solid:#1f5493;--bui-bg-solid-hover:#163a66;--bui-bg-solid-pressed:#0f2b4e;--bui-bg-solid-disabled:#ebebeb;--bui-bg-tint:transparent;--bui-bg-tint-hover:#1f549366;--bui-bg-tint-pressed:#1f549399;--bui-bg-tint-disabled:#ebebeb;--bui-bg-danger:#feebe7;--bui-bg-warning:#fff2b2;--bui-bg-success:#e6f6eb;--bui-fg-primary:var(--bui-black);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:#1f5493;--bui-fg-link-hover:#1f2d5c;--bui-fg-disabled:#9e9e9e;--bui-fg-solid:var(--bui-white);--bui-fg-solid-disabled:#9c9c9c;--bui-fg-tint:#1f5493;--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:#0000001a;--bui-border-hover:#0003;--bui-border-pressed:#0006;--bui-border-disabled:#0000001a;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#1f5493;--bui-scrollbar:#a0a0a03b;--bui-scrollbar-thumb:#a0a0a0;--bui-animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite}[data-theme-mode=dark]{--bui-gray-1:#191919;--bui-gray-2:#242424;--bui-gray-3:#373737;--bui-gray-4:#464646;--bui-gray-5:#575757;--bui-gray-6:#7b7b7b;--bui-gray-7:#9e9e9e;--bui-gray-8:#b4b4b4;--bui-bg:#333;--bui-bg-surface-1:#424242;--bui-bg-surface-2:var(--bui-gray-2);--bui-bg-solid:#9cc9ff;--bui-bg-solid-hover:#83b9fd;--bui-bg-solid-pressed:#83b9fd;--bui-bg-solid-disabled:#222;--bui-bg-tint:transparent;--bui-bg-tint-hover:#9cc9ff1f;--bui-bg-tint-pressed:#9cc9ff29;--bui-bg-tint-disabled:transparent;--bui-bg-danger:#3b1219;--bui-bg-warning:#302008;--bui-bg-success:#132d21;--bui-fg-primary:var(--bui-white);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:#9cc9ff;--bui-fg-link-hover:#7eb5f7;--bui-fg-disabled:var(--bui-gray-7);--bui-fg-solid:#101821;--bui-fg-solid-disabled:var(--bui-gray-5);--bui-fg-tint:#9cc9ff;--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:#ffffff1f;--bui-border-hover:#fff6;--bui-border-pressed:#ffffff80;--bui-border-disabled:#fff3;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#1f5493;--bui-scrollbar:#3636363a;--bui-scrollbar-thumb:#575757}}@layer base{*,:before,:after{box-sizing:border-box}html{-webkit-text-size-adjust:100%;tab-size:4;font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;line-height:1.15}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentColor}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}:where(a){color:inherit;text-decoration:none}@keyframes pulse{50%{opacity:.5}}body{background-color:var(--bui-bg);color:var(--bui-fg-primary);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);font-size:var(--bui-font-size-3);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}}@layer components;@layer utilities{.bui-p{padding:var(--p)}.bui-p-0\.5{padding:var(--bui-space-0_5)}.bui-p-1{padding:var(--bui-space-1)}.bui-p-1\.5{padding:var(--bui-space-1_5)}.bui-p-2{padding:var(--bui-space-2)}.bui-p-3{padding:var(--bui-space-3)}.bui-p-4{padding:var(--bui-space-4)}.bui-p-5{padding:var(--bui-space-5)}.bui-p-6{padding:var(--bui-space-6)}.bui-p-7{padding:var(--bui-space-7)}.bui-p-8{padding:var(--bui-space-8)}.bui-p-9{padding:var(--bui-space-9)}.bui-p-10{padding:var(--bui-space-10)}.bui-p-11{padding:var(--bui-space-11)}.bui-p-12{padding:var(--bui-space-12)}.bui-p-13{padding:var(--bui-space-13)}.bui-p-14{padding:var(--bui-space-14)}@media (width>=640px){.xs\:bui-p{padding:var(--p-xs)}.xs\:bui-p-0\.5{padding:var(--bui-space-0_5)}.xs\:bui-p-1{padding:var(--bui-space-1)}.xs\:bui-p-1\.5{padding:var(--bui-space-1_5)}.xs\:bui-p-2{padding:var(--bui-space-2)}.xs\:bui-p-3{padding:var(--bui-space-3)}.xs\:bui-p-4{padding:var(--bui-space-4)}.xs\:bui-p-5{padding:var(--bui-space-5)}.xs\:bui-p-6{padding:var(--bui-space-6)}.xs\:bui-p-7{padding:var(--bui-space-7)}.xs\:bui-p-8{padding:var(--bui-space-8)}.xs\:bui-p-9{padding:var(--bui-space-9)}.xs\:bui-p-10{padding:var(--bui-space-10)}.xs\:bui-p-11{padding:var(--bui-space-11)}.xs\:bui-p-12{padding:var(--bui-space-12)}.xs\:bui-p-13{padding:var(--bui-space-13)}.xs\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-p{padding:var(--p-sm)}.sm\:bui-p-0\.5{padding:var(--bui-space-0_5)}.sm\:bui-p-1{padding:var(--bui-space-1)}.sm\:bui-p-1\.5{padding:var(--bui-space-1_5)}.sm\:bui-p-2{padding:var(--bui-space-2)}.sm\:bui-p-3{padding:var(--bui-space-3)}.sm\:bui-p-4{padding:var(--bui-space-4)}.sm\:bui-p-5{padding:var(--bui-space-5)}.sm\:bui-p-6{padding:var(--bui-space-6)}.sm\:bui-p-7{padding:var(--bui-space-7)}.sm\:bui-p-8{padding:var(--bui-space-8)}.sm\:bui-p-9{padding:var(--bui-space-9)}.sm\:bui-p-10{padding:var(--bui-space-10)}.sm\:bui-p-11{padding:var(--bui-space-11)}.sm\:bui-p-12{padding:var(--bui-space-12)}.sm\:bui-p-13{padding:var(--bui-space-13)}.sm\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-p{padding:var(--p-md)}.md\:bui-p-0\.5{padding:var(--bui-space-0_5)}.md\:bui-p-1{padding:var(--bui-space-1)}.md\:bui-p-1\.5{padding:var(--bui-space-1_5)}.md\:bui-p-2{padding:var(--bui-space-2)}.md\:bui-p-3{padding:var(--bui-space-3)}.md\:bui-p-4{padding:var(--bui-space-4)}.md\:bui-p-5{padding:var(--bui-space-5)}.md\:bui-p-6{padding:var(--bui-space-6)}.md\:bui-p-7{padding:var(--bui-space-7)}.md\:bui-p-8{padding:var(--bui-space-8)}.md\:bui-p-9{padding:var(--bui-space-9)}.md\:bui-p-10{padding:var(--bui-space-10)}.md\:bui-p-11{padding:var(--bui-space-11)}.md\:bui-p-12{padding:var(--bui-space-12)}.md\:bui-p-13{padding:var(--bui-space-13)}.md\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-p{padding:var(--p-lg)}.lg\:bui-p-0\.5{padding:var(--bui-space-0_5)}.lg\:bui-p-1{padding:var(--bui-space-1)}.lg\:bui-p-1\.5{padding:var(--bui-space-1_5)}.lg\:bui-p-2{padding:var(--bui-space-2)}.lg\:bui-p-3{padding:var(--bui-space-3)}.lg\:bui-p-4{padding:var(--bui-space-4)}.lg\:bui-p-5{padding:var(--bui-space-5)}.lg\:bui-p-6{padding:var(--bui-space-6)}.lg\:bui-p-7{padding:var(--bui-space-7)}.lg\:bui-p-8{padding:var(--bui-space-8)}.lg\:bui-p-9{padding:var(--bui-space-9)}.lg\:bui-p-10{padding:var(--bui-space-10)}.lg\:bui-p-11{padding:var(--bui-space-11)}.lg\:bui-p-12{padding:var(--bui-space-12)}.lg\:bui-p-13{padding:var(--bui-space-13)}.lg\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-p{padding:var(--p-xl)}.xl\:bui-p-0\.5{padding:var(--bui-space-0_5)}.xl\:bui-p-1{padding:var(--bui-space-1)}.xl\:bui-p-1\.5{padding:var(--bui-space-1_5)}.xl\:bui-p-2{padding:var(--bui-space-2)}.xl\:bui-p-3{padding:var(--bui-space-3)}.xl\:bui-p-4{padding:var(--bui-space-4)}.xl\:bui-p-5{padding:var(--bui-space-5)}.xl\:bui-p-6{padding:var(--bui-space-6)}.xl\:bui-p-7{padding:var(--bui-space-7)}.xl\:bui-p-8{padding:var(--bui-space-8)}.xl\:bui-p-9{padding:var(--bui-space-9)}.xl\:bui-p-10{padding:var(--bui-space-10)}.xl\:bui-p-11{padding:var(--bui-space-11)}.xl\:bui-p-12{padding:var(--bui-space-12)}.xl\:bui-p-13{padding:var(--bui-space-13)}.xl\:bui-p-14{padding:var(--bui-space-14)}}.bui-pl{padding-left:var(--pl)}.bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.bui-pl-1{padding-left:var(--bui-space-1)}.bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.bui-pl-2{padding-left:var(--bui-space-2)}.bui-pl-3{padding-left:var(--bui-space-3)}.bui-pl-4{padding-left:var(--bui-space-4)}.bui-pl-5{padding-left:var(--bui-space-5)}.bui-pl-6{padding-left:var(--bui-space-6)}.bui-pl-7{padding-left:var(--bui-space-7)}.bui-pl-8{padding-left:var(--bui-space-8)}.bui-pl-9{padding-left:var(--bui-space-9)}.bui-pl-10{padding-left:var(--bui-space-10)}.bui-pl-11{padding-left:var(--bui-space-11)}.bui-pl-12{padding-left:var(--bui-space-12)}.bui-pl-13{padding-left:var(--bui-space-13)}.bui-pl-14{padding-left:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pl{padding-left:var(--pl-xs)}.xs\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.xs\:bui-pl-1{padding-left:var(--bui-space-1)}.xs\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.xs\:bui-pl-2{padding-left:var(--bui-space-2)}.xs\:bui-pl-3{padding-left:var(--bui-space-3)}.xs\:bui-pl-4{padding-left:var(--bui-space-4)}.xs\:bui-pl-5{padding-left:var(--bui-space-5)}.xs\:bui-pl-6{padding-left:var(--bui-space-6)}.xs\:bui-pl-7{padding-left:var(--bui-space-7)}.xs\:bui-pl-8{padding-left:var(--bui-space-8)}.xs\:bui-pl-9{padding-left:var(--bui-space-9)}.xs\:bui-pl-10{padding-left:var(--bui-space-10)}.xs\:bui-pl-11{padding-left:var(--bui-space-11)}.xs\:bui-pl-12{padding-left:var(--bui-space-12)}.xs\:bui-pl-13{padding-left:var(--bui-space-13)}.xs\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pl{padding-left:var(--pl-sm)}.sm\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.sm\:bui-pl-1{padding-left:var(--bui-space-1)}.sm\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.sm\:bui-pl-2{padding-left:var(--bui-space-2)}.sm\:bui-pl-3{padding-left:var(--bui-space-3)}.sm\:bui-pl-4{padding-left:var(--bui-space-4)}.sm\:bui-pl-5{padding-left:var(--bui-space-5)}.sm\:bui-pl-6{padding-left:var(--bui-space-6)}.sm\:bui-pl-7{padding-left:var(--bui-space-7)}.sm\:bui-pl-8{padding-left:var(--bui-space-8)}.sm\:bui-pl-9{padding-left:var(--bui-space-9)}.sm\:bui-pl-10{padding-left:var(--bui-space-10)}.sm\:bui-pl-11{padding-left:var(--bui-space-11)}.sm\:bui-pl-12{padding-left:var(--bui-space-12)}.sm\:bui-pl-13{padding-left:var(--bui-space-13)}.sm\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pl{padding-left:var(--pl-md)}.md\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.md\:bui-pl-1{padding-left:var(--bui-space-1)}.md\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.md\:bui-pl-2{padding-left:var(--bui-space-2)}.md\:bui-pl-3{padding-left:var(--bui-space-3)}.md\:bui-pl-4{padding-left:var(--bui-space-4)}.md\:bui-pl-5{padding-left:var(--bui-space-5)}.md\:bui-pl-6{padding-left:var(--bui-space-6)}.md\:bui-pl-7{padding-left:var(--bui-space-7)}.md\:bui-pl-8{padding-left:var(--bui-space-8)}.md\:bui-pl-9{padding-left:var(--bui-space-9)}.md\:bui-pl-10{padding-left:var(--bui-space-10)}.md\:bui-pl-11{padding-left:var(--bui-space-11)}.md\:bui-pl-12{padding-left:var(--bui-space-12)}.md\:bui-pl-13{padding-left:var(--bui-space-13)}.md\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pl{padding-left:var(--pl-lg)}.lg\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.lg\:bui-pl-1{padding-left:var(--bui-space-1)}.lg\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.lg\:bui-pl-2{padding-left:var(--bui-space-2)}.lg\:bui-pl-3{padding-left:var(--bui-space-3)}.lg\:bui-pl-4{padding-left:var(--bui-space-4)}.lg\:bui-pl-5{padding-left:var(--bui-space-5)}.lg\:bui-pl-6{padding-left:var(--bui-space-6)}.lg\:bui-pl-7{padding-left:var(--bui-space-7)}.lg\:bui-pl-8{padding-left:var(--bui-space-8)}.lg\:bui-pl-9{padding-left:var(--bui-space-9)}.lg\:bui-pl-10{padding-left:var(--bui-space-10)}.lg\:bui-pl-11{padding-left:var(--bui-space-11)}.lg\:bui-pl-12{padding-left:var(--bui-space-12)}.lg\:bui-pl-13{padding-left:var(--bui-space-13)}.lg\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pl{padding-left:var(--pl-xl)}.xl\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.xl\:bui-pl-1{padding-left:var(--bui-space-1)}.xl\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.xl\:bui-pl-2{padding-left:var(--bui-space-2)}.xl\:bui-pl-3{padding-left:var(--bui-space-3)}.xl\:bui-pl-4{padding-left:var(--bui-space-4)}.xl\:bui-pl-5{padding-left:var(--bui-space-5)}.xl\:bui-pl-6{padding-left:var(--bui-space-6)}.xl\:bui-pl-7{padding-left:var(--bui-space-7)}.xl\:bui-pl-8{padding-left:var(--bui-space-8)}.xl\:bui-pl-9{padding-left:var(--bui-space-9)}.xl\:bui-pl-10{padding-left:var(--bui-space-10)}.xl\:bui-pl-11{padding-left:var(--bui-space-11)}.xl\:bui-pl-12{padding-left:var(--bui-space-12)}.xl\:bui-pl-13{padding-left:var(--bui-space-13)}.xl\:bui-pl-14{padding-left:var(--bui-space-14)}}.bui-pr{padding-right:var(--pr)}.bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.bui-pr-1{padding-right:var(--bui-space-1)}.bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.bui-pr-2{padding-right:var(--bui-space-2)}.bui-pr-3{padding-right:var(--bui-space-3)}.bui-pr-4{padding-right:var(--bui-space-4)}.bui-pr-5{padding-right:var(--bui-space-5)}.bui-pr-6{padding-right:var(--bui-space-6)}.bui-pr-7{padding-right:var(--bui-space-7)}.bui-pr-8{padding-right:var(--bui-space-8)}.bui-pr-9{padding-right:var(--bui-space-9)}.bui-pr-10{padding-right:var(--bui-space-10)}.bui-pr-11{padding-right:var(--bui-space-11)}.bui-pr-12{padding-right:var(--bui-space-12)}.bui-pr-13{padding-right:var(--bui-space-13)}.bui-pr-14{padding-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pr{padding-right:var(--pr-xs)}.xs\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.xs\:bui-pr-1{padding-right:var(--bui-space-1)}.xs\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.xs\:bui-pr-2{padding-right:var(--bui-space-2)}.xs\:bui-pr-3{padding-right:var(--bui-space-3)}.xs\:bui-pr-4{padding-right:var(--bui-space-4)}.xs\:bui-pr-5{padding-right:var(--bui-space-5)}.xs\:bui-pr-6{padding-right:var(--bui-space-6)}.xs\:bui-pr-7{padding-right:var(--bui-space-7)}.xs\:bui-pr-8{padding-right:var(--bui-space-8)}.xs\:bui-pr-9{padding-right:var(--bui-space-9)}.xs\:bui-pr-10{padding-right:var(--bui-space-10)}.xs\:bui-pr-11{padding-right:var(--bui-space-11)}.xs\:bui-pr-12{padding-right:var(--bui-space-12)}.xs\:bui-pr-13{padding-right:var(--bui-space-13)}.xs\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pr{padding-right:var(--pr-sm)}.sm\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.sm\:bui-pr-1{padding-right:var(--bui-space-1)}.sm\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.sm\:bui-pr-2{padding-right:var(--bui-space-2)}.sm\:bui-pr-3{padding-right:var(--bui-space-3)}.sm\:bui-pr-4{padding-right:var(--bui-space-4)}.sm\:bui-pr-5{padding-right:var(--bui-space-5)}.sm\:bui-pr-6{padding-right:var(--bui-space-6)}.sm\:bui-pr-7{padding-right:var(--bui-space-7)}.sm\:bui-pr-8{padding-right:var(--bui-space-8)}.sm\:bui-pr-9{padding-right:var(--bui-space-9)}.sm\:bui-pr-10{padding-right:var(--bui-space-10)}.sm\:bui-pr-11{padding-right:var(--bui-space-11)}.sm\:bui-pr-12{padding-right:var(--bui-space-12)}.sm\:bui-pr-13{padding-right:var(--bui-space-13)}.sm\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pr{padding-right:var(--pr-md)}.md\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.md\:bui-pr-1{padding-right:var(--bui-space-1)}.md\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.md\:bui-pr-2{padding-right:var(--bui-space-2)}.md\:bui-pr-3{padding-right:var(--bui-space-3)}.md\:bui-pr-4{padding-right:var(--bui-space-4)}.md\:bui-pr-5{padding-right:var(--bui-space-5)}.md\:bui-pr-6{padding-right:var(--bui-space-6)}.md\:bui-pr-7{padding-right:var(--bui-space-7)}.md\:bui-pr-8{padding-right:var(--bui-space-8)}.md\:bui-pr-9{padding-right:var(--bui-space-9)}.md\:bui-pr-10{padding-right:var(--bui-space-10)}.md\:bui-pr-11{padding-right:var(--bui-space-11)}.md\:bui-pr-12{padding-right:var(--bui-space-12)}.md\:bui-pr-13{padding-right:var(--bui-space-13)}.md\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pr{padding-right:var(--pr-lg)}.lg\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.lg\:bui-pr-1{padding-right:var(--bui-space-1)}.lg\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.lg\:bui-pr-2{padding-right:var(--bui-space-2)}.lg\:bui-pr-3{padding-right:var(--bui-space-3)}.lg\:bui-pr-4{padding-right:var(--bui-space-4)}.lg\:bui-pr-5{padding-right:var(--bui-space-5)}.lg\:bui-pr-6{padding-right:var(--bui-space-6)}.lg\:bui-pr-7{padding-right:var(--bui-space-7)}.lg\:bui-pr-8{padding-right:var(--bui-space-8)}.lg\:bui-pr-9{padding-right:var(--bui-space-9)}.lg\:bui-pr-10{padding-right:var(--bui-space-10)}.lg\:bui-pr-11{padding-right:var(--bui-space-11)}.lg\:bui-pr-12{padding-right:var(--bui-space-12)}.lg\:bui-pr-13{padding-right:var(--bui-space-13)}.lg\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pr{padding-right:var(--pr-xl)}.xl\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.xl\:bui-pr-1{padding-right:var(--bui-space-1)}.xl\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.xl\:bui-pr-2{padding-right:var(--bui-space-2)}.xl\:bui-pr-3{padding-right:var(--bui-space-3)}.xl\:bui-pr-4{padding-right:var(--bui-space-4)}.xl\:bui-pr-5{padding-right:var(--bui-space-5)}.xl\:bui-pr-6{padding-right:var(--bui-space-6)}.xl\:bui-pr-7{padding-right:var(--bui-space-7)}.xl\:bui-pr-8{padding-right:var(--bui-space-8)}.xl\:bui-pr-9{padding-right:var(--bui-space-9)}.xl\:bui-pr-10{padding-right:var(--bui-space-10)}.xl\:bui-pr-11{padding-right:var(--bui-space-11)}.xl\:bui-pr-12{padding-right:var(--bui-space-12)}.xl\:bui-pr-13{padding-right:var(--bui-space-13)}.xl\:bui-pr-14{padding-right:var(--bui-space-14)}}.bui-pt{padding-top:var(--pt)}.bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.bui-pt-1{padding-top:var(--bui-space-1)}.bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.bui-pt-2{padding-top:var(--bui-space-2)}.bui-pt-3{padding-top:var(--bui-space-3)}.bui-pt-4{padding-top:var(--bui-space-4)}.bui-pt-5{padding-top:var(--bui-space-5)}.bui-pt-6{padding-top:var(--bui-space-6)}.bui-pt-7{padding-top:var(--bui-space-7)}.bui-pt-8{padding-top:var(--bui-space-8)}.bui-pt-9{padding-top:var(--bui-space-9)}.bui-pt-10{padding-top:var(--bui-space-10)}.bui-pt-11{padding-top:var(--bui-space-11)}.bui-pt-12{padding-top:var(--bui-space-12)}.bui-pt-13{padding-top:var(--bui-space-13)}.bui-pt-14{padding-top:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pt{padding-top:var(--pt-xs)}.xs\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.xs\:bui-pt-1{padding-top:var(--bui-space-1)}.xs\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.xs\:bui-pt-2{padding-top:var(--bui-space-2)}.xs\:bui-pt-3{padding-top:var(--bui-space-3)}.xs\:bui-pt-4{padding-top:var(--bui-space-4)}.xs\:bui-pt-5{padding-top:var(--bui-space-5)}.xs\:bui-pt-6{padding-top:var(--bui-space-6)}.xs\:bui-pt-7{padding-top:var(--bui-space-7)}.xs\:bui-pt-8{padding-top:var(--bui-space-8)}.xs\:bui-pt-9{padding-top:var(--bui-space-9)}.xs\:bui-pt-10{padding-top:var(--bui-space-10)}.xs\:bui-pt-11{padding-top:var(--bui-space-11)}.xs\:bui-pt-12{padding-top:var(--bui-space-12)}.xs\:bui-pt-13{padding-top:var(--bui-space-13)}.xs\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pt{padding-top:var(--pt-sm)}.sm\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.sm\:bui-pt-1{padding-top:var(--bui-space-1)}.sm\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.sm\:bui-pt-2{padding-top:var(--bui-space-2)}.sm\:bui-pt-3{padding-top:var(--bui-space-3)}.sm\:bui-pt-4{padding-top:var(--bui-space-4)}.sm\:bui-pt-5{padding-top:var(--bui-space-5)}.sm\:bui-pt-6{padding-top:var(--bui-space-6)}.sm\:bui-pt-7{padding-top:var(--bui-space-7)}.sm\:bui-pt-8{padding-top:var(--bui-space-8)}.sm\:bui-pt-9{padding-top:var(--bui-space-9)}.sm\:bui-pt-10{padding-top:var(--bui-space-10)}.sm\:bui-pt-11{padding-top:var(--bui-space-11)}.sm\:bui-pt-12{padding-top:var(--bui-space-12)}.sm\:bui-pt-13{padding-top:var(--bui-space-13)}.sm\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pt{padding-top:var(--pt-md)}.md\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.md\:bui-pt-1{padding-top:var(--bui-space-1)}.md\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.md\:bui-pt-2{padding-top:var(--bui-space-2)}.md\:bui-pt-3{padding-top:var(--bui-space-3)}.md\:bui-pt-4{padding-top:var(--bui-space-4)}.md\:bui-pt-5{padding-top:var(--bui-space-5)}.md\:bui-pt-6{padding-top:var(--bui-space-6)}.md\:bui-pt-7{padding-top:var(--bui-space-7)}.md\:bui-pt-8{padding-top:var(--bui-space-8)}.md\:bui-pt-9{padding-top:var(--bui-space-9)}.md\:bui-pt-10{padding-top:var(--bui-space-10)}.md\:bui-pt-11{padding-top:var(--bui-space-11)}.md\:bui-pt-12{padding-top:var(--bui-space-12)}.md\:bui-pt-13{padding-top:var(--bui-space-13)}.md\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pt{padding-top:var(--pt-lg)}.lg\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.lg\:bui-pt-1{padding-top:var(--bui-space-1)}.lg\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.lg\:bui-pt-2{padding-top:var(--bui-space-2)}.lg\:bui-pt-3{padding-top:var(--bui-space-3)}.lg\:bui-pt-4{padding-top:var(--bui-space-4)}.lg\:bui-pt-5{padding-top:var(--bui-space-5)}.lg\:bui-pt-6{padding-top:var(--bui-space-6)}.lg\:bui-pt-7{padding-top:var(--bui-space-7)}.lg\:bui-pt-8{padding-top:var(--bui-space-8)}.lg\:bui-pt-9{padding-top:var(--bui-space-9)}.lg\:bui-pt-10{padding-top:var(--bui-space-10)}.lg\:bui-pt-11{padding-top:var(--bui-space-11)}.lg\:bui-pt-12{padding-top:var(--bui-space-12)}.lg\:bui-pt-13{padding-top:var(--bui-space-13)}.lg\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pt{padding-top:var(--pt-xl)}.xl\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.xl\:bui-pt-1{padding-top:var(--bui-space-1)}.xl\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.xl\:bui-pt-2{padding-top:var(--bui-space-2)}.xl\:bui-pt-3{padding-top:var(--bui-space-3)}.xl\:bui-pt-4{padding-top:var(--bui-space-4)}.xl\:bui-pt-5{padding-top:var(--bui-space-5)}.xl\:bui-pt-6{padding-top:var(--bui-space-6)}.xl\:bui-pt-7{padding-top:var(--bui-space-7)}.xl\:bui-pt-8{padding-top:var(--bui-space-8)}.xl\:bui-pt-9{padding-top:var(--bui-space-9)}.xl\:bui-pt-10{padding-top:var(--bui-space-10)}.xl\:bui-pt-11{padding-top:var(--bui-space-11)}.xl\:bui-pt-12{padding-top:var(--bui-space-12)}.xl\:bui-pt-13{padding-top:var(--bui-space-13)}.xl\:bui-pt-14{padding-top:var(--bui-space-14)}}.bui-pb{padding-bottom:var(--pb)}.bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.bui-pb-1{padding-bottom:var(--bui-space-1)}.bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.bui-pb-2{padding-bottom:var(--bui-space-2)}.bui-pb-3{padding-bottom:var(--bui-space-3)}.bui-pb-4{padding-bottom:var(--bui-space-4)}.bui-pb-5{padding-bottom:var(--bui-space-5)}.bui-pb-6{padding-bottom:var(--bui-space-6)}.bui-pb-7{padding-bottom:var(--bui-space-7)}.bui-pb-8{padding-bottom:var(--bui-space-8)}.bui-pb-9{padding-bottom:var(--bui-space-9)}.bui-pb-10{padding-bottom:var(--bui-space-10)}.bui-pb-11{padding-bottom:var(--bui-space-11)}.bui-pb-12{padding-bottom:var(--bui-space-12)}.bui-pb-13{padding-bottom:var(--bui-space-13)}.bui-pb-14{padding-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pb{padding-bottom:var(--pb-xs)}.xs\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.xs\:bui-pb-1{padding-bottom:var(--bui-space-1)}.xs\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.xs\:bui-pb-2{padding-bottom:var(--bui-space-2)}.xs\:bui-pb-3{padding-bottom:var(--bui-space-3)}.xs\:bui-pb-4{padding-bottom:var(--bui-space-4)}.xs\:bui-pb-5{padding-bottom:var(--bui-space-5)}.xs\:bui-pb-6{padding-bottom:var(--bui-space-6)}.xs\:bui-pb-7{padding-bottom:var(--bui-space-7)}.xs\:bui-pb-8{padding-bottom:var(--bui-space-8)}.xs\:bui-pb-9{padding-bottom:var(--bui-space-9)}.xs\:bui-pb-10{padding-bottom:var(--bui-space-10)}.xs\:bui-pb-11{padding-bottom:var(--bui-space-11)}.xs\:bui-pb-12{padding-bottom:var(--bui-space-12)}.xs\:bui-pb-13{padding-bottom:var(--bui-space-13)}.xs\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pb{padding-bottom:var(--pb-sm)}.sm\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.sm\:bui-pb-1{padding-bottom:var(--bui-space-1)}.sm\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.sm\:bui-pb-2{padding-bottom:var(--bui-space-2)}.sm\:bui-pb-3{padding-bottom:var(--bui-space-3)}.sm\:bui-pb-4{padding-bottom:var(--bui-space-4)}.sm\:bui-pb-5{padding-bottom:var(--bui-space-5)}.sm\:bui-pb-6{padding-bottom:var(--bui-space-6)}.sm\:bui-pb-7{padding-bottom:var(--bui-space-7)}.sm\:bui-pb-8{padding-bottom:var(--bui-space-8)}.sm\:bui-pb-9{padding-bottom:var(--bui-space-9)}.sm\:bui-pb-10{padding-bottom:var(--bui-space-10)}.sm\:bui-pb-11{padding-bottom:var(--bui-space-11)}.sm\:bui-pb-12{padding-bottom:var(--bui-space-12)}.sm\:bui-pb-13{padding-bottom:var(--bui-space-13)}.sm\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pb{padding-bottom:var(--pb-md)}.md\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.md\:bui-pb-1{padding-bottom:var(--bui-space-1)}.md\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.md\:bui-pb-2{padding-bottom:var(--bui-space-2)}.md\:bui-pb-3{padding-bottom:var(--bui-space-3)}.md\:bui-pb-4{padding-bottom:var(--bui-space-4)}.md\:bui-pb-5{padding-bottom:var(--bui-space-5)}.md\:bui-pb-6{padding-bottom:var(--bui-space-6)}.md\:bui-pb-7{padding-bottom:var(--bui-space-7)}.md\:bui-pb-8{padding-bottom:var(--bui-space-8)}.md\:bui-pb-9{padding-bottom:var(--bui-space-9)}.md\:bui-pb-10{padding-bottom:var(--bui-space-10)}.md\:bui-pb-11{padding-bottom:var(--bui-space-11)}.md\:bui-pb-12{padding-bottom:var(--bui-space-12)}.md\:bui-pb-13{padding-bottom:var(--bui-space-13)}.md\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pb{padding-bottom:var(--pb-lg)}.lg\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.lg\:bui-pb-1{padding-bottom:var(--bui-space-1)}.lg\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.lg\:bui-pb-2{padding-bottom:var(--bui-space-2)}.lg\:bui-pb-3{padding-bottom:var(--bui-space-3)}.lg\:bui-pb-4{padding-bottom:var(--bui-space-4)}.lg\:bui-pb-5{padding-bottom:var(--bui-space-5)}.lg\:bui-pb-6{padding-bottom:var(--bui-space-6)}.lg\:bui-pb-7{padding-bottom:var(--bui-space-7)}.lg\:bui-pb-8{padding-bottom:var(--bui-space-8)}.lg\:bui-pb-9{padding-bottom:var(--bui-space-9)}.lg\:bui-pb-10{padding-bottom:var(--bui-space-10)}.lg\:bui-pb-11{padding-bottom:var(--bui-space-11)}.lg\:bui-pb-12{padding-bottom:var(--bui-space-12)}.lg\:bui-pb-13{padding-bottom:var(--bui-space-13)}.lg\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pb{padding-bottom:var(--pb-xl)}.xl\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.xl\:bui-pb-1{padding-bottom:var(--bui-space-1)}.xl\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.xl\:bui-pb-2{padding-bottom:var(--bui-space-2)}.xl\:bui-pb-3{padding-bottom:var(--bui-space-3)}.xl\:bui-pb-4{padding-bottom:var(--bui-space-4)}.xl\:bui-pb-5{padding-bottom:var(--bui-space-5)}.xl\:bui-pb-6{padding-bottom:var(--bui-space-6)}.xl\:bui-pb-7{padding-bottom:var(--bui-space-7)}.xl\:bui-pb-8{padding-bottom:var(--bui-space-8)}.xl\:bui-pb-9{padding-bottom:var(--bui-space-9)}.xl\:bui-pb-10{padding-bottom:var(--bui-space-10)}.xl\:bui-pb-11{padding-bottom:var(--bui-space-11)}.xl\:bui-pb-12{padding-bottom:var(--bui-space-12)}.xl\:bui-pb-13{padding-bottom:var(--bui-space-13)}.xl\:bui-pb-14{padding-bottom:var(--bui-space-14)}}.bui-py{padding-top:var(--py);padding-bottom:var(--py)}.bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-py{padding-top:var(--py-xs);padding-bottom:var(--py-xs)}.xs\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.xs\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.xs\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.xs\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.xs\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.xs\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.xs\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.xs\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.xs\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.xs\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.xs\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.xs\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.xs\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.xs\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.xs\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.xs\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-py{padding-top:var(--py-sm);padding-bottom:var(--py-sm)}.sm\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.sm\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.sm\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.sm\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.sm\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.sm\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.sm\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.sm\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.sm\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.sm\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.sm\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.sm\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.sm\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.sm\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.sm\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.sm\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-py{padding-top:var(--py-md);padding-bottom:var(--py-md)}.md\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.md\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.md\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.md\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.md\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.md\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.md\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.md\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.md\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.md\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.md\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.md\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.md\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.md\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.md\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.md\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-py{padding-top:var(--py-lg);padding-bottom:var(--py-lg)}.lg\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.lg\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.lg\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.lg\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.lg\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.lg\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.lg\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.lg\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.lg\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.lg\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.lg\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.lg\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.lg\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.lg\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.lg\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.lg\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-py{padding-top:var(--py-xl);padding-bottom:var(--py-xl)}.xl\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.xl\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.xl\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.xl\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.xl\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.xl\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.xl\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.xl\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.xl\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.xl\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.xl\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.xl\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.xl\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.xl\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.xl\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.xl\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}.bui-px{padding-left:var(--px);padding-right:var(--px)}.bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-px{padding-left:var(--px-xs);padding-right:var(--px-xs)}.xs\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.xs\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.xs\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.xs\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.xs\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.xs\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.xs\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.xs\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.xs\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.xs\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.xs\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.xs\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.xs\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.xs\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.xs\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.xs\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-px{padding-left:var(--px-sm);padding-right:var(--px-sm)}.sm\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.sm\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.sm\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.sm\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.sm\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.sm\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.sm\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.sm\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.sm\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.sm\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.sm\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.sm\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.sm\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.sm\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.sm\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.sm\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-px{padding-left:var(--px-md);padding-right:var(--px-md)}.md\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.md\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.md\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.md\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.md\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.md\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.md\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.md\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.md\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.md\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.md\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.md\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.md\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.md\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.md\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.md\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-px{padding-left:var(--px-lg);padding-right:var(--px-lg)}.lg\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.lg\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.lg\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.lg\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.lg\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.lg\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.lg\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.lg\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.lg\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.lg\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.lg\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.lg\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.lg\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.lg\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.lg\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.lg\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-px{padding-left:var(--px-xl);padding-right:var(--px-xl)}.xl\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.xl\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.xl\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.xl\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.xl\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.xl\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.xl\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.xl\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.xl\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.xl\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.xl\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.xl\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.xl\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.xl\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.xl\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.xl\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}.bui-m{margin:var(--m)}.bui-m-0\.5{margin:var(--bui-space-0_5)}.bui-m-1{margin:var(--bui-space-1)}.bui-m-1\.5{margin:var(--bui-space-1_5)}.bui-m-2{margin:var(--bui-space-2)}.bui-m-3{margin:var(--bui-space-3)}.bui-m-4{margin:var(--bui-space-4)}.bui-m-5{margin:var(--bui-space-5)}.bui-m-6{margin:var(--bui-space-6)}.bui-m-7{margin:var(--bui-space-7)}.bui-m-8{margin:var(--bui-space-8)}.bui-m-9{margin:var(--bui-space-9)}.bui-m-10{margin:var(--bui-space-10)}.bui-m-11{margin:var(--bui-space-11)}.bui-m-12{margin:var(--bui-space-12)}.bui-m-13{margin:var(--bui-space-13)}.bui-m-14{margin:var(--bui-space-14)}@media (width>=640px){.xs\:bui-m{margin:var(--p-xs)}.xs\:bui-m-0\.5{margin:var(--bui-space-0_5)}.xs\:bui-m-1{margin:var(--bui-space-1)}.xs\:bui-m-1\.5{margin:var(--bui-space-1_5)}.xs\:bui-m-2{margin:var(--bui-space-2)}.xs\:bui-m-3{margin:var(--bui-space-3)}.xs\:bui-m-4{margin:var(--bui-space-4)}.xs\:bui-m-5{margin:var(--bui-space-5)}.xs\:bui-m-6{margin:var(--bui-space-6)}.xs\:bui-m-7{margin:var(--bui-space-7)}.xs\:bui-m-8{margin:var(--bui-space-8)}.xs\:bui-m-9{margin:var(--bui-space-9)}.xs\:bui-m-10{margin:var(--bui-space-10)}.xs\:bui-m-11{margin:var(--bui-space-11)}.xs\:bui-m-12{margin:var(--bui-space-12)}.xs\:bui-m-13{margin:var(--bui-space-13)}.xs\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-m{margin:var(--p-sm)}.sm\:bui-m-0\.5{margin:var(--bui-space-0_5)}.sm\:bui-m-1{margin:var(--bui-space-1)}.sm\:bui-m-1\.5{margin:var(--bui-space-1_5)}.sm\:bui-m-2{margin:var(--bui-space-2)}.sm\:bui-m-3{margin:var(--bui-space-3)}.sm\:bui-m-4{margin:var(--bui-space-4)}.sm\:bui-m-5{margin:var(--bui-space-5)}.sm\:bui-m-6{margin:var(--bui-space-6)}.sm\:bui-m-7{margin:var(--bui-space-7)}.sm\:bui-m-8{margin:var(--bui-space-8)}.sm\:bui-m-9{margin:var(--bui-space-9)}.sm\:bui-m-10{margin:var(--bui-space-10)}.sm\:bui-m-11{margin:var(--bui-space-11)}.sm\:bui-m-12{margin:var(--bui-space-12)}.sm\:bui-m-13{margin:var(--bui-space-13)}.sm\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-m{margin:var(--p-md)}.md\:bui-m-0\.5{margin:var(--bui-space-0_5)}.md\:bui-m-1{margin:var(--bui-space-1)}.md\:bui-m-1\.5{margin:var(--bui-space-1_5)}.md\:bui-m-2{margin:var(--bui-space-2)}.md\:bui-m-3{margin:var(--bui-space-3)}.md\:bui-m-4{margin:var(--bui-space-4)}.md\:bui-m-5{margin:var(--bui-space-5)}.md\:bui-m-6{margin:var(--bui-space-6)}.md\:bui-m-7{margin:var(--bui-space-7)}.md\:bui-m-8{margin:var(--bui-space-8)}.md\:bui-m-9{margin:var(--bui-space-9)}.md\:bui-m-10{margin:var(--bui-space-10)}.md\:bui-m-11{margin:var(--bui-space-11)}.md\:bui-m-12{margin:var(--bui-space-12)}.md\:bui-m-13{margin:var(--bui-space-13)}.md\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-m{margin:var(--p-lg)}.lg\:bui-m-0\.5{margin:var(--bui-space-0_5)}.lg\:bui-m-1{margin:var(--bui-space-1)}.lg\:bui-m-1\.5{margin:var(--bui-space-1_5)}.lg\:bui-m-2{margin:var(--bui-space-2)}.lg\:bui-m-3{margin:var(--bui-space-3)}.lg\:bui-m-4{margin:var(--bui-space-4)}.lg\:bui-m-5{margin:var(--bui-space-5)}.lg\:bui-m-6{margin:var(--bui-space-6)}.lg\:bui-m-7{margin:var(--bui-space-7)}.lg\:bui-m-8{margin:var(--bui-space-8)}.lg\:bui-m-9{margin:var(--bui-space-9)}.lg\:bui-m-10{margin:var(--bui-space-10)}.lg\:bui-m-11{margin:var(--bui-space-11)}.lg\:bui-m-12{margin:var(--bui-space-12)}.lg\:bui-m-13{margin:var(--bui-space-13)}.lg\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-m{margin:var(--p-xl)}.xl\:bui-m-0\.5{margin:var(--bui-space-0_5)}.xl\:bui-m-1{margin:var(--bui-space-1)}.xl\:bui-m-1\.5{margin:var(--bui-space-1_5)}.xl\:bui-m-2{margin:var(--bui-space-2)}.xl\:bui-m-3{margin:var(--bui-space-3)}.xl\:bui-m-4{margin:var(--bui-space-4)}.xl\:bui-m-5{margin:var(--bui-space-5)}.xl\:bui-m-6{margin:var(--bui-space-6)}.xl\:bui-m-7{margin:var(--bui-space-7)}.xl\:bui-m-8{margin:var(--bui-space-8)}.xl\:bui-m-9{margin:var(--bui-space-9)}.xl\:bui-m-10{margin:var(--bui-space-10)}.xl\:bui-m-11{margin:var(--bui-space-11)}.xl\:bui-m-12{margin:var(--bui-space-12)}.xl\:bui-m-13{margin:var(--bui-space-13)}.xl\:bui-m-14{margin:var(--bui-space-14)}}.bui-ml{margin-left:var(--ml)}.bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.bui-ml-1{margin-left:var(--bui-space-1)}.bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.bui-ml-2{margin-left:var(--bui-space-2)}.bui-ml-3{margin-left:var(--bui-space-3)}.bui-ml-4{margin-left:var(--bui-space-4)}.bui-ml-5{margin-left:var(--bui-space-5)}.bui-ml-6{margin-left:var(--bui-space-6)}.bui-ml-7{margin-left:var(--bui-space-7)}.bui-ml-8{margin-left:var(--bui-space-8)}.bui-ml-9{margin-left:var(--bui-space-9)}.bui-ml-10{margin-left:var(--bui-space-10)}.bui-ml-11{margin-left:var(--bui-space-11)}.bui-ml-12{margin-left:var(--bui-space-12)}.bui-ml-13{margin-left:var(--bui-space-13)}.bui-ml-14{margin-left:var(--bui-space-14)}@media (width>=640px){.xs\:bui-ml{margin-left:var(--ml-xs)}.xs\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.xs\:bui-ml-1{margin-left:var(--bui-space-1)}.xs\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.xs\:bui-ml-2{margin-left:var(--bui-space-2)}.xs\:bui-ml-3{margin-left:var(--bui-space-3)}.xs\:bui-ml-4{margin-left:var(--bui-space-4)}.xs\:bui-ml-5{margin-left:var(--bui-space-5)}.xs\:bui-ml-6{margin-left:var(--bui-space-6)}.xs\:bui-ml-7{margin-left:var(--bui-space-7)}.xs\:bui-ml-8{margin-left:var(--bui-space-8)}.xs\:bui-ml-9{margin-left:var(--bui-space-9)}.xs\:bui-ml-10{margin-left:var(--bui-space-10)}.xs\:bui-ml-11{margin-left:var(--bui-space-11)}.xs\:bui-ml-12{margin-left:var(--bui-space-12)}.xs\:bui-ml-13{margin-left:var(--bui-space-13)}.xs\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-ml{margin-left:var(--ml-sm)}.sm\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.sm\:bui-ml-1{margin-left:var(--bui-space-1)}.sm\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.sm\:bui-ml-2{margin-left:var(--bui-space-2)}.sm\:bui-ml-3{margin-left:var(--bui-space-3)}.sm\:bui-ml-4{margin-left:var(--bui-space-4)}.sm\:bui-ml-5{margin-left:var(--bui-space-5)}.sm\:bui-ml-6{margin-left:var(--bui-space-6)}.sm\:bui-ml-7{margin-left:var(--bui-space-7)}.sm\:bui-ml-8{margin-left:var(--bui-space-8)}.sm\:bui-ml-9{margin-left:var(--bui-space-9)}.sm\:bui-ml-10{margin-left:var(--bui-space-10)}.sm\:bui-ml-11{margin-left:var(--bui-space-11)}.sm\:bui-ml-12{margin-left:var(--bui-space-12)}.sm\:bui-ml-13{margin-left:var(--bui-space-13)}.sm\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-ml{margin-left:var(--ml-md)}.md\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.md\:bui-ml-1{margin-left:var(--bui-space-1)}.md\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.md\:bui-ml-2{margin-left:var(--bui-space-2)}.md\:bui-ml-3{margin-left:var(--bui-space-3)}.md\:bui-ml-4{margin-left:var(--bui-space-4)}.md\:bui-ml-5{margin-left:var(--bui-space-5)}.md\:bui-ml-6{margin-left:var(--bui-space-6)}.md\:bui-ml-7{margin-left:var(--bui-space-7)}.md\:bui-ml-8{margin-left:var(--bui-space-8)}.md\:bui-ml-9{margin-left:var(--bui-space-9)}.md\:bui-ml-10{margin-left:var(--bui-space-10)}.md\:bui-ml-11{margin-left:var(--bui-space-11)}.md\:bui-ml-12{margin-left:var(--bui-space-12)}.md\:bui-ml-13{margin-left:var(--bui-space-13)}.md\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-ml{margin-left:var(--ml-lg)}.lg\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.lg\:bui-ml-1{margin-left:var(--bui-space-1)}.lg\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.lg\:bui-ml-2{margin-left:var(--bui-space-2)}.lg\:bui-ml-3{margin-left:var(--bui-space-3)}.lg\:bui-ml-4{margin-left:var(--bui-space-4)}.lg\:bui-ml-5{margin-left:var(--bui-space-5)}.lg\:bui-ml-6{margin-left:var(--bui-space-6)}.lg\:bui-ml-7{margin-left:var(--bui-space-7)}.lg\:bui-ml-8{margin-left:var(--bui-space-8)}.lg\:bui-ml-9{margin-left:var(--bui-space-9)}.lg\:bui-ml-10{margin-left:var(--bui-space-10)}.lg\:bui-ml-11{margin-left:var(--bui-space-11)}.lg\:bui-ml-12{margin-left:var(--bui-space-12)}.lg\:bui-ml-13{margin-left:var(--bui-space-13)}.lg\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-ml{margin-left:var(--ml-xl)}.xl\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.xl\:bui-ml-1{margin-left:var(--bui-space-1)}.xl\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.xl\:bui-ml-2{margin-left:var(--bui-space-2)}.xl\:bui-ml-3{margin-left:var(--bui-space-3)}.xl\:bui-ml-4{margin-left:var(--bui-space-4)}.xl\:bui-ml-5{margin-left:var(--bui-space-5)}.xl\:bui-ml-6{margin-left:var(--bui-space-6)}.xl\:bui-ml-7{margin-left:var(--bui-space-7)}.xl\:bui-ml-8{margin-left:var(--bui-space-8)}.xl\:bui-ml-9{margin-left:var(--bui-space-9)}.xl\:bui-ml-10{margin-left:var(--bui-space-10)}.xl\:bui-ml-11{margin-left:var(--bui-space-11)}.xl\:bui-ml-12{margin-left:var(--bui-space-12)}.xl\:bui-ml-13{margin-left:var(--bui-space-13)}.xl\:bui-ml-14{margin-left:var(--bui-space-14)}}.bui-mr{margin-right:var(--mr)}.bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.bui-mr-1{margin-right:var(--bui-space-1)}.bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.bui-mr-2{margin-right:var(--bui-space-2)}.bui-mr-3{margin-right:var(--bui-space-3)}.bui-mr-4{margin-right:var(--bui-space-4)}.bui-mr-5{margin-right:var(--bui-space-5)}.bui-mr-6{margin-right:var(--bui-space-6)}.bui-mr-7{margin-right:var(--bui-space-7)}.bui-mr-8{margin-right:var(--bui-space-8)}.bui-mr-9{margin-right:var(--bui-space-9)}.bui-mr-10{margin-right:var(--bui-space-10)}.bui-mr-11{margin-right:var(--bui-space-11)}.bui-mr-12{margin-right:var(--bui-space-12)}.bui-mr-13{margin-right:var(--bui-space-13)}.bui-mr-14{margin-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mr{margin-right:var(--mr-xs)}.xs\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.xs\:bui-mr-1{margin-right:var(--bui-space-1)}.xs\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.xs\:bui-mr-2{margin-right:var(--bui-space-2)}.xs\:bui-mr-3{margin-right:var(--bui-space-3)}.xs\:bui-mr-4{margin-right:var(--bui-space-4)}.xs\:bui-mr-5{margin-right:var(--bui-space-5)}.xs\:bui-mr-6{margin-right:var(--bui-space-6)}.xs\:bui-mr-7{margin-right:var(--bui-space-7)}.xs\:bui-mr-8{margin-right:var(--bui-space-8)}.xs\:bui-mr-9{margin-right:var(--bui-space-9)}.xs\:bui-mr-10{margin-right:var(--bui-space-10)}.xs\:bui-mr-11{margin-right:var(--bui-space-11)}.xs\:bui-mr-12{margin-right:var(--bui-space-12)}.xs\:bui-mr-13{margin-right:var(--bui-space-13)}.xs\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mr{margin-right:var(--mr-sm)}.sm\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.sm\:bui-mr-1{margin-right:var(--bui-space-1)}.sm\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.sm\:bui-mr-2{margin-right:var(--bui-space-2)}.sm\:bui-mr-3{margin-right:var(--bui-space-3)}.sm\:bui-mr-4{margin-right:var(--bui-space-4)}.sm\:bui-mr-5{margin-right:var(--bui-space-5)}.sm\:bui-mr-6{margin-right:var(--bui-space-6)}.sm\:bui-mr-7{margin-right:var(--bui-space-7)}.sm\:bui-mr-8{margin-right:var(--bui-space-8)}.sm\:bui-mr-9{margin-right:var(--bui-space-9)}.sm\:bui-mr-10{margin-right:var(--bui-space-10)}.sm\:bui-mr-11{margin-right:var(--bui-space-11)}.sm\:bui-mr-12{margin-right:var(--bui-space-12)}.sm\:bui-mr-13{margin-right:var(--bui-space-13)}.sm\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mr{margin-right:var(--mr-md)}.md\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.md\:bui-mr-1{margin-right:var(--bui-space-1)}.md\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.md\:bui-mr-2{margin-right:var(--bui-space-2)}.md\:bui-mr-3{margin-right:var(--bui-space-3)}.md\:bui-mr-4{margin-right:var(--bui-space-4)}.md\:bui-mr-5{margin-right:var(--bui-space-5)}.md\:bui-mr-6{margin-right:var(--bui-space-6)}.md\:bui-mr-7{margin-right:var(--bui-space-7)}.md\:bui-mr-8{margin-right:var(--bui-space-8)}.md\:bui-mr-9{margin-right:var(--bui-space-9)}.md\:bui-mr-10{margin-right:var(--bui-space-10)}.md\:bui-mr-11{margin-right:var(--bui-space-11)}.md\:bui-mr-12{margin-right:var(--bui-space-12)}.md\:bui-mr-13{margin-right:var(--bui-space-13)}.md\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mr{margin-right:var(--mr-lg)}.lg\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.lg\:bui-mr-1{margin-right:var(--bui-space-1)}.lg\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.lg\:bui-mr-2{margin-right:var(--bui-space-2)}.lg\:bui-mr-3{margin-right:var(--bui-space-3)}.lg\:bui-mr-4{margin-right:var(--bui-space-4)}.lg\:bui-mr-5{margin-right:var(--bui-space-5)}.lg\:bui-mr-6{margin-right:var(--bui-space-6)}.lg\:bui-mr-7{margin-right:var(--bui-space-7)}.lg\:bui-mr-8{margin-right:var(--bui-space-8)}.lg\:bui-mr-9{margin-right:var(--bui-space-9)}.lg\:bui-mr-10{margin-right:var(--bui-space-10)}.lg\:bui-mr-11{margin-right:var(--bui-space-11)}.lg\:bui-mr-12{margin-right:var(--bui-space-12)}.lg\:bui-mr-13{margin-right:var(--bui-space-13)}.lg\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mr{margin-right:var(--mr-xl)}.xl\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.xl\:bui-mr-1{margin-right:var(--bui-space-1)}.xl\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.xl\:bui-mr-2{margin-right:var(--bui-space-2)}.xl\:bui-mr-3{margin-right:var(--bui-space-3)}.xl\:bui-mr-4{margin-right:var(--bui-space-4)}.xl\:bui-mr-5{margin-right:var(--bui-space-5)}.xl\:bui-mr-6{margin-right:var(--bui-space-6)}.xl\:bui-mr-7{margin-right:var(--bui-space-7)}.xl\:bui-mr-8{margin-right:var(--bui-space-8)}.xl\:bui-mr-9{margin-right:var(--bui-space-9)}.xl\:bui-mr-10{margin-right:var(--bui-space-10)}.xl\:bui-mr-11{margin-right:var(--bui-space-11)}.xl\:bui-mr-12{margin-right:var(--bui-space-12)}.xl\:bui-mr-13{margin-right:var(--bui-space-13)}.xl\:bui-mr-14{margin-right:var(--bui-space-14)}}.bui-mt{margin-top:var(--mt)}.bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.bui-mt-1{margin-top:var(--bui-space-1)}.bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.bui-mt-2{margin-top:var(--bui-space-2)}.bui-mt-3{margin-top:var(--bui-space-3)}.bui-mt-4{margin-top:var(--bui-space-4)}.bui-mt-5{margin-top:var(--bui-space-5)}.bui-mt-6{margin-top:var(--bui-space-6)}.bui-mt-7{margin-top:var(--bui-space-7)}.bui-mt-8{margin-top:var(--bui-space-8)}.bui-mt-9{margin-top:var(--bui-space-9)}.bui-mt-10{margin-top:var(--bui-space-10)}.bui-mt-11{margin-top:var(--bui-space-11)}.bui-mt-12{margin-top:var(--bui-space-12)}.bui-mt-13{margin-top:var(--bui-space-13)}.bui-mt-14{margin-top:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mt{margin-top:var(--mt-xs)}.xs\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.xs\:bui-mt-1{margin-top:var(--bui-space-1)}.xs\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.xs\:bui-mt-2{margin-top:var(--bui-space-2)}.xs\:bui-mt-3{margin-top:var(--bui-space-3)}.xs\:bui-mt-4{margin-top:var(--bui-space-4)}.xs\:bui-mt-5{margin-top:var(--bui-space-5)}.xs\:bui-mt-6{margin-top:var(--bui-space-6)}.xs\:bui-mt-7{margin-top:var(--bui-space-7)}.xs\:bui-mt-8{margin-top:var(--bui-space-8)}.xs\:bui-mt-9{margin-top:var(--bui-space-9)}.xs\:bui-mt-10{margin-top:var(--bui-space-10)}.xs\:bui-mt-11{margin-top:var(--bui-space-11)}.xs\:bui-mt-12{margin-top:var(--bui-space-12)}.xs\:bui-mt-13{margin-top:var(--bui-space-13)}.xs\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mt{margin-top:var(--mt-sm)}.sm\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.sm\:bui-mt-1{margin-top:var(--bui-space-1)}.sm\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.sm\:bui-mt-2{margin-top:var(--bui-space-2)}.sm\:bui-mt-3{margin-top:var(--bui-space-3)}.sm\:bui-mt-4{margin-top:var(--bui-space-4)}.sm\:bui-mt-5{margin-top:var(--bui-space-5)}.sm\:bui-mt-6{margin-top:var(--bui-space-6)}.sm\:bui-mt-7{margin-top:var(--bui-space-7)}.sm\:bui-mt-8{margin-top:var(--bui-space-8)}.sm\:bui-mt-9{margin-top:var(--bui-space-9)}.sm\:bui-mt-10{margin-top:var(--bui-space-10)}.sm\:bui-mt-11{margin-top:var(--bui-space-11)}.sm\:bui-mt-12{margin-top:var(--bui-space-12)}.sm\:bui-mt-13{margin-top:var(--bui-space-13)}.sm\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mt{margin-top:var(--mt-md)}.md\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.md\:bui-mt-1{margin-top:var(--bui-space-1)}.md\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.md\:bui-mt-2{margin-top:var(--bui-space-2)}.md\:bui-mt-3{margin-top:var(--bui-space-3)}.md\:bui-mt-4{margin-top:var(--bui-space-4)}.md\:bui-mt-5{margin-top:var(--bui-space-5)}.md\:bui-mt-6{margin-top:var(--bui-space-6)}.md\:bui-mt-7{margin-top:var(--bui-space-7)}.md\:bui-mt-8{margin-top:var(--bui-space-8)}.md\:bui-mt-9{margin-top:var(--bui-space-9)}.md\:bui-mt-10{margin-top:var(--bui-space-10)}.md\:bui-mt-11{margin-top:var(--bui-space-11)}.md\:bui-mt-12{margin-top:var(--bui-space-12)}.md\:bui-mt-13{margin-top:var(--bui-space-13)}.md\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mt{margin-top:var(--mt-lg)}.lg\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.lg\:bui-mt-1{margin-top:var(--bui-space-1)}.lg\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.lg\:bui-mt-2{margin-top:var(--bui-space-2)}.lg\:bui-mt-3{margin-top:var(--bui-space-3)}.lg\:bui-mt-4{margin-top:var(--bui-space-4)}.lg\:bui-mt-5{margin-top:var(--bui-space-5)}.lg\:bui-mt-6{margin-top:var(--bui-space-6)}.lg\:bui-mt-7{margin-top:var(--bui-space-7)}.lg\:bui-mt-8{margin-top:var(--bui-space-8)}.lg\:bui-mt-9{margin-top:var(--bui-space-9)}.lg\:bui-mt-10{margin-top:var(--bui-space-10)}.lg\:bui-mt-11{margin-top:var(--bui-space-11)}.lg\:bui-mt-12{margin-top:var(--bui-space-12)}.lg\:bui-mt-13{margin-top:var(--bui-space-13)}.lg\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mt{margin-top:var(--mt-xl)}.xl\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.xl\:bui-mt-1{margin-top:var(--bui-space-1)}.xl\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.xl\:bui-mt-2{margin-top:var(--bui-space-2)}.xl\:bui-mt-3{margin-top:var(--bui-space-3)}.xl\:bui-mt-4{margin-top:var(--bui-space-4)}.xl\:bui-mt-5{margin-top:var(--bui-space-5)}.xl\:bui-mt-6{margin-top:var(--bui-space-6)}.xl\:bui-mt-7{margin-top:var(--bui-space-7)}.xl\:bui-mt-8{margin-top:var(--bui-space-8)}.xl\:bui-mt-9{margin-top:var(--bui-space-9)}.xl\:bui-mt-10{margin-top:var(--bui-space-10)}.xl\:bui-mt-11{margin-top:var(--bui-space-11)}.xl\:bui-mt-12{margin-top:var(--bui-space-12)}.xl\:bui-mt-13{margin-top:var(--bui-space-13)}.xl\:bui-mt-14{margin-top:var(--bui-space-14)}}.bui-mb{margin-bottom:var(--mb)}.bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.bui-mb-1{margin-bottom:var(--bui-space-1)}.bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.bui-mb-2{margin-bottom:var(--bui-space-2)}.bui-mb-3{margin-bottom:var(--bui-space-3)}.bui-mb-4{margin-bottom:var(--bui-space-4)}.bui-mb-5{margin-bottom:var(--bui-space-5)}.bui-mb-6{margin-bottom:var(--bui-space-6)}.bui-mb-7{margin-bottom:var(--bui-space-7)}.bui-mb-8{margin-bottom:var(--bui-space-8)}.bui-mb-9{margin-bottom:var(--bui-space-9)}.bui-mb-10{margin-bottom:var(--bui-space-10)}.bui-mb-11{margin-bottom:var(--bui-space-11)}.bui-mb-12{margin-bottom:var(--bui-space-12)}.bui-mb-13{margin-bottom:var(--bui-space-13)}.bui-mb-14{margin-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mb{margin-bottom:var(--mb-xs)}.xs\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.xs\:bui-mb-1{margin-bottom:var(--bui-space-1)}.xs\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.xs\:bui-mb-2{margin-bottom:var(--bui-space-2)}.xs\:bui-mb-3{margin-bottom:var(--bui-space-3)}.xs\:bui-mb-4{margin-bottom:var(--bui-space-4)}.xs\:bui-mb-5{margin-bottom:var(--bui-space-5)}.xs\:bui-mb-6{margin-bottom:var(--bui-space-6)}.xs\:bui-mb-7{margin-bottom:var(--bui-space-7)}.xs\:bui-mb-8{margin-bottom:var(--bui-space-8)}.xs\:bui-mb-9{margin-bottom:var(--bui-space-9)}.xs\:bui-mb-10{margin-bottom:var(--bui-space-10)}.xs\:bui-mb-11{margin-bottom:var(--bui-space-11)}.xs\:bui-mb-12{margin-bottom:var(--bui-space-12)}.xs\:bui-mb-13{margin-bottom:var(--bui-space-13)}.xs\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mb{margin-bottom:var(--mb-sm)}.sm\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.sm\:bui-mb-1{margin-bottom:var(--bui-space-1)}.sm\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.sm\:bui-mb-2{margin-bottom:var(--bui-space-2)}.sm\:bui-mb-3{margin-bottom:var(--bui-space-3)}.sm\:bui-mb-4{margin-bottom:var(--bui-space-4)}.sm\:bui-mb-5{margin-bottom:var(--bui-space-5)}.sm\:bui-mb-6{margin-bottom:var(--bui-space-6)}.sm\:bui-mb-7{margin-bottom:var(--bui-space-7)}.sm\:bui-mb-8{margin-bottom:var(--bui-space-8)}.sm\:bui-mb-9{margin-bottom:var(--bui-space-9)}.sm\:bui-mb-10{margin-bottom:var(--bui-space-10)}.sm\:bui-mb-11{margin-bottom:var(--bui-space-11)}.sm\:bui-mb-12{margin-bottom:var(--bui-space-12)}.sm\:bui-mb-13{margin-bottom:var(--bui-space-13)}.sm\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mb{margin-bottom:var(--mb-md)}.md\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.md\:bui-mb-1{margin-bottom:var(--bui-space-1)}.md\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.md\:bui-mb-2{margin-bottom:var(--bui-space-2)}.md\:bui-mb-3{margin-bottom:var(--bui-space-3)}.md\:bui-mb-4{margin-bottom:var(--bui-space-4)}.md\:bui-mb-5{margin-bottom:var(--bui-space-5)}.md\:bui-mb-6{margin-bottom:var(--bui-space-6)}.md\:bui-mb-7{margin-bottom:var(--bui-space-7)}.md\:bui-mb-8{margin-bottom:var(--bui-space-8)}.md\:bui-mb-9{margin-bottom:var(--bui-space-9)}.md\:bui-mb-10{margin-bottom:var(--bui-space-10)}.md\:bui-mb-11{margin-bottom:var(--bui-space-11)}.md\:bui-mb-12{margin-bottom:var(--bui-space-12)}.md\:bui-mb-13{margin-bottom:var(--bui-space-13)}.md\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mb{margin-bottom:var(--mb-lg)}.lg\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.lg\:bui-mb-1{margin-bottom:var(--bui-space-1)}.lg\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.lg\:bui-mb-2{margin-bottom:var(--bui-space-2)}.lg\:bui-mb-3{margin-bottom:var(--bui-space-3)}.lg\:bui-mb-4{margin-bottom:var(--bui-space-4)}.lg\:bui-mb-5{margin-bottom:var(--bui-space-5)}.lg\:bui-mb-6{margin-bottom:var(--bui-space-6)}.lg\:bui-mb-7{margin-bottom:var(--bui-space-7)}.lg\:bui-mb-8{margin-bottom:var(--bui-space-8)}.lg\:bui-mb-9{margin-bottom:var(--bui-space-9)}.lg\:bui-mb-10{margin-bottom:var(--bui-space-10)}.lg\:bui-mb-11{margin-bottom:var(--bui-space-11)}.lg\:bui-mb-12{margin-bottom:var(--bui-space-12)}.lg\:bui-mb-13{margin-bottom:var(--bui-space-13)}.lg\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mb{margin-bottom:var(--mb-xl)}.xl\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.xl\:bui-mb-1{margin-bottom:var(--bui-space-1)}.xl\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.xl\:bui-mb-2{margin-bottom:var(--bui-space-2)}.xl\:bui-mb-3{margin-bottom:var(--bui-space-3)}.xl\:bui-mb-4{margin-bottom:var(--bui-space-4)}.xl\:bui-mb-5{margin-bottom:var(--bui-space-5)}.xl\:bui-mb-6{margin-bottom:var(--bui-space-6)}.xl\:bui-mb-7{margin-bottom:var(--bui-space-7)}.xl\:bui-mb-8{margin-bottom:var(--bui-space-8)}.xl\:bui-mb-9{margin-bottom:var(--bui-space-9)}.xl\:bui-mb-10{margin-bottom:var(--bui-space-10)}.xl\:bui-mb-11{margin-bottom:var(--bui-space-11)}.xl\:bui-mb-12{margin-bottom:var(--bui-space-12)}.xl\:bui-mb-13{margin-bottom:var(--bui-space-13)}.xl\:bui-mb-14{margin-bottom:var(--bui-space-14)}}.bui-my{margin-top:var(--my);margin-bottom:var(--my)}.bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-my{margin-top:var(--my-xs);margin-bottom:var(--my-xs)}.xs\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.xs\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.xs\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.xs\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.xs\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.xs\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.xs\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.xs\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.xs\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.xs\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.xs\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.xs\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.xs\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.xs\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.xs\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.xs\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-my{margin-top:var(--my-sm);margin-bottom:var(--my-sm)}.sm\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.sm\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.sm\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.sm\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.sm\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.sm\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.sm\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.sm\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.sm\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.sm\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.sm\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.sm\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.sm\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.sm\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.sm\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.sm\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-my{margin-top:var(--my-md);margin-bottom:var(--my-md)}.md\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.md\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.md\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.md\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.md\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.md\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.md\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.md\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.md\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.md\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.md\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.md\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.md\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.md\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.md\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.md\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-my{margin-top:var(--my-lg);margin-bottom:var(--my-lg)}.lg\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.lg\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.lg\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.lg\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.lg\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.lg\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.lg\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.lg\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.lg\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.lg\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.lg\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.lg\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.lg\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.lg\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.lg\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.lg\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-my{margin-top:var(--my-xl);margin-bottom:var(--my-xl)}.xl\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.xl\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.xl\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.xl\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.xl\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.xl\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.xl\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.xl\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.xl\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.xl\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.xl\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.xl\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.xl\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.xl\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.xl\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.xl\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}.bui-mx{margin-left:var(--mx);margin-right:var(--mx)}.bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mx{margin-left:var(--mx-xs);margin-right:var(--mx-xs)}.xs\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.xs\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.xs\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.xs\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.xs\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.xs\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.xs\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.xs\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.xs\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.xs\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.xs\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.xs\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.xs\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.xs\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.xs\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.xs\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mx{margin-left:var(--mx-sm);margin-right:var(--mx-sm)}.sm\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.sm\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.sm\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.sm\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.sm\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.sm\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.sm\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.sm\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.sm\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.sm\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.sm\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.sm\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.sm\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.sm\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.sm\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.sm\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mx{margin-left:var(--mx-md);margin-right:var(--mx-md)}.md\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.md\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.md\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.md\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.md\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.md\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.md\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.md\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.md\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.md\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.md\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.md\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.md\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.md\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.md\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.md\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mx{margin-left:var(--mx-lg);margin-right:var(--mx-lg)}.lg\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.lg\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.lg\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.lg\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.lg\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.lg\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.lg\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.lg\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.lg\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.lg\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.lg\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.lg\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.lg\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.lg\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.lg\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.lg\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mx{margin-left:var(--mx-xl);margin-right:var(--mx-xl)}.xl\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.xl\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.xl\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.xl\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.xl\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.xl\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.xl\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.xl\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.xl\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.xl\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.xl\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.xl\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.xl\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.xl\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.xl\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.xl\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}.bui-display-none{display:none}.bui-display-inline{display:inline}.bui-display-inline-block{display:inline-block}.bui-display-block{display:block}@media (width>=640px){.xs\:bui-display-none{display:none}.xs\:bui-display-inline{display:inline}.xs\:bui-display-inline-block{display:inline-block}.xs\:bui-display-block{display:block}}@media (width>=768px){.sm\:bui-display-none{display:none}.sm\:bui-display-inline{display:inline}.sm\:bui-display-inline-block{display:inline-block}.sm\:bui-display-block{display:block}}@media (width>=1024px){.md\:bui-display-none{display:none}.md\:bui-display-inline{display:inline}.md\:bui-display-inline-block{display:inline-block}.md\:bui-display-block{display:block}}@media (width>=1280px){.lg\:bui-display-none{display:none}.lg\:bui-display-inline{display:inline}.lg\:bui-display-inline-block{display:inline-block}.lg\:bui-display-block{display:block}}@media (width>=1536px){.xl\:bui-display-none{display:none}.xl\:bui-display-inline{display:inline}.xl\:bui-display-inline-block{display:inline-block}.xl\:bui-display-block{display:block}}.bui-w{width:var(--width)}.bui-min-w{min-width:var(--min-width)}.bui-max-w{max-width:var(--max-width)}@media (width>=640px){.xs\:bui-w{width:var(--width)}.xs\:bui-min-w{min-width:var(--min-width)}.xs\:bui-max-w{max-width:var(--max-width)}}@media (width>=768px){.sm\:bui-w{width:var(--width)}.sm\:bui-min-w{min-width:var(--min-width)}.sm\:bui-max-w{max-width:var(--max-width)}}@media (width>=1024px){.md\:bui-w{width:var(--width)}.md\:bui-min-w{min-width:var(--min-width)}.md\:bui-max-w{max-width:var(--max-width)}}@media (width>=1280px){.lg\:bui-w{width:var(--width)}.lg\:bui-min-w{min-width:var(--min-width)}.lg\:bui-max-w{max-width:var(--max-width)}}@media (width>=1536px){.xl\:bui-w{width:var(--width)}.xl\:bui-min-w{min-width:var(--min-width)}.xl\:bui-max-w{max-width:var(--max-width)}}.bui-h{height:var(--height)}.bui-min-h{min-height:var(--min-height)}.bui-max-h{max-height:var(--max-height)}@media (width>=640px){.xs\:bui-h{height:var(--height)}.xs\:bui-min-h{min-height:var(--min-height)}.xs\:bui-max-h{max-height:var(--max-height)}}@media (width>=768px){.sm\:bui-h{height:var(--height)}.sm\:bui-min-h{min-height:var(--min-height)}.sm\:bui-max-h{max-height:var(--max-height)}}@media (width>=1024px){.md\:bui-h{height:var(--height)}.md\:bui-min-h{min-height:var(--min-height)}.md\:bui-max-h{max-height:var(--max-height)}}@media (width>=1280px){.lg\:bui-h{height:var(--height)}.lg\:bui-min-h{min-height:var(--min-height)}.lg\:bui-max-h{max-height:var(--max-height)}}@media (width>=1536px){.xl\:bui-h{height:var(--height)}.xl\:bui-min-h{min-height:var(--min-height)}.xl\:bui-max-h{max-height:var(--max-height)}}.bui-position-absolute{position:absolute}.bui-position-fixed{position:fixed}.bui-position-sticky{position:sticky}.bui-position-relative{position:relative}.bui-position-static{position:static}@media (width>=640px){.xs\:bui-position-absolute{position:absolute}.xs\:bui-position-fixed{position:fixed}.xs\:bui-position-sticky{position:sticky}.xs\:bui-position-relative{position:relative}.xs\:bui-position-static{position:static}}@media (width>=768px){.sm\:bui-position-absolute{position:absolute}.sm\:bui-position-fixed{position:fixed}.sm\:bui-position-sticky{position:sticky}.sm\:bui-position-relative{position:relative}.sm\:bui-position-static{position:static}}@media (width>=1024px){.md\:bui-position-absolute{position:absolute}.md\:bui-position-fixed{position:fixed}.md\:bui-position-sticky{position:sticky}.md\:bui-position-relative{position:relative}.md\:bui-position-static{position:static}}@media (width>=1280px){.lg\:bui-position-absolute{position:absolute}.lg\:bui-position-fixed{position:fixed}.lg\:bui-position-sticky{position:sticky}.lg\:bui-position-relative{position:relative}.lg\:bui-position-static{position:static}}@media (width>=1536px){.xl\:bui-position-absolute{position:absolute}.xl\:bui-position-fixed{position:fixed}.xl\:bui-position-sticky{position:sticky}.xl\:bui-position-relative{position:relative}.xl\:bui-position-static{position:static}}.bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.bui-col-span-1{grid-column:span 1/span 1}.bui-col-span-2{grid-column:span 2/span 2}.bui-col-span-3{grid-column:span 3/span 3}.bui-col-span-4{grid-column:span 4/span 4}.bui-col-span-5{grid-column:span 5/span 5}.bui-col-span-6{grid-column:span 6/span 6}.bui-col-span-7{grid-column:span 7/span 7}.bui-col-span-8{grid-column:span 8/span 8}.bui-col-span-9{grid-column:span 9/span 9}.bui-col-span-10{grid-column:span 10/span 10}.bui-col-span-11{grid-column:span 11/span 11}.bui-col-span-12{grid-column:span 12/span 12}.bui-col-span-auto{grid-column:span auto/span auto}.bui-col-start-1{grid-column-start:1}.bui-col-start-2{grid-column-start:2}.bui-col-start-3{grid-column-start:3}.bui-col-start-4{grid-column-start:4}.bui-col-start-5{grid-column-start:5}.bui-col-start-6{grid-column-start:6}.bui-col-start-7{grid-column-start:7}.bui-col-start-8{grid-column-start:8}.bui-col-start-9{grid-column-start:9}.bui-col-start-10{grid-column-start:10}.bui-col-start-11{grid-column-start:11}.bui-col-start-12{grid-column-start:12}.bui-col-start-13{grid-column-start:13}.bui-col-start-auto{grid-column-start:auto}.bui-col-end-1{grid-column-end:1}.bui-col-end-2{grid-column-end:2}.bui-col-end-3{grid-column-end:3}.bui-col-end-4{grid-column-end:4}.bui-col-end-5{grid-column-end:5}.bui-col-end-6{grid-column-end:6}.bui-col-end-7{grid-column-end:7}.bui-col-end-8{grid-column-end:8}.bui-col-end-9{grid-column-end:9}.bui-col-end-10{grid-column-end:10}.bui-col-end-11{grid-column-end:11}.bui-col-end-12{grid-column-end:12}.bui-col-end-13{grid-column-end:13}.bui-col-end-auto{grid-column-end:auto}.bui-row-span-1{grid-row:span 1/span 1}.bui-row-span-2{grid-row:span 2/span 2}.bui-row-span-3{grid-row:span 3/span 3}.bui-row-span-4{grid-row:span 4/span 4}.bui-row-span-5{grid-row:span 5/span 5}.bui-row-span-6{grid-row:span 6/span 6}.bui-row-span-7{grid-row:span 7/span 7}.bui-row-span-8{grid-row:span 8/span 8}.bui-row-span-9{grid-row:span 9/span 9}.bui-row-span-10{grid-row:span 10/span 10}.bui-row-span-11{grid-row:span 11/span 11}.bui-row-span-12{grid-row:span 12/span 12}.bui-row-span-auto{grid-row:span auto/span auto}@media (width>=640px){.xs\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xs\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xs\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xs\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xs\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xs\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xs\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xs\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xs\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xs\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xs\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xs\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xs\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xs\:bui-col-span-1{grid-column:span 1/span 1}.xs\:bui-col-span-2{grid-column:span 2/span 2}.xs\:bui-col-span-3{grid-column:span 3/span 3}.xs\:bui-col-span-4{grid-column:span 4/span 4}.xs\:bui-col-span-5{grid-column:span 5/span 5}.xs\:bui-col-span-6{grid-column:span 6/span 6}.xs\:bui-col-span-7{grid-column:span 7/span 7}.xs\:bui-col-span-8{grid-column:span 8/span 8}.xs\:bui-col-span-9{grid-column:span 9/span 9}.xs\:bui-col-span-10{grid-column:span 10/span 10}.xs\:bui-col-span-11{grid-column:span 11/span 11}.xs\:bui-col-span-12{grid-column:span 12/span 12}.xs\:bui-col-span-auto{grid-column:span auto/span auto}.xs\:bui-col-start-1{grid-column-start:1}.xs\:bui-col-start-2{grid-column-start:2}.xs\:bui-col-start-3{grid-column-start:3}.xs\:bui-col-start-4{grid-column-start:4}.xs\:bui-col-start-5{grid-column-start:5}.xs\:bui-col-start-6{grid-column-start:6}.xs\:bui-col-start-7{grid-column-start:7}.xs\:bui-col-start-8{grid-column-start:8}.xs\:bui-col-start-9{grid-column-start:9}.xs\:bui-col-start-10{grid-column-start:10}.xs\:bui-col-start-11{grid-column-start:11}.xs\:bui-col-start-12{grid-column-start:12}.xs\:bui-col-start-13{grid-column-start:13}.xs\:bui-col-start-auto{grid-column-start:auto}.xs\:bui-col-end-1{grid-column-end:1}.xs\:bui-col-end-2{grid-column-end:2}.xs\:bui-col-end-3{grid-column-end:3}.xs\:bui-col-end-4{grid-column-end:4}.xs\:bui-col-end-5{grid-column-end:5}.xs\:bui-col-end-6{grid-column-end:6}.xs\:bui-col-end-7{grid-column-end:7}.xs\:bui-col-end-8{grid-column-end:8}.xs\:bui-col-end-9{grid-column-end:9}.xs\:bui-col-end-10{grid-column-end:10}.xs\:bui-col-end-11{grid-column-end:11}.xs\:bui-col-end-12{grid-column-end:12}.xs\:bui-col-end-13{grid-column-end:13}.xs\:bui-col-end-auto{grid-column-end:auto}.xs\:bui-row-span-1{grid-row:span 1/span 1}.xs\:bui-row-span-2{grid-row:span 2/span 2}.xs\:bui-row-span-3{grid-row:span 3/span 3}.xs\:bui-row-span-4{grid-row:span 4/span 4}.xs\:bui-row-span-5{grid-row:span 5/span 5}.xs\:bui-row-span-6{grid-row:span 6/span 6}.xs\:bui-row-span-7{grid-row:span 7/span 7}.xs\:bui-row-span-8{grid-row:span 8/span 8}.xs\:bui-row-span-9{grid-row:span 9/span 9}.xs\:bui-row-span-10{grid-row:span 10/span 10}.xs\:bui-row-span-11{grid-row:span 11/span 11}.xs\:bui-row-span-12{grid-row:span 12/span 12}.xs\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=768px){.sm\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.sm\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.sm\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.sm\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.sm\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.sm\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.sm\:bui-col-span-1{grid-column:span 1/span 1}.sm\:bui-col-span-2{grid-column:span 2/span 2}.sm\:bui-col-span-3{grid-column:span 3/span 3}.sm\:bui-col-span-4{grid-column:span 4/span 4}.sm\:bui-col-span-5{grid-column:span 5/span 5}.sm\:bui-col-span-6{grid-column:span 6/span 6}.sm\:bui-col-span-7{grid-column:span 7/span 7}.sm\:bui-col-span-8{grid-column:span 8/span 8}.sm\:bui-col-span-9{grid-column:span 9/span 9}.sm\:bui-col-span-10{grid-column:span 10/span 10}.sm\:bui-col-span-11{grid-column:span 11/span 11}.sm\:bui-col-span-12{grid-column:span 12/span 12}.sm\:bui-col-span-auto{grid-column:span auto/span auto}.sm\:bui-col-start-1{grid-column-start:1}.sm\:bui-col-start-2{grid-column-start:2}.sm\:bui-col-start-3{grid-column-start:3}.sm\:bui-col-start-4{grid-column-start:4}.sm\:bui-col-start-5{grid-column-start:5}.sm\:bui-col-start-6{grid-column-start:6}.sm\:bui-col-start-7{grid-column-start:7}.sm\:bui-col-start-8{grid-column-start:8}.sm\:bui-col-start-9{grid-column-start:9}.sm\:bui-col-start-10{grid-column-start:10}.sm\:bui-col-start-11{grid-column-start:11}.sm\:bui-col-start-12{grid-column-start:12}.sm\:bui-col-start-13{grid-column-start:13}.sm\:bui-col-start-auto{grid-column-start:auto}.sm\:bui-col-end-1{grid-column-end:1}.sm\:bui-col-end-2{grid-column-end:2}.sm\:bui-col-end-3{grid-column-end:3}.sm\:bui-col-end-4{grid-column-end:4}.sm\:bui-col-end-5{grid-column-end:5}.sm\:bui-col-end-6{grid-column-end:6}.sm\:bui-col-end-7{grid-column-end:7}.sm\:bui-col-end-8{grid-column-end:8}.sm\:bui-col-end-9{grid-column-end:9}.sm\:bui-col-end-10{grid-column-end:10}.sm\:bui-col-end-11{grid-column-end:11}.sm\:bui-col-end-12{grid-column-end:12}.sm\:bui-col-end-13{grid-column-end:13}.sm\:bui-col-end-auto{grid-column-end:auto}.sm\:bui-row-span-1{grid-row:span 1/span 1}.sm\:bui-row-span-2{grid-row:span 2/span 2}.sm\:bui-row-span-3{grid-row:span 3/span 3}.sm\:bui-row-span-4{grid-row:span 4/span 4}.sm\:bui-row-span-5{grid-row:span 5/span 5}.sm\:bui-row-span-6{grid-row:span 6/span 6}.sm\:bui-row-span-7{grid-row:span 7/span 7}.sm\:bui-row-span-8{grid-row:span 8/span 8}.sm\:bui-row-span-9{grid-row:span 9/span 9}.sm\:bui-row-span-10{grid-row:span 10/span 10}.sm\:bui-row-span-11{grid-row:span 11/span 11}.sm\:bui-row-span-12{grid-row:span 12/span 12}.sm\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1024px){.md\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.md\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.md\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.md\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.md\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.md\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.md\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.md\:bui-col-span-1{grid-column:span 1/span 1}.md\:bui-col-span-2{grid-column:span 2/span 2}.md\:bui-col-span-3{grid-column:span 3/span 3}.md\:bui-col-span-4{grid-column:span 4/span 4}.md\:bui-col-span-5{grid-column:span 5/span 5}.md\:bui-col-span-6{grid-column:span 6/span 6}.md\:bui-col-span-7{grid-column:span 7/span 7}.md\:bui-col-span-8{grid-column:span 8/span 8}.md\:bui-col-span-9{grid-column:span 9/span 9}.md\:bui-col-span-10{grid-column:span 10/span 10}.md\:bui-col-span-11{grid-column:span 11/span 11}.md\:bui-col-span-12{grid-column:span 12/span 12}.md\:bui-col-span-auto{grid-column:span auto/span auto}.md\:bui-col-start-1{grid-column-start:1}.md\:bui-col-start-2{grid-column-start:2}.md\:bui-col-start-3{grid-column-start:3}.md\:bui-col-start-4{grid-column-start:4}.md\:bui-col-start-5{grid-column-start:5}.md\:bui-col-start-6{grid-column-start:6}.md\:bui-col-start-7{grid-column-start:7}.md\:bui-col-start-8{grid-column-start:8}.md\:bui-col-start-9{grid-column-start:9}.md\:bui-col-start-10{grid-column-start:10}.md\:bui-col-start-11{grid-column-start:11}.md\:bui-col-start-12{grid-column-start:12}.md\:bui-col-start-13{grid-column-start:13}.md\:bui-col-start-auto{grid-column-start:auto}.md\:bui-col-end-1{grid-column-end:1}.md\:bui-col-end-2{grid-column-end:2}.md\:bui-col-end-3{grid-column-end:3}.md\:bui-col-end-4{grid-column-end:4}.md\:bui-col-end-5{grid-column-end:5}.md\:bui-col-end-6{grid-column-end:6}.md\:bui-col-end-7{grid-column-end:7}.md\:bui-col-end-8{grid-column-end:8}.md\:bui-col-end-9{grid-column-end:9}.md\:bui-col-end-10{grid-column-end:10}.md\:bui-col-end-11{grid-column-end:11}.md\:bui-col-end-12{grid-column-end:12}.md\:bui-col-end-13{grid-column-end:13}.md\:bui-col-end-auto{grid-column-end:auto}.md\:bui-row-span-1{grid-row:span 1/span 1}.md\:bui-row-span-2{grid-row:span 2/span 2}.md\:bui-row-span-3{grid-row:span 3/span 3}.md\:bui-row-span-4{grid-row:span 4/span 4}.md\:bui-row-span-5{grid-row:span 5/span 5}.md\:bui-row-span-6{grid-row:span 6/span 6}.md\:bui-row-span-7{grid-row:span 7/span 7}.md\:bui-row-span-8{grid-row:span 8/span 8}.md\:bui-row-span-9{grid-row:span 9/span 9}.md\:bui-row-span-10{grid-row:span 10/span 10}.md\:bui-row-span-11{grid-row:span 11/span 11}.md\:bui-row-span-12{grid-row:span 12/span 12}.md\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1280px){.lg\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.lg\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.lg\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.lg\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.lg\:bui-col-span-1{grid-column:span 1/span 1}.lg\:bui-col-span-2{grid-column:span 2/span 2}.lg\:bui-col-span-3{grid-column:span 3/span 3}.lg\:bui-col-span-4{grid-column:span 4/span 4}.lg\:bui-col-span-5{grid-column:span 5/span 5}.lg\:bui-col-span-6{grid-column:span 6/span 6}.lg\:bui-col-span-7{grid-column:span 7/span 7}.lg\:bui-col-span-8{grid-column:span 8/span 8}.lg\:bui-col-span-9{grid-column:span 9/span 9}.lg\:bui-col-span-10{grid-column:span 10/span 10}.lg\:bui-col-span-11{grid-column:span 11/span 11}.lg\:bui-col-span-12{grid-column:span 12/span 12}.lg\:bui-col-span-auto{grid-column:span auto/span auto}.lg\:bui-col-start-1{grid-column-start:1}.lg\:bui-col-start-2{grid-column-start:2}.lg\:bui-col-start-3{grid-column-start:3}.lg\:bui-col-start-4{grid-column-start:4}.lg\:bui-col-start-5{grid-column-start:5}.lg\:bui-col-start-6{grid-column-start:6}.lg\:bui-col-start-7{grid-column-start:7}.lg\:bui-col-start-8{grid-column-start:8}.lg\:bui-col-start-9{grid-column-start:9}.lg\:bui-col-start-10{grid-column-start:10}.lg\:bui-col-start-11{grid-column-start:11}.lg\:bui-col-start-12{grid-column-start:12}.lg\:bui-col-start-13{grid-column-start:13}.lg\:bui-col-start-auto{grid-column-start:auto}.lg\:bui-col-end-1{grid-column-end:1}.lg\:bui-col-end-2{grid-column-end:2}.lg\:bui-col-end-3{grid-column-end:3}.lg\:bui-col-end-4{grid-column-end:4}.lg\:bui-col-end-5{grid-column-end:5}.lg\:bui-col-end-6{grid-column-end:6}.lg\:bui-col-end-7{grid-column-end:7}.lg\:bui-col-end-8{grid-column-end:8}.lg\:bui-col-end-9{grid-column-end:9}.lg\:bui-col-end-10{grid-column-end:10}.lg\:bui-col-end-11{grid-column-end:11}.lg\:bui-col-end-12{grid-column-end:12}.lg\:bui-col-end-13{grid-column-end:13}.lg\:bui-col-end-auto{grid-column-end:auto}.lg\:bui-row-span-1{grid-row:span 1/span 1}.lg\:bui-row-span-2{grid-row:span 2/span 2}.lg\:bui-row-span-3{grid-row:span 3/span 3}.lg\:bui-row-span-4{grid-row:span 4/span 4}.lg\:bui-row-span-5{grid-row:span 5/span 5}.lg\:bui-row-span-6{grid-row:span 6/span 6}.lg\:bui-row-span-7{grid-row:span 7/span 7}.lg\:bui-row-span-8{grid-row:span 8/span 8}.lg\:bui-row-span-9{grid-row:span 9/span 9}.lg\:bui-row-span-10{grid-row:span 10/span 10}.lg\:bui-row-span-11{grid-row:span 11/span 11}.lg\:bui-row-span-12{grid-row:span 12/span 12}.lg\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1536px){.xl\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xl\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xl\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xl\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xl\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xl\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xl\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xl\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xl\:bui-col-span-1{grid-column:span 1/span 1}.xl\:bui-col-span-2{grid-column:span 2/span 2}.xl\:bui-col-span-3{grid-column:span 3/span 3}.xl\:bui-col-span-4{grid-column:span 4/span 4}.xl\:bui-col-span-5{grid-column:span 5/span 5}.xl\:bui-col-span-6{grid-column:span 6/span 6}.xl\:bui-col-span-7{grid-column:span 7/span 7}.xl\:bui-col-span-8{grid-column:span 8/span 8}.xl\:bui-col-span-9{grid-column:span 9/span 9}.xl\:bui-col-span-10{grid-column:span 10/span 10}.xl\:bui-col-span-11{grid-column:span 11/span 11}.xl\:bui-col-span-12{grid-column:span 12/span 12}.xl\:bui-col-span-auto{grid-column:span auto/span auto}.xl\:bui-col-start-1{grid-column-start:1}.xl\:bui-col-start-2{grid-column-start:2}.xl\:bui-col-start-3{grid-column-start:3}.xl\:bui-col-start-4{grid-column-start:4}.xl\:bui-col-start-5{grid-column-start:5}.xl\:bui-col-start-6{grid-column-start:6}.xl\:bui-col-start-7{grid-column-start:7}.xl\:bui-col-start-8{grid-column-start:8}.xl\:bui-col-start-9{grid-column-start:9}.xl\:bui-col-start-10{grid-column-start:10}.xl\:bui-col-start-11{grid-column-start:11}.xl\:bui-col-start-12{grid-column-start:12}.xl\:bui-col-start-13{grid-column-start:13}.xl\:bui-col-start-auto{grid-column-start:auto}.xl\:bui-col-end-1{grid-column-end:1}.xl\:bui-col-end-2{grid-column-end:2}.xl\:bui-col-end-3{grid-column-end:3}.xl\:bui-col-end-4{grid-column-end:4}.xl\:bui-col-end-5{grid-column-end:5}.xl\:bui-col-end-6{grid-column-end:6}.xl\:bui-col-end-7{grid-column-end:7}.xl\:bui-col-end-8{grid-column-end:8}.xl\:bui-col-end-9{grid-column-end:9}.xl\:bui-col-end-10{grid-column-end:10}.xl\:bui-col-end-11{grid-column-end:11}.xl\:bui-col-end-12{grid-column-end:12}.xl\:bui-col-end-13{grid-column-end:13}.xl\:bui-col-end-auto{grid-column-end:auto}.xl\:bui-row-span-1{grid-row:span 1/span 1}.xl\:bui-row-span-2{grid-row:span 2/span 2}.xl\:bui-row-span-3{grid-row:span 3/span 3}.xl\:bui-row-span-4{grid-row:span 4/span 4}.xl\:bui-row-span-5{grid-row:span 5/span 5}.xl\:bui-row-span-6{grid-row:span 6/span 6}.xl\:bui-row-span-7{grid-row:span 7/span 7}.xl\:bui-row-span-8{grid-row:span 8/span 8}.xl\:bui-row-span-9{grid-row:span 9/span 9}.xl\:bui-row-span-10{grid-row:span 10/span 10}.xl\:bui-row-span-11{grid-row:span 11/span 11}.xl\:bui-row-span-12{grid-row:span 12/span 12}.xl\:bui-row-span-auto{grid-row:span auto/span auto}}.bui-gap{gap:var(--gap)}.bui-gap-0\.5{gap:var(--bui-space-0_5)}.bui-gap-1{gap:var(--bui-space-1)}.bui-gap-1\.5{gap:var(--bui-space-1_5)}.bui-gap-2{gap:var(--bui-space-2)}.bui-gap-3{gap:var(--bui-space-3)}.bui-gap-4{gap:var(--bui-space-4)}.bui-gap-5{gap:var(--bui-space-5)}.bui-gap-6{gap:var(--bui-space-6)}.bui-gap-7{gap:var(--bui-space-7)}.bui-gap-8{gap:var(--bui-space-8)}.bui-gap-9{gap:var(--bui-space-9)}.bui-gap-10{gap:var(--bui-space-10)}.bui-gap-11{gap:var(--bui-space-11)}.bui-gap-12{gap:var(--bui-space-12)}.bui-gap-13{gap:var(--bui-space-13)}.bui-gap-14{gap:var(--bui-space-14)}@media (width>=640px){.xs\:bui-gap{gap:var(--gap-xs)}.xs\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.xs\:bui-gap-1{gap:var(--bui-space-1)}.xs\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.xs\:bui-gap-2{gap:var(--bui-space-2)}.xs\:bui-gap-3{gap:var(--bui-space-3)}.xs\:bui-gap-4{gap:var(--bui-space-4)}.xs\:bui-gap-5{gap:var(--bui-space-5)}.xs\:bui-gap-6{gap:var(--bui-space-6)}.xs\:bui-gap-7{gap:var(--bui-space-7)}.xs\:bui-gap-8{gap:var(--bui-space-8)}.xs\:bui-gap-9{gap:var(--bui-space-9)}.xs\:bui-gap-10{gap:var(--bui-space-10)}.xs\:bui-gap-11{gap:var(--bui-space-11)}.xs\:bui-gap-12{gap:var(--bui-space-12)}.xs\:bui-gap-13{gap:var(--bui-space-13)}.xs\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-gap{gap:var(--gap-sm)}.sm\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.sm\:bui-gap-1{gap:var(--bui-space-1)}.sm\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.sm\:bui-gap-2{gap:var(--bui-space-2)}.sm\:bui-gap-3{gap:var(--bui-space-3)}.sm\:bui-gap-4{gap:var(--bui-space-4)}.sm\:bui-gap-5{gap:var(--bui-space-5)}.sm\:bui-gap-6{gap:var(--bui-space-6)}.sm\:bui-gap-7{gap:var(--bui-space-7)}.sm\:bui-gap-8{gap:var(--bui-space-8)}.sm\:bui-gap-9{gap:var(--bui-space-9)}.sm\:bui-gap-10{gap:var(--bui-space-10)}.sm\:bui-gap-11{gap:var(--bui-space-11)}.sm\:bui-gap-12{gap:var(--bui-space-12)}.sm\:bui-gap-13{gap:var(--bui-space-13)}.sm\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-gap{gap:var(--gap-md)}.md\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.md\:bui-gap-1{gap:var(--bui-space-1)}.md\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.md\:bui-gap-2{gap:var(--bui-space-2)}.md\:bui-gap-3{gap:var(--bui-space-3)}.md\:bui-gap-4{gap:var(--bui-space-4)}.md\:bui-gap-5{gap:var(--bui-space-5)}.md\:bui-gap-6{gap:var(--bui-space-6)}.md\:bui-gap-7{gap:var(--bui-space-7)}.md\:bui-gap-8{gap:var(--bui-space-8)}.md\:bui-gap-9{gap:var(--bui-space-9)}.md\:bui-gap-10{gap:var(--bui-space-10)}.md\:bui-gap-11{gap:var(--bui-space-11)}.md\:bui-gap-12{gap:var(--bui-space-12)}.md\:bui-gap-13{gap:var(--bui-space-13)}.md\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-gap{gap:var(--gap-lg)}.lg\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.lg\:bui-gap-1{gap:var(--bui-space-1)}.lg\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.lg\:bui-gap-2{gap:var(--bui-space-2)}.lg\:bui-gap-3{gap:var(--bui-space-3)}.lg\:bui-gap-4{gap:var(--bui-space-4)}.lg\:bui-gap-5{gap:var(--bui-space-5)}.lg\:bui-gap-6{gap:var(--bui-space-6)}.lg\:bui-gap-7{gap:var(--bui-space-7)}.lg\:bui-gap-8{gap:var(--bui-space-8)}.lg\:bui-gap-9{gap:var(--bui-space-9)}.lg\:bui-gap-10{gap:var(--bui-space-10)}.lg\:bui-gap-11{gap:var(--bui-space-11)}.lg\:bui-gap-12{gap:var(--bui-space-12)}.lg\:bui-gap-13{gap:var(--bui-space-13)}.lg\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-gap{gap:var(--gap-xl)}.xl\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.xl\:bui-gap-1{gap:var(--bui-space-1)}.xl\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.xl\:bui-gap-2{gap:var(--bui-space-2)}.xl\:bui-gap-3{gap:var(--bui-space-3)}.xl\:bui-gap-4{gap:var(--bui-space-4)}.xl\:bui-gap-5{gap:var(--bui-space-5)}.xl\:bui-gap-6{gap:var(--bui-space-6)}.xl\:bui-gap-7{gap:var(--bui-space-7)}.xl\:bui-gap-8{gap:var(--bui-space-8)}.xl\:bui-gap-9{gap:var(--bui-space-9)}.xl\:bui-gap-10{gap:var(--bui-space-10)}.xl\:bui-gap-11{gap:var(--bui-space-11)}.xl\:bui-gap-12{gap:var(--bui-space-12)}.xl\:bui-gap-13{gap:var(--bui-space-13)}.xl\:bui-gap-14{gap:var(--bui-space-14)}}.bui-align-start{align-items:start}.bui-align-center{align-items:center}.bui-align-end{align-items:end}.bui-align-baseline{align-items:baseline}.bui-align-stretch{align-items:stretch}.bui-jc-start{justify-content:start}.bui-jc-center{justify-content:center}.bui-jc-end{justify-content:end}.bui-jc-between{justify-content:space-between}.bui-fd-row{flex-direction:row}.bui-fd-column{flex-direction:column}.bui-fd-row-reverse{flex-direction:row-reverse}.bui-fd-column-reverse{flex-direction:column-reverse}@media (width>=640px){.xs\:bui-align-start{align-items:start}.xs\:bui-align-center{align-items:center}.xs\:bui-align-end{align-items:end}.xs\:bui-align-stretch{align-items:stretch}.xs\:bui-jc-start{justify-content:start}.xs\:bui-jc-center{justify-content:center}.xs\:bui-jc-end{justify-content:end}.xs\:bui-jc-between{justify-content:space-between}.xs\:bui-fd-row{flex-direction:row}.xs\:bui-fd-column{flex-direction:column}.xs\:bui-fd-row-reverse{flex-direction:row-reverse}.xs\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=768px){.sm\:bui-align-start{align-items:start}.sm\:bui-align-center{align-items:center}.sm\:bui-align-end{align-items:end}.sm\:bui-align-stretch{align-items:stretch}.sm\:bui-jc-start{justify-content:start}.sm\:bui-jc-center{justify-content:center}.sm\:bui-jc-end{justify-content:end}.sm\:bui-jc-between{justify-content:space-between}.sm\:bui-fd-row{flex-direction:row}.sm\:bui-fd-column{flex-direction:column}.sm\:bui-fd-row-reverse{flex-direction:row-reverse}.sm\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1024px){.md\:bui-align-start{align-items:start}.md\:bui-align-center{align-items:center}.md\:bui-align-end{align-items:end}.md\:bui-align-stretch{align-items:stretch}.md\:bui-jc-start{justify-content:start}.md\:bui-jc-center{justify-content:center}.md\:bui-jc-end{justify-content:end}.md\:bui-jc-between{justify-content:space-between}.md\:bui-fd-row{flex-direction:row}.md\:bui-fd-column{flex-direction:column}.md\:bui-fd-row-reverse{flex-direction:row-reverse}.md\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1280px){.lg\:bui-align-start{align-items:start}.lg\:bui-align-center{align-items:center}.lg\:bui-align-end{align-items:end}.lg\:bui-align-stretch{align-items:stretch}.lg\:bui-jc-start{justify-content:start}.lg\:bui-jc-center{justify-content:center}.lg\:bui-jc-end{justify-content:end}.lg\:bui-jc-between{justify-content:space-between}.lg\:bui-fd-row{flex-direction:row}.lg\:bui-fd-column{flex-direction:column}.lg\:bui-fd-row-reverse{flex-direction:row-reverse}.lg\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1536px){.xl\:bui-align-start{align-items:start}.xl\:bui-align-center{align-items:center}.xl\:bui-align-end{align-items:end}.xl\:bui-align-stretch{align-items:stretch}.xl\:bui-jc-start{justify-content:start}.xl\:bui-jc-center{justify-content:center}.xl\:bui-jc-end{justify-content:end}.xl\:bui-jc-between{justify-content:space-between}.xl\:bui-fd-row{flex-direction:row}.xl\:bui-fd-column{flex-direction:column}.xl\:bui-fd-row-reverse{flex-direction:row-reverse}.xl\:bui-fd-column-reverse{flex-direction:column-reverse}}} \ No newline at end of file +@layer tokens{:root{--bui-font-regular:system-ui;--bui-font-monospace:ui-monospace,"Menlo","Monaco","Consolas","Liberation Mono","Courier New",monospace;--bui-font-weight-regular:400;--bui-font-weight-bold:600;--bui-font-size-1:.625rem;--bui-font-size-2:.75rem;--bui-font-size-3:.875rem;--bui-font-size-4:1rem;--bui-font-size-5:1.25rem;--bui-font-size-6:1.5rem;--bui-font-size-7:2rem;--bui-font-size-8:3rem;--bui-font-size-9:4rem;--bui-font-size-10:5.75rem;--bui-space:.25rem;--bui-space-0_5:calc(var(--bui-space)*.5);--bui-space-1:var(--bui-space);--bui-space-1_5:calc(var(--bui-space)*1.5);--bui-space-2:calc(var(--bui-space)*2);--bui-space-3:calc(var(--bui-space)*3);--bui-space-4:calc(var(--bui-space)*4);--bui-space-5:calc(var(--bui-space)*5);--bui-space-6:calc(var(--bui-space)*6);--bui-space-7:calc(var(--bui-space)*7);--bui-space-8:calc(var(--bui-space)*8);--bui-space-9:calc(var(--bui-space)*9);--bui-space-10:calc(var(--bui-space)*10);--bui-space-11:calc(var(--bui-space)*11);--bui-space-12:calc(var(--bui-space)*12);--bui-space-13:calc(var(--bui-space)*13);--bui-space-14:calc(var(--bui-space)*14);--bui-radius-1:calc(.125rem);--bui-radius-2:calc(.25rem);--bui-radius-3:calc(.5rem);--bui-radius-4:calc(.75rem);--bui-radius-5:calc(1rem);--bui-radius-6:calc(1.25rem);--bui-radius-full:9999px;--bui-black:#000;--bui-white:#fff;--bui-gray-1:#f8f8f8;--bui-gray-2:#ececec;--bui-gray-3:#d9d9d9;--bui-gray-4:#c1c1c1;--bui-gray-5:#9e9e9e;--bui-gray-6:#8c8c8c;--bui-gray-7:#757575;--bui-gray-8:#595959;--bui-bg-surface-0:var(--bui-gray-1);--bui-bg-surface-1:var(--bui-white);--bui-bg-surface-2:var(--bui-gray-1);--bui-bg-surface-3:var(--bui-gray-2);--bui-bg-solid:#1f5493;--bui-bg-solid-hover:#163a66;--bui-bg-solid-pressed:#0f2b4e;--bui-bg-solid-disabled:#ebebeb;--bui-bg-tint:transparent;--bui-bg-tint-hover:#1f549366;--bui-bg-tint-pressed:#1f549399;--bui-bg-tint-disabled:#ebebeb;--bui-bg-danger:#feebe7;--bui-bg-warning:#fff2b2;--bui-bg-success:#e6f6eb;--bui-fg-primary:var(--bui-black);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:#1f5493;--bui-fg-link-hover:#1f2d5c;--bui-fg-disabled:#9e9e9e;--bui-fg-solid:var(--bui-white);--bui-fg-solid-disabled:#9c9c9c;--bui-fg-tint:#1f5493;--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:#0000001a;--bui-border-hover:#0003;--bui-border-pressed:#0006;--bui-border-disabled:#0000001a;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#1f5493;--bui-scrollbar:#a0a0a03b;--bui-scrollbar-thumb:#a0a0a0;--bui-animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite}[data-theme-mode=dark]{--bui-gray-1:#191919;--bui-gray-2:#242424;--bui-gray-3:#373737;--bui-gray-4:#464646;--bui-gray-5:#575757;--bui-gray-6:#7b7b7b;--bui-gray-7:#9e9e9e;--bui-gray-8:#b4b4b4;--bui-bg-surface-0:#333;--bui-bg-surface-1:var(--bui-gray-1);--bui-bg-surface-2:var(--bui-gray-2);--bui-bg-surface-3:var(--bui-gray-3);--bui-bg-solid:#9cc9ff;--bui-bg-solid-hover:#83b9fd;--bui-bg-solid-pressed:#83b9fd;--bui-bg-solid-disabled:#222;--bui-bg-tint:transparent;--bui-bg-tint-hover:#9cc9ff1f;--bui-bg-tint-pressed:#9cc9ff29;--bui-bg-tint-disabled:transparent;--bui-bg-danger:#3b1219;--bui-bg-warning:#302008;--bui-bg-success:#132d21;--bui-fg-primary:var(--bui-white);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:#9cc9ff;--bui-fg-link-hover:#7eb5f7;--bui-fg-disabled:var(--bui-gray-7);--bui-fg-solid:#101821;--bui-fg-solid-disabled:var(--bui-gray-5);--bui-fg-tint:#9cc9ff;--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:#ffffff1f;--bui-border-hover:#fff6;--bui-border-pressed:#ffffff80;--bui-border-disabled:#fff3;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#1f5493;--bui-scrollbar:#3636363a;--bui-scrollbar-thumb:#575757}}@layer base{*,:before,:after{box-sizing:border-box}html{-webkit-text-size-adjust:100%;tab-size:4;font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;line-height:1.15}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentColor}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}:where(a){color:inherit;text-decoration:none}@keyframes pulse{50%{opacity:.5}}body{background-color:var(--bui-bg-surface-0);color:var(--bui-fg-primary);font-family:var(--bui-font-regular);font-weight:var(--bui-font-weight-regular);font-size:var(--bui-font-size-3);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[data-theme-mode=dark]{color-scheme:dark}[data-theme-mode=light]{color-scheme:light}}@layer components;@layer utilities{.bui-p{padding:var(--p)}.bui-p-0\.5{padding:var(--bui-space-0_5)}.bui-p-1{padding:var(--bui-space-1)}.bui-p-1\.5{padding:var(--bui-space-1_5)}.bui-p-2{padding:var(--bui-space-2)}.bui-p-3{padding:var(--bui-space-3)}.bui-p-4{padding:var(--bui-space-4)}.bui-p-5{padding:var(--bui-space-5)}.bui-p-6{padding:var(--bui-space-6)}.bui-p-7{padding:var(--bui-space-7)}.bui-p-8{padding:var(--bui-space-8)}.bui-p-9{padding:var(--bui-space-9)}.bui-p-10{padding:var(--bui-space-10)}.bui-p-11{padding:var(--bui-space-11)}.bui-p-12{padding:var(--bui-space-12)}.bui-p-13{padding:var(--bui-space-13)}.bui-p-14{padding:var(--bui-space-14)}@media (width>=640px){.xs\:bui-p{padding:var(--p-xs)}.xs\:bui-p-0\.5{padding:var(--bui-space-0_5)}.xs\:bui-p-1{padding:var(--bui-space-1)}.xs\:bui-p-1\.5{padding:var(--bui-space-1_5)}.xs\:bui-p-2{padding:var(--bui-space-2)}.xs\:bui-p-3{padding:var(--bui-space-3)}.xs\:bui-p-4{padding:var(--bui-space-4)}.xs\:bui-p-5{padding:var(--bui-space-5)}.xs\:bui-p-6{padding:var(--bui-space-6)}.xs\:bui-p-7{padding:var(--bui-space-7)}.xs\:bui-p-8{padding:var(--bui-space-8)}.xs\:bui-p-9{padding:var(--bui-space-9)}.xs\:bui-p-10{padding:var(--bui-space-10)}.xs\:bui-p-11{padding:var(--bui-space-11)}.xs\:bui-p-12{padding:var(--bui-space-12)}.xs\:bui-p-13{padding:var(--bui-space-13)}.xs\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-p{padding:var(--p-sm)}.sm\:bui-p-0\.5{padding:var(--bui-space-0_5)}.sm\:bui-p-1{padding:var(--bui-space-1)}.sm\:bui-p-1\.5{padding:var(--bui-space-1_5)}.sm\:bui-p-2{padding:var(--bui-space-2)}.sm\:bui-p-3{padding:var(--bui-space-3)}.sm\:bui-p-4{padding:var(--bui-space-4)}.sm\:bui-p-5{padding:var(--bui-space-5)}.sm\:bui-p-6{padding:var(--bui-space-6)}.sm\:bui-p-7{padding:var(--bui-space-7)}.sm\:bui-p-8{padding:var(--bui-space-8)}.sm\:bui-p-9{padding:var(--bui-space-9)}.sm\:bui-p-10{padding:var(--bui-space-10)}.sm\:bui-p-11{padding:var(--bui-space-11)}.sm\:bui-p-12{padding:var(--bui-space-12)}.sm\:bui-p-13{padding:var(--bui-space-13)}.sm\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-p{padding:var(--p-md)}.md\:bui-p-0\.5{padding:var(--bui-space-0_5)}.md\:bui-p-1{padding:var(--bui-space-1)}.md\:bui-p-1\.5{padding:var(--bui-space-1_5)}.md\:bui-p-2{padding:var(--bui-space-2)}.md\:bui-p-3{padding:var(--bui-space-3)}.md\:bui-p-4{padding:var(--bui-space-4)}.md\:bui-p-5{padding:var(--bui-space-5)}.md\:bui-p-6{padding:var(--bui-space-6)}.md\:bui-p-7{padding:var(--bui-space-7)}.md\:bui-p-8{padding:var(--bui-space-8)}.md\:bui-p-9{padding:var(--bui-space-9)}.md\:bui-p-10{padding:var(--bui-space-10)}.md\:bui-p-11{padding:var(--bui-space-11)}.md\:bui-p-12{padding:var(--bui-space-12)}.md\:bui-p-13{padding:var(--bui-space-13)}.md\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-p{padding:var(--p-lg)}.lg\:bui-p-0\.5{padding:var(--bui-space-0_5)}.lg\:bui-p-1{padding:var(--bui-space-1)}.lg\:bui-p-1\.5{padding:var(--bui-space-1_5)}.lg\:bui-p-2{padding:var(--bui-space-2)}.lg\:bui-p-3{padding:var(--bui-space-3)}.lg\:bui-p-4{padding:var(--bui-space-4)}.lg\:bui-p-5{padding:var(--bui-space-5)}.lg\:bui-p-6{padding:var(--bui-space-6)}.lg\:bui-p-7{padding:var(--bui-space-7)}.lg\:bui-p-8{padding:var(--bui-space-8)}.lg\:bui-p-9{padding:var(--bui-space-9)}.lg\:bui-p-10{padding:var(--bui-space-10)}.lg\:bui-p-11{padding:var(--bui-space-11)}.lg\:bui-p-12{padding:var(--bui-space-12)}.lg\:bui-p-13{padding:var(--bui-space-13)}.lg\:bui-p-14{padding:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-p{padding:var(--p-xl)}.xl\:bui-p-0\.5{padding:var(--bui-space-0_5)}.xl\:bui-p-1{padding:var(--bui-space-1)}.xl\:bui-p-1\.5{padding:var(--bui-space-1_5)}.xl\:bui-p-2{padding:var(--bui-space-2)}.xl\:bui-p-3{padding:var(--bui-space-3)}.xl\:bui-p-4{padding:var(--bui-space-4)}.xl\:bui-p-5{padding:var(--bui-space-5)}.xl\:bui-p-6{padding:var(--bui-space-6)}.xl\:bui-p-7{padding:var(--bui-space-7)}.xl\:bui-p-8{padding:var(--bui-space-8)}.xl\:bui-p-9{padding:var(--bui-space-9)}.xl\:bui-p-10{padding:var(--bui-space-10)}.xl\:bui-p-11{padding:var(--bui-space-11)}.xl\:bui-p-12{padding:var(--bui-space-12)}.xl\:bui-p-13{padding:var(--bui-space-13)}.xl\:bui-p-14{padding:var(--bui-space-14)}}.bui-pl{padding-left:var(--pl)}.bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.bui-pl-1{padding-left:var(--bui-space-1)}.bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.bui-pl-2{padding-left:var(--bui-space-2)}.bui-pl-3{padding-left:var(--bui-space-3)}.bui-pl-4{padding-left:var(--bui-space-4)}.bui-pl-5{padding-left:var(--bui-space-5)}.bui-pl-6{padding-left:var(--bui-space-6)}.bui-pl-7{padding-left:var(--bui-space-7)}.bui-pl-8{padding-left:var(--bui-space-8)}.bui-pl-9{padding-left:var(--bui-space-9)}.bui-pl-10{padding-left:var(--bui-space-10)}.bui-pl-11{padding-left:var(--bui-space-11)}.bui-pl-12{padding-left:var(--bui-space-12)}.bui-pl-13{padding-left:var(--bui-space-13)}.bui-pl-14{padding-left:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pl{padding-left:var(--pl-xs)}.xs\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.xs\:bui-pl-1{padding-left:var(--bui-space-1)}.xs\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.xs\:bui-pl-2{padding-left:var(--bui-space-2)}.xs\:bui-pl-3{padding-left:var(--bui-space-3)}.xs\:bui-pl-4{padding-left:var(--bui-space-4)}.xs\:bui-pl-5{padding-left:var(--bui-space-5)}.xs\:bui-pl-6{padding-left:var(--bui-space-6)}.xs\:bui-pl-7{padding-left:var(--bui-space-7)}.xs\:bui-pl-8{padding-left:var(--bui-space-8)}.xs\:bui-pl-9{padding-left:var(--bui-space-9)}.xs\:bui-pl-10{padding-left:var(--bui-space-10)}.xs\:bui-pl-11{padding-left:var(--bui-space-11)}.xs\:bui-pl-12{padding-left:var(--bui-space-12)}.xs\:bui-pl-13{padding-left:var(--bui-space-13)}.xs\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pl{padding-left:var(--pl-sm)}.sm\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.sm\:bui-pl-1{padding-left:var(--bui-space-1)}.sm\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.sm\:bui-pl-2{padding-left:var(--bui-space-2)}.sm\:bui-pl-3{padding-left:var(--bui-space-3)}.sm\:bui-pl-4{padding-left:var(--bui-space-4)}.sm\:bui-pl-5{padding-left:var(--bui-space-5)}.sm\:bui-pl-6{padding-left:var(--bui-space-6)}.sm\:bui-pl-7{padding-left:var(--bui-space-7)}.sm\:bui-pl-8{padding-left:var(--bui-space-8)}.sm\:bui-pl-9{padding-left:var(--bui-space-9)}.sm\:bui-pl-10{padding-left:var(--bui-space-10)}.sm\:bui-pl-11{padding-left:var(--bui-space-11)}.sm\:bui-pl-12{padding-left:var(--bui-space-12)}.sm\:bui-pl-13{padding-left:var(--bui-space-13)}.sm\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pl{padding-left:var(--pl-md)}.md\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.md\:bui-pl-1{padding-left:var(--bui-space-1)}.md\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.md\:bui-pl-2{padding-left:var(--bui-space-2)}.md\:bui-pl-3{padding-left:var(--bui-space-3)}.md\:bui-pl-4{padding-left:var(--bui-space-4)}.md\:bui-pl-5{padding-left:var(--bui-space-5)}.md\:bui-pl-6{padding-left:var(--bui-space-6)}.md\:bui-pl-7{padding-left:var(--bui-space-7)}.md\:bui-pl-8{padding-left:var(--bui-space-8)}.md\:bui-pl-9{padding-left:var(--bui-space-9)}.md\:bui-pl-10{padding-left:var(--bui-space-10)}.md\:bui-pl-11{padding-left:var(--bui-space-11)}.md\:bui-pl-12{padding-left:var(--bui-space-12)}.md\:bui-pl-13{padding-left:var(--bui-space-13)}.md\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pl{padding-left:var(--pl-lg)}.lg\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.lg\:bui-pl-1{padding-left:var(--bui-space-1)}.lg\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.lg\:bui-pl-2{padding-left:var(--bui-space-2)}.lg\:bui-pl-3{padding-left:var(--bui-space-3)}.lg\:bui-pl-4{padding-left:var(--bui-space-4)}.lg\:bui-pl-5{padding-left:var(--bui-space-5)}.lg\:bui-pl-6{padding-left:var(--bui-space-6)}.lg\:bui-pl-7{padding-left:var(--bui-space-7)}.lg\:bui-pl-8{padding-left:var(--bui-space-8)}.lg\:bui-pl-9{padding-left:var(--bui-space-9)}.lg\:bui-pl-10{padding-left:var(--bui-space-10)}.lg\:bui-pl-11{padding-left:var(--bui-space-11)}.lg\:bui-pl-12{padding-left:var(--bui-space-12)}.lg\:bui-pl-13{padding-left:var(--bui-space-13)}.lg\:bui-pl-14{padding-left:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pl{padding-left:var(--pl-xl)}.xl\:bui-pl-0\.5{padding-left:var(--bui-space-0_5)}.xl\:bui-pl-1{padding-left:var(--bui-space-1)}.xl\:bui-pl-1\.5{padding-left:var(--bui-space-1_5)}.xl\:bui-pl-2{padding-left:var(--bui-space-2)}.xl\:bui-pl-3{padding-left:var(--bui-space-3)}.xl\:bui-pl-4{padding-left:var(--bui-space-4)}.xl\:bui-pl-5{padding-left:var(--bui-space-5)}.xl\:bui-pl-6{padding-left:var(--bui-space-6)}.xl\:bui-pl-7{padding-left:var(--bui-space-7)}.xl\:bui-pl-8{padding-left:var(--bui-space-8)}.xl\:bui-pl-9{padding-left:var(--bui-space-9)}.xl\:bui-pl-10{padding-left:var(--bui-space-10)}.xl\:bui-pl-11{padding-left:var(--bui-space-11)}.xl\:bui-pl-12{padding-left:var(--bui-space-12)}.xl\:bui-pl-13{padding-left:var(--bui-space-13)}.xl\:bui-pl-14{padding-left:var(--bui-space-14)}}.bui-pr{padding-right:var(--pr)}.bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.bui-pr-1{padding-right:var(--bui-space-1)}.bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.bui-pr-2{padding-right:var(--bui-space-2)}.bui-pr-3{padding-right:var(--bui-space-3)}.bui-pr-4{padding-right:var(--bui-space-4)}.bui-pr-5{padding-right:var(--bui-space-5)}.bui-pr-6{padding-right:var(--bui-space-6)}.bui-pr-7{padding-right:var(--bui-space-7)}.bui-pr-8{padding-right:var(--bui-space-8)}.bui-pr-9{padding-right:var(--bui-space-9)}.bui-pr-10{padding-right:var(--bui-space-10)}.bui-pr-11{padding-right:var(--bui-space-11)}.bui-pr-12{padding-right:var(--bui-space-12)}.bui-pr-13{padding-right:var(--bui-space-13)}.bui-pr-14{padding-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pr{padding-right:var(--pr-xs)}.xs\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.xs\:bui-pr-1{padding-right:var(--bui-space-1)}.xs\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.xs\:bui-pr-2{padding-right:var(--bui-space-2)}.xs\:bui-pr-3{padding-right:var(--bui-space-3)}.xs\:bui-pr-4{padding-right:var(--bui-space-4)}.xs\:bui-pr-5{padding-right:var(--bui-space-5)}.xs\:bui-pr-6{padding-right:var(--bui-space-6)}.xs\:bui-pr-7{padding-right:var(--bui-space-7)}.xs\:bui-pr-8{padding-right:var(--bui-space-8)}.xs\:bui-pr-9{padding-right:var(--bui-space-9)}.xs\:bui-pr-10{padding-right:var(--bui-space-10)}.xs\:bui-pr-11{padding-right:var(--bui-space-11)}.xs\:bui-pr-12{padding-right:var(--bui-space-12)}.xs\:bui-pr-13{padding-right:var(--bui-space-13)}.xs\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pr{padding-right:var(--pr-sm)}.sm\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.sm\:bui-pr-1{padding-right:var(--bui-space-1)}.sm\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.sm\:bui-pr-2{padding-right:var(--bui-space-2)}.sm\:bui-pr-3{padding-right:var(--bui-space-3)}.sm\:bui-pr-4{padding-right:var(--bui-space-4)}.sm\:bui-pr-5{padding-right:var(--bui-space-5)}.sm\:bui-pr-6{padding-right:var(--bui-space-6)}.sm\:bui-pr-7{padding-right:var(--bui-space-7)}.sm\:bui-pr-8{padding-right:var(--bui-space-8)}.sm\:bui-pr-9{padding-right:var(--bui-space-9)}.sm\:bui-pr-10{padding-right:var(--bui-space-10)}.sm\:bui-pr-11{padding-right:var(--bui-space-11)}.sm\:bui-pr-12{padding-right:var(--bui-space-12)}.sm\:bui-pr-13{padding-right:var(--bui-space-13)}.sm\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pr{padding-right:var(--pr-md)}.md\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.md\:bui-pr-1{padding-right:var(--bui-space-1)}.md\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.md\:bui-pr-2{padding-right:var(--bui-space-2)}.md\:bui-pr-3{padding-right:var(--bui-space-3)}.md\:bui-pr-4{padding-right:var(--bui-space-4)}.md\:bui-pr-5{padding-right:var(--bui-space-5)}.md\:bui-pr-6{padding-right:var(--bui-space-6)}.md\:bui-pr-7{padding-right:var(--bui-space-7)}.md\:bui-pr-8{padding-right:var(--bui-space-8)}.md\:bui-pr-9{padding-right:var(--bui-space-9)}.md\:bui-pr-10{padding-right:var(--bui-space-10)}.md\:bui-pr-11{padding-right:var(--bui-space-11)}.md\:bui-pr-12{padding-right:var(--bui-space-12)}.md\:bui-pr-13{padding-right:var(--bui-space-13)}.md\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pr{padding-right:var(--pr-lg)}.lg\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.lg\:bui-pr-1{padding-right:var(--bui-space-1)}.lg\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.lg\:bui-pr-2{padding-right:var(--bui-space-2)}.lg\:bui-pr-3{padding-right:var(--bui-space-3)}.lg\:bui-pr-4{padding-right:var(--bui-space-4)}.lg\:bui-pr-5{padding-right:var(--bui-space-5)}.lg\:bui-pr-6{padding-right:var(--bui-space-6)}.lg\:bui-pr-7{padding-right:var(--bui-space-7)}.lg\:bui-pr-8{padding-right:var(--bui-space-8)}.lg\:bui-pr-9{padding-right:var(--bui-space-9)}.lg\:bui-pr-10{padding-right:var(--bui-space-10)}.lg\:bui-pr-11{padding-right:var(--bui-space-11)}.lg\:bui-pr-12{padding-right:var(--bui-space-12)}.lg\:bui-pr-13{padding-right:var(--bui-space-13)}.lg\:bui-pr-14{padding-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pr{padding-right:var(--pr-xl)}.xl\:bui-pr-0\.5{padding-right:var(--bui-space-0_5)}.xl\:bui-pr-1{padding-right:var(--bui-space-1)}.xl\:bui-pr-1\.5{padding-right:var(--bui-space-1_5)}.xl\:bui-pr-2{padding-right:var(--bui-space-2)}.xl\:bui-pr-3{padding-right:var(--bui-space-3)}.xl\:bui-pr-4{padding-right:var(--bui-space-4)}.xl\:bui-pr-5{padding-right:var(--bui-space-5)}.xl\:bui-pr-6{padding-right:var(--bui-space-6)}.xl\:bui-pr-7{padding-right:var(--bui-space-7)}.xl\:bui-pr-8{padding-right:var(--bui-space-8)}.xl\:bui-pr-9{padding-right:var(--bui-space-9)}.xl\:bui-pr-10{padding-right:var(--bui-space-10)}.xl\:bui-pr-11{padding-right:var(--bui-space-11)}.xl\:bui-pr-12{padding-right:var(--bui-space-12)}.xl\:bui-pr-13{padding-right:var(--bui-space-13)}.xl\:bui-pr-14{padding-right:var(--bui-space-14)}}.bui-pt{padding-top:var(--pt)}.bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.bui-pt-1{padding-top:var(--bui-space-1)}.bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.bui-pt-2{padding-top:var(--bui-space-2)}.bui-pt-3{padding-top:var(--bui-space-3)}.bui-pt-4{padding-top:var(--bui-space-4)}.bui-pt-5{padding-top:var(--bui-space-5)}.bui-pt-6{padding-top:var(--bui-space-6)}.bui-pt-7{padding-top:var(--bui-space-7)}.bui-pt-8{padding-top:var(--bui-space-8)}.bui-pt-9{padding-top:var(--bui-space-9)}.bui-pt-10{padding-top:var(--bui-space-10)}.bui-pt-11{padding-top:var(--bui-space-11)}.bui-pt-12{padding-top:var(--bui-space-12)}.bui-pt-13{padding-top:var(--bui-space-13)}.bui-pt-14{padding-top:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pt{padding-top:var(--pt-xs)}.xs\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.xs\:bui-pt-1{padding-top:var(--bui-space-1)}.xs\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.xs\:bui-pt-2{padding-top:var(--bui-space-2)}.xs\:bui-pt-3{padding-top:var(--bui-space-3)}.xs\:bui-pt-4{padding-top:var(--bui-space-4)}.xs\:bui-pt-5{padding-top:var(--bui-space-5)}.xs\:bui-pt-6{padding-top:var(--bui-space-6)}.xs\:bui-pt-7{padding-top:var(--bui-space-7)}.xs\:bui-pt-8{padding-top:var(--bui-space-8)}.xs\:bui-pt-9{padding-top:var(--bui-space-9)}.xs\:bui-pt-10{padding-top:var(--bui-space-10)}.xs\:bui-pt-11{padding-top:var(--bui-space-11)}.xs\:bui-pt-12{padding-top:var(--bui-space-12)}.xs\:bui-pt-13{padding-top:var(--bui-space-13)}.xs\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pt{padding-top:var(--pt-sm)}.sm\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.sm\:bui-pt-1{padding-top:var(--bui-space-1)}.sm\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.sm\:bui-pt-2{padding-top:var(--bui-space-2)}.sm\:bui-pt-3{padding-top:var(--bui-space-3)}.sm\:bui-pt-4{padding-top:var(--bui-space-4)}.sm\:bui-pt-5{padding-top:var(--bui-space-5)}.sm\:bui-pt-6{padding-top:var(--bui-space-6)}.sm\:bui-pt-7{padding-top:var(--bui-space-7)}.sm\:bui-pt-8{padding-top:var(--bui-space-8)}.sm\:bui-pt-9{padding-top:var(--bui-space-9)}.sm\:bui-pt-10{padding-top:var(--bui-space-10)}.sm\:bui-pt-11{padding-top:var(--bui-space-11)}.sm\:bui-pt-12{padding-top:var(--bui-space-12)}.sm\:bui-pt-13{padding-top:var(--bui-space-13)}.sm\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pt{padding-top:var(--pt-md)}.md\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.md\:bui-pt-1{padding-top:var(--bui-space-1)}.md\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.md\:bui-pt-2{padding-top:var(--bui-space-2)}.md\:bui-pt-3{padding-top:var(--bui-space-3)}.md\:bui-pt-4{padding-top:var(--bui-space-4)}.md\:bui-pt-5{padding-top:var(--bui-space-5)}.md\:bui-pt-6{padding-top:var(--bui-space-6)}.md\:bui-pt-7{padding-top:var(--bui-space-7)}.md\:bui-pt-8{padding-top:var(--bui-space-8)}.md\:bui-pt-9{padding-top:var(--bui-space-9)}.md\:bui-pt-10{padding-top:var(--bui-space-10)}.md\:bui-pt-11{padding-top:var(--bui-space-11)}.md\:bui-pt-12{padding-top:var(--bui-space-12)}.md\:bui-pt-13{padding-top:var(--bui-space-13)}.md\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pt{padding-top:var(--pt-lg)}.lg\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.lg\:bui-pt-1{padding-top:var(--bui-space-1)}.lg\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.lg\:bui-pt-2{padding-top:var(--bui-space-2)}.lg\:bui-pt-3{padding-top:var(--bui-space-3)}.lg\:bui-pt-4{padding-top:var(--bui-space-4)}.lg\:bui-pt-5{padding-top:var(--bui-space-5)}.lg\:bui-pt-6{padding-top:var(--bui-space-6)}.lg\:bui-pt-7{padding-top:var(--bui-space-7)}.lg\:bui-pt-8{padding-top:var(--bui-space-8)}.lg\:bui-pt-9{padding-top:var(--bui-space-9)}.lg\:bui-pt-10{padding-top:var(--bui-space-10)}.lg\:bui-pt-11{padding-top:var(--bui-space-11)}.lg\:bui-pt-12{padding-top:var(--bui-space-12)}.lg\:bui-pt-13{padding-top:var(--bui-space-13)}.lg\:bui-pt-14{padding-top:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pt{padding-top:var(--pt-xl)}.xl\:bui-pt-0\.5{padding-top:var(--bui-space-0_5)}.xl\:bui-pt-1{padding-top:var(--bui-space-1)}.xl\:bui-pt-1\.5{padding-top:var(--bui-space-1_5)}.xl\:bui-pt-2{padding-top:var(--bui-space-2)}.xl\:bui-pt-3{padding-top:var(--bui-space-3)}.xl\:bui-pt-4{padding-top:var(--bui-space-4)}.xl\:bui-pt-5{padding-top:var(--bui-space-5)}.xl\:bui-pt-6{padding-top:var(--bui-space-6)}.xl\:bui-pt-7{padding-top:var(--bui-space-7)}.xl\:bui-pt-8{padding-top:var(--bui-space-8)}.xl\:bui-pt-9{padding-top:var(--bui-space-9)}.xl\:bui-pt-10{padding-top:var(--bui-space-10)}.xl\:bui-pt-11{padding-top:var(--bui-space-11)}.xl\:bui-pt-12{padding-top:var(--bui-space-12)}.xl\:bui-pt-13{padding-top:var(--bui-space-13)}.xl\:bui-pt-14{padding-top:var(--bui-space-14)}}.bui-pb{padding-bottom:var(--pb)}.bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.bui-pb-1{padding-bottom:var(--bui-space-1)}.bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.bui-pb-2{padding-bottom:var(--bui-space-2)}.bui-pb-3{padding-bottom:var(--bui-space-3)}.bui-pb-4{padding-bottom:var(--bui-space-4)}.bui-pb-5{padding-bottom:var(--bui-space-5)}.bui-pb-6{padding-bottom:var(--bui-space-6)}.bui-pb-7{padding-bottom:var(--bui-space-7)}.bui-pb-8{padding-bottom:var(--bui-space-8)}.bui-pb-9{padding-bottom:var(--bui-space-9)}.bui-pb-10{padding-bottom:var(--bui-space-10)}.bui-pb-11{padding-bottom:var(--bui-space-11)}.bui-pb-12{padding-bottom:var(--bui-space-12)}.bui-pb-13{padding-bottom:var(--bui-space-13)}.bui-pb-14{padding-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-pb{padding-bottom:var(--pb-xs)}.xs\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.xs\:bui-pb-1{padding-bottom:var(--bui-space-1)}.xs\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.xs\:bui-pb-2{padding-bottom:var(--bui-space-2)}.xs\:bui-pb-3{padding-bottom:var(--bui-space-3)}.xs\:bui-pb-4{padding-bottom:var(--bui-space-4)}.xs\:bui-pb-5{padding-bottom:var(--bui-space-5)}.xs\:bui-pb-6{padding-bottom:var(--bui-space-6)}.xs\:bui-pb-7{padding-bottom:var(--bui-space-7)}.xs\:bui-pb-8{padding-bottom:var(--bui-space-8)}.xs\:bui-pb-9{padding-bottom:var(--bui-space-9)}.xs\:bui-pb-10{padding-bottom:var(--bui-space-10)}.xs\:bui-pb-11{padding-bottom:var(--bui-space-11)}.xs\:bui-pb-12{padding-bottom:var(--bui-space-12)}.xs\:bui-pb-13{padding-bottom:var(--bui-space-13)}.xs\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-pb{padding-bottom:var(--pb-sm)}.sm\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.sm\:bui-pb-1{padding-bottom:var(--bui-space-1)}.sm\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.sm\:bui-pb-2{padding-bottom:var(--bui-space-2)}.sm\:bui-pb-3{padding-bottom:var(--bui-space-3)}.sm\:bui-pb-4{padding-bottom:var(--bui-space-4)}.sm\:bui-pb-5{padding-bottom:var(--bui-space-5)}.sm\:bui-pb-6{padding-bottom:var(--bui-space-6)}.sm\:bui-pb-7{padding-bottom:var(--bui-space-7)}.sm\:bui-pb-8{padding-bottom:var(--bui-space-8)}.sm\:bui-pb-9{padding-bottom:var(--bui-space-9)}.sm\:bui-pb-10{padding-bottom:var(--bui-space-10)}.sm\:bui-pb-11{padding-bottom:var(--bui-space-11)}.sm\:bui-pb-12{padding-bottom:var(--bui-space-12)}.sm\:bui-pb-13{padding-bottom:var(--bui-space-13)}.sm\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-pb{padding-bottom:var(--pb-md)}.md\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.md\:bui-pb-1{padding-bottom:var(--bui-space-1)}.md\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.md\:bui-pb-2{padding-bottom:var(--bui-space-2)}.md\:bui-pb-3{padding-bottom:var(--bui-space-3)}.md\:bui-pb-4{padding-bottom:var(--bui-space-4)}.md\:bui-pb-5{padding-bottom:var(--bui-space-5)}.md\:bui-pb-6{padding-bottom:var(--bui-space-6)}.md\:bui-pb-7{padding-bottom:var(--bui-space-7)}.md\:bui-pb-8{padding-bottom:var(--bui-space-8)}.md\:bui-pb-9{padding-bottom:var(--bui-space-9)}.md\:bui-pb-10{padding-bottom:var(--bui-space-10)}.md\:bui-pb-11{padding-bottom:var(--bui-space-11)}.md\:bui-pb-12{padding-bottom:var(--bui-space-12)}.md\:bui-pb-13{padding-bottom:var(--bui-space-13)}.md\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-pb{padding-bottom:var(--pb-lg)}.lg\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.lg\:bui-pb-1{padding-bottom:var(--bui-space-1)}.lg\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.lg\:bui-pb-2{padding-bottom:var(--bui-space-2)}.lg\:bui-pb-3{padding-bottom:var(--bui-space-3)}.lg\:bui-pb-4{padding-bottom:var(--bui-space-4)}.lg\:bui-pb-5{padding-bottom:var(--bui-space-5)}.lg\:bui-pb-6{padding-bottom:var(--bui-space-6)}.lg\:bui-pb-7{padding-bottom:var(--bui-space-7)}.lg\:bui-pb-8{padding-bottom:var(--bui-space-8)}.lg\:bui-pb-9{padding-bottom:var(--bui-space-9)}.lg\:bui-pb-10{padding-bottom:var(--bui-space-10)}.lg\:bui-pb-11{padding-bottom:var(--bui-space-11)}.lg\:bui-pb-12{padding-bottom:var(--bui-space-12)}.lg\:bui-pb-13{padding-bottom:var(--bui-space-13)}.lg\:bui-pb-14{padding-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-pb{padding-bottom:var(--pb-xl)}.xl\:bui-pb-0\.5{padding-bottom:var(--bui-space-0_5)}.xl\:bui-pb-1{padding-bottom:var(--bui-space-1)}.xl\:bui-pb-1\.5{padding-bottom:var(--bui-space-1_5)}.xl\:bui-pb-2{padding-bottom:var(--bui-space-2)}.xl\:bui-pb-3{padding-bottom:var(--bui-space-3)}.xl\:bui-pb-4{padding-bottom:var(--bui-space-4)}.xl\:bui-pb-5{padding-bottom:var(--bui-space-5)}.xl\:bui-pb-6{padding-bottom:var(--bui-space-6)}.xl\:bui-pb-7{padding-bottom:var(--bui-space-7)}.xl\:bui-pb-8{padding-bottom:var(--bui-space-8)}.xl\:bui-pb-9{padding-bottom:var(--bui-space-9)}.xl\:bui-pb-10{padding-bottom:var(--bui-space-10)}.xl\:bui-pb-11{padding-bottom:var(--bui-space-11)}.xl\:bui-pb-12{padding-bottom:var(--bui-space-12)}.xl\:bui-pb-13{padding-bottom:var(--bui-space-13)}.xl\:bui-pb-14{padding-bottom:var(--bui-space-14)}}.bui-py{padding-top:var(--py);padding-bottom:var(--py)}.bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-py{padding-top:var(--py-xs);padding-bottom:var(--py-xs)}.xs\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.xs\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.xs\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.xs\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.xs\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.xs\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.xs\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.xs\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.xs\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.xs\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.xs\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.xs\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.xs\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.xs\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.xs\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.xs\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-py{padding-top:var(--py-sm);padding-bottom:var(--py-sm)}.sm\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.sm\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.sm\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.sm\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.sm\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.sm\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.sm\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.sm\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.sm\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.sm\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.sm\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.sm\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.sm\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.sm\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.sm\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.sm\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-py{padding-top:var(--py-md);padding-bottom:var(--py-md)}.md\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.md\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.md\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.md\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.md\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.md\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.md\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.md\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.md\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.md\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.md\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.md\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.md\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.md\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.md\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.md\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-py{padding-top:var(--py-lg);padding-bottom:var(--py-lg)}.lg\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.lg\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.lg\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.lg\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.lg\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.lg\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.lg\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.lg\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.lg\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.lg\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.lg\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.lg\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.lg\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.lg\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.lg\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.lg\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-py{padding-top:var(--py-xl);padding-bottom:var(--py-xl)}.xl\:bui-py-0\.5{padding-top:var(--bui-space-0_5);padding-bottom:var(--bui-space-0_5)}.xl\:bui-py-1{padding-top:var(--bui-space-1);padding-bottom:var(--bui-space-1)}.xl\:bui-py-1\.5{padding-top:var(--bui-space-1_5);padding-bottom:var(--bui-space-1_5)}.xl\:bui-py-2{padding-top:var(--bui-space-2);padding-bottom:var(--bui-space-2)}.xl\:bui-py-3{padding-top:var(--bui-space-3);padding-bottom:var(--bui-space-3)}.xl\:bui-py-4{padding-top:var(--bui-space-4);padding-bottom:var(--bui-space-4)}.xl\:bui-py-5{padding-top:var(--bui-space-5);padding-bottom:var(--bui-space-5)}.xl\:bui-py-6{padding-top:var(--bui-space-6);padding-bottom:var(--bui-space-6)}.xl\:bui-py-7{padding-top:var(--bui-space-7);padding-bottom:var(--bui-space-7)}.xl\:bui-py-8{padding-top:var(--bui-space-8);padding-bottom:var(--bui-space-8)}.xl\:bui-py-9{padding-top:var(--bui-space-9);padding-bottom:var(--bui-space-9)}.xl\:bui-py-10{padding-top:var(--bui-space-10);padding-bottom:var(--bui-space-10)}.xl\:bui-py-11{padding-top:var(--bui-space-11);padding-bottom:var(--bui-space-11)}.xl\:bui-py-12{padding-top:var(--bui-space-12);padding-bottom:var(--bui-space-12)}.xl\:bui-py-13{padding-top:var(--bui-space-13);padding-bottom:var(--bui-space-13)}.xl\:bui-py-14{padding-top:var(--bui-space-14);padding-bottom:var(--bui-space-14)}}.bui-px{padding-left:var(--px);padding-right:var(--px)}.bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-px{padding-left:var(--px-xs);padding-right:var(--px-xs)}.xs\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.xs\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.xs\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.xs\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.xs\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.xs\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.xs\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.xs\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.xs\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.xs\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.xs\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.xs\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.xs\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.xs\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.xs\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.xs\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-px{padding-left:var(--px-sm);padding-right:var(--px-sm)}.sm\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.sm\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.sm\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.sm\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.sm\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.sm\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.sm\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.sm\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.sm\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.sm\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.sm\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.sm\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.sm\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.sm\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.sm\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.sm\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-px{padding-left:var(--px-md);padding-right:var(--px-md)}.md\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.md\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.md\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.md\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.md\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.md\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.md\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.md\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.md\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.md\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.md\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.md\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.md\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.md\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.md\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.md\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-px{padding-left:var(--px-lg);padding-right:var(--px-lg)}.lg\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.lg\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.lg\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.lg\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.lg\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.lg\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.lg\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.lg\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.lg\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.lg\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.lg\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.lg\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.lg\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.lg\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.lg\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.lg\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-px{padding-left:var(--px-xl);padding-right:var(--px-xl)}.xl\:bui-px-0\.5{padding-left:var(--bui-space-0_5);padding-right:var(--bui-space-0_5)}.xl\:bui-px-1{padding-left:var(--bui-space-1);padding-right:var(--bui-space-1)}.xl\:bui-px-1\.5{padding-left:var(--bui-space-1_5);padding-right:var(--bui-space-1_5)}.xl\:bui-px-2{padding-left:var(--bui-space-2);padding-right:var(--bui-space-2)}.xl\:bui-px-3{padding-left:var(--bui-space-3);padding-right:var(--bui-space-3)}.xl\:bui-px-4{padding-left:var(--bui-space-4);padding-right:var(--bui-space-4)}.xl\:bui-px-5{padding-left:var(--bui-space-5);padding-right:var(--bui-space-5)}.xl\:bui-px-6{padding-left:var(--bui-space-6);padding-right:var(--bui-space-6)}.xl\:bui-px-7{padding-left:var(--bui-space-7);padding-right:var(--bui-space-7)}.xl\:bui-px-8{padding-left:var(--bui-space-8);padding-right:var(--bui-space-8)}.xl\:bui-px-9{padding-left:var(--bui-space-9);padding-right:var(--bui-space-9)}.xl\:bui-px-10{padding-left:var(--bui-space-10);padding-right:var(--bui-space-10)}.xl\:bui-px-11{padding-left:var(--bui-space-11);padding-right:var(--bui-space-11)}.xl\:bui-px-12{padding-left:var(--bui-space-12);padding-right:var(--bui-space-12)}.xl\:bui-px-13{padding-left:var(--bui-space-13);padding-right:var(--bui-space-13)}.xl\:bui-px-14{padding-left:var(--bui-space-14);padding-right:var(--bui-space-14)}}.bui-m{margin:var(--m)}.bui-m-0\.5{margin:var(--bui-space-0_5)}.bui-m-1{margin:var(--bui-space-1)}.bui-m-1\.5{margin:var(--bui-space-1_5)}.bui-m-2{margin:var(--bui-space-2)}.bui-m-3{margin:var(--bui-space-3)}.bui-m-4{margin:var(--bui-space-4)}.bui-m-5{margin:var(--bui-space-5)}.bui-m-6{margin:var(--bui-space-6)}.bui-m-7{margin:var(--bui-space-7)}.bui-m-8{margin:var(--bui-space-8)}.bui-m-9{margin:var(--bui-space-9)}.bui-m-10{margin:var(--bui-space-10)}.bui-m-11{margin:var(--bui-space-11)}.bui-m-12{margin:var(--bui-space-12)}.bui-m-13{margin:var(--bui-space-13)}.bui-m-14{margin:var(--bui-space-14)}@media (width>=640px){.xs\:bui-m{margin:var(--p-xs)}.xs\:bui-m-0\.5{margin:var(--bui-space-0_5)}.xs\:bui-m-1{margin:var(--bui-space-1)}.xs\:bui-m-1\.5{margin:var(--bui-space-1_5)}.xs\:bui-m-2{margin:var(--bui-space-2)}.xs\:bui-m-3{margin:var(--bui-space-3)}.xs\:bui-m-4{margin:var(--bui-space-4)}.xs\:bui-m-5{margin:var(--bui-space-5)}.xs\:bui-m-6{margin:var(--bui-space-6)}.xs\:bui-m-7{margin:var(--bui-space-7)}.xs\:bui-m-8{margin:var(--bui-space-8)}.xs\:bui-m-9{margin:var(--bui-space-9)}.xs\:bui-m-10{margin:var(--bui-space-10)}.xs\:bui-m-11{margin:var(--bui-space-11)}.xs\:bui-m-12{margin:var(--bui-space-12)}.xs\:bui-m-13{margin:var(--bui-space-13)}.xs\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-m{margin:var(--p-sm)}.sm\:bui-m-0\.5{margin:var(--bui-space-0_5)}.sm\:bui-m-1{margin:var(--bui-space-1)}.sm\:bui-m-1\.5{margin:var(--bui-space-1_5)}.sm\:bui-m-2{margin:var(--bui-space-2)}.sm\:bui-m-3{margin:var(--bui-space-3)}.sm\:bui-m-4{margin:var(--bui-space-4)}.sm\:bui-m-5{margin:var(--bui-space-5)}.sm\:bui-m-6{margin:var(--bui-space-6)}.sm\:bui-m-7{margin:var(--bui-space-7)}.sm\:bui-m-8{margin:var(--bui-space-8)}.sm\:bui-m-9{margin:var(--bui-space-9)}.sm\:bui-m-10{margin:var(--bui-space-10)}.sm\:bui-m-11{margin:var(--bui-space-11)}.sm\:bui-m-12{margin:var(--bui-space-12)}.sm\:bui-m-13{margin:var(--bui-space-13)}.sm\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-m{margin:var(--p-md)}.md\:bui-m-0\.5{margin:var(--bui-space-0_5)}.md\:bui-m-1{margin:var(--bui-space-1)}.md\:bui-m-1\.5{margin:var(--bui-space-1_5)}.md\:bui-m-2{margin:var(--bui-space-2)}.md\:bui-m-3{margin:var(--bui-space-3)}.md\:bui-m-4{margin:var(--bui-space-4)}.md\:bui-m-5{margin:var(--bui-space-5)}.md\:bui-m-6{margin:var(--bui-space-6)}.md\:bui-m-7{margin:var(--bui-space-7)}.md\:bui-m-8{margin:var(--bui-space-8)}.md\:bui-m-9{margin:var(--bui-space-9)}.md\:bui-m-10{margin:var(--bui-space-10)}.md\:bui-m-11{margin:var(--bui-space-11)}.md\:bui-m-12{margin:var(--bui-space-12)}.md\:bui-m-13{margin:var(--bui-space-13)}.md\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-m{margin:var(--p-lg)}.lg\:bui-m-0\.5{margin:var(--bui-space-0_5)}.lg\:bui-m-1{margin:var(--bui-space-1)}.lg\:bui-m-1\.5{margin:var(--bui-space-1_5)}.lg\:bui-m-2{margin:var(--bui-space-2)}.lg\:bui-m-3{margin:var(--bui-space-3)}.lg\:bui-m-4{margin:var(--bui-space-4)}.lg\:bui-m-5{margin:var(--bui-space-5)}.lg\:bui-m-6{margin:var(--bui-space-6)}.lg\:bui-m-7{margin:var(--bui-space-7)}.lg\:bui-m-8{margin:var(--bui-space-8)}.lg\:bui-m-9{margin:var(--bui-space-9)}.lg\:bui-m-10{margin:var(--bui-space-10)}.lg\:bui-m-11{margin:var(--bui-space-11)}.lg\:bui-m-12{margin:var(--bui-space-12)}.lg\:bui-m-13{margin:var(--bui-space-13)}.lg\:bui-m-14{margin:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-m{margin:var(--p-xl)}.xl\:bui-m-0\.5{margin:var(--bui-space-0_5)}.xl\:bui-m-1{margin:var(--bui-space-1)}.xl\:bui-m-1\.5{margin:var(--bui-space-1_5)}.xl\:bui-m-2{margin:var(--bui-space-2)}.xl\:bui-m-3{margin:var(--bui-space-3)}.xl\:bui-m-4{margin:var(--bui-space-4)}.xl\:bui-m-5{margin:var(--bui-space-5)}.xl\:bui-m-6{margin:var(--bui-space-6)}.xl\:bui-m-7{margin:var(--bui-space-7)}.xl\:bui-m-8{margin:var(--bui-space-8)}.xl\:bui-m-9{margin:var(--bui-space-9)}.xl\:bui-m-10{margin:var(--bui-space-10)}.xl\:bui-m-11{margin:var(--bui-space-11)}.xl\:bui-m-12{margin:var(--bui-space-12)}.xl\:bui-m-13{margin:var(--bui-space-13)}.xl\:bui-m-14{margin:var(--bui-space-14)}}.bui-ml{margin-left:var(--ml)}.bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.bui-ml-1{margin-left:var(--bui-space-1)}.bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.bui-ml-2{margin-left:var(--bui-space-2)}.bui-ml-3{margin-left:var(--bui-space-3)}.bui-ml-4{margin-left:var(--bui-space-4)}.bui-ml-5{margin-left:var(--bui-space-5)}.bui-ml-6{margin-left:var(--bui-space-6)}.bui-ml-7{margin-left:var(--bui-space-7)}.bui-ml-8{margin-left:var(--bui-space-8)}.bui-ml-9{margin-left:var(--bui-space-9)}.bui-ml-10{margin-left:var(--bui-space-10)}.bui-ml-11{margin-left:var(--bui-space-11)}.bui-ml-12{margin-left:var(--bui-space-12)}.bui-ml-13{margin-left:var(--bui-space-13)}.bui-ml-14{margin-left:var(--bui-space-14)}@media (width>=640px){.xs\:bui-ml{margin-left:var(--ml-xs)}.xs\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.xs\:bui-ml-1{margin-left:var(--bui-space-1)}.xs\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.xs\:bui-ml-2{margin-left:var(--bui-space-2)}.xs\:bui-ml-3{margin-left:var(--bui-space-3)}.xs\:bui-ml-4{margin-left:var(--bui-space-4)}.xs\:bui-ml-5{margin-left:var(--bui-space-5)}.xs\:bui-ml-6{margin-left:var(--bui-space-6)}.xs\:bui-ml-7{margin-left:var(--bui-space-7)}.xs\:bui-ml-8{margin-left:var(--bui-space-8)}.xs\:bui-ml-9{margin-left:var(--bui-space-9)}.xs\:bui-ml-10{margin-left:var(--bui-space-10)}.xs\:bui-ml-11{margin-left:var(--bui-space-11)}.xs\:bui-ml-12{margin-left:var(--bui-space-12)}.xs\:bui-ml-13{margin-left:var(--bui-space-13)}.xs\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-ml{margin-left:var(--ml-sm)}.sm\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.sm\:bui-ml-1{margin-left:var(--bui-space-1)}.sm\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.sm\:bui-ml-2{margin-left:var(--bui-space-2)}.sm\:bui-ml-3{margin-left:var(--bui-space-3)}.sm\:bui-ml-4{margin-left:var(--bui-space-4)}.sm\:bui-ml-5{margin-left:var(--bui-space-5)}.sm\:bui-ml-6{margin-left:var(--bui-space-6)}.sm\:bui-ml-7{margin-left:var(--bui-space-7)}.sm\:bui-ml-8{margin-left:var(--bui-space-8)}.sm\:bui-ml-9{margin-left:var(--bui-space-9)}.sm\:bui-ml-10{margin-left:var(--bui-space-10)}.sm\:bui-ml-11{margin-left:var(--bui-space-11)}.sm\:bui-ml-12{margin-left:var(--bui-space-12)}.sm\:bui-ml-13{margin-left:var(--bui-space-13)}.sm\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-ml{margin-left:var(--ml-md)}.md\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.md\:bui-ml-1{margin-left:var(--bui-space-1)}.md\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.md\:bui-ml-2{margin-left:var(--bui-space-2)}.md\:bui-ml-3{margin-left:var(--bui-space-3)}.md\:bui-ml-4{margin-left:var(--bui-space-4)}.md\:bui-ml-5{margin-left:var(--bui-space-5)}.md\:bui-ml-6{margin-left:var(--bui-space-6)}.md\:bui-ml-7{margin-left:var(--bui-space-7)}.md\:bui-ml-8{margin-left:var(--bui-space-8)}.md\:bui-ml-9{margin-left:var(--bui-space-9)}.md\:bui-ml-10{margin-left:var(--bui-space-10)}.md\:bui-ml-11{margin-left:var(--bui-space-11)}.md\:bui-ml-12{margin-left:var(--bui-space-12)}.md\:bui-ml-13{margin-left:var(--bui-space-13)}.md\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-ml{margin-left:var(--ml-lg)}.lg\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.lg\:bui-ml-1{margin-left:var(--bui-space-1)}.lg\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.lg\:bui-ml-2{margin-left:var(--bui-space-2)}.lg\:bui-ml-3{margin-left:var(--bui-space-3)}.lg\:bui-ml-4{margin-left:var(--bui-space-4)}.lg\:bui-ml-5{margin-left:var(--bui-space-5)}.lg\:bui-ml-6{margin-left:var(--bui-space-6)}.lg\:bui-ml-7{margin-left:var(--bui-space-7)}.lg\:bui-ml-8{margin-left:var(--bui-space-8)}.lg\:bui-ml-9{margin-left:var(--bui-space-9)}.lg\:bui-ml-10{margin-left:var(--bui-space-10)}.lg\:bui-ml-11{margin-left:var(--bui-space-11)}.lg\:bui-ml-12{margin-left:var(--bui-space-12)}.lg\:bui-ml-13{margin-left:var(--bui-space-13)}.lg\:bui-ml-14{margin-left:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-ml{margin-left:var(--ml-xl)}.xl\:bui-ml-0\.5{margin-left:var(--bui-space-0_5)}.xl\:bui-ml-1{margin-left:var(--bui-space-1)}.xl\:bui-ml-1\.5{margin-left:var(--bui-space-1_5)}.xl\:bui-ml-2{margin-left:var(--bui-space-2)}.xl\:bui-ml-3{margin-left:var(--bui-space-3)}.xl\:bui-ml-4{margin-left:var(--bui-space-4)}.xl\:bui-ml-5{margin-left:var(--bui-space-5)}.xl\:bui-ml-6{margin-left:var(--bui-space-6)}.xl\:bui-ml-7{margin-left:var(--bui-space-7)}.xl\:bui-ml-8{margin-left:var(--bui-space-8)}.xl\:bui-ml-9{margin-left:var(--bui-space-9)}.xl\:bui-ml-10{margin-left:var(--bui-space-10)}.xl\:bui-ml-11{margin-left:var(--bui-space-11)}.xl\:bui-ml-12{margin-left:var(--bui-space-12)}.xl\:bui-ml-13{margin-left:var(--bui-space-13)}.xl\:bui-ml-14{margin-left:var(--bui-space-14)}}.bui-mr{margin-right:var(--mr)}.bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.bui-mr-1{margin-right:var(--bui-space-1)}.bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.bui-mr-2{margin-right:var(--bui-space-2)}.bui-mr-3{margin-right:var(--bui-space-3)}.bui-mr-4{margin-right:var(--bui-space-4)}.bui-mr-5{margin-right:var(--bui-space-5)}.bui-mr-6{margin-right:var(--bui-space-6)}.bui-mr-7{margin-right:var(--bui-space-7)}.bui-mr-8{margin-right:var(--bui-space-8)}.bui-mr-9{margin-right:var(--bui-space-9)}.bui-mr-10{margin-right:var(--bui-space-10)}.bui-mr-11{margin-right:var(--bui-space-11)}.bui-mr-12{margin-right:var(--bui-space-12)}.bui-mr-13{margin-right:var(--bui-space-13)}.bui-mr-14{margin-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mr{margin-right:var(--mr-xs)}.xs\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.xs\:bui-mr-1{margin-right:var(--bui-space-1)}.xs\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.xs\:bui-mr-2{margin-right:var(--bui-space-2)}.xs\:bui-mr-3{margin-right:var(--bui-space-3)}.xs\:bui-mr-4{margin-right:var(--bui-space-4)}.xs\:bui-mr-5{margin-right:var(--bui-space-5)}.xs\:bui-mr-6{margin-right:var(--bui-space-6)}.xs\:bui-mr-7{margin-right:var(--bui-space-7)}.xs\:bui-mr-8{margin-right:var(--bui-space-8)}.xs\:bui-mr-9{margin-right:var(--bui-space-9)}.xs\:bui-mr-10{margin-right:var(--bui-space-10)}.xs\:bui-mr-11{margin-right:var(--bui-space-11)}.xs\:bui-mr-12{margin-right:var(--bui-space-12)}.xs\:bui-mr-13{margin-right:var(--bui-space-13)}.xs\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mr{margin-right:var(--mr-sm)}.sm\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.sm\:bui-mr-1{margin-right:var(--bui-space-1)}.sm\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.sm\:bui-mr-2{margin-right:var(--bui-space-2)}.sm\:bui-mr-3{margin-right:var(--bui-space-3)}.sm\:bui-mr-4{margin-right:var(--bui-space-4)}.sm\:bui-mr-5{margin-right:var(--bui-space-5)}.sm\:bui-mr-6{margin-right:var(--bui-space-6)}.sm\:bui-mr-7{margin-right:var(--bui-space-7)}.sm\:bui-mr-8{margin-right:var(--bui-space-8)}.sm\:bui-mr-9{margin-right:var(--bui-space-9)}.sm\:bui-mr-10{margin-right:var(--bui-space-10)}.sm\:bui-mr-11{margin-right:var(--bui-space-11)}.sm\:bui-mr-12{margin-right:var(--bui-space-12)}.sm\:bui-mr-13{margin-right:var(--bui-space-13)}.sm\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mr{margin-right:var(--mr-md)}.md\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.md\:bui-mr-1{margin-right:var(--bui-space-1)}.md\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.md\:bui-mr-2{margin-right:var(--bui-space-2)}.md\:bui-mr-3{margin-right:var(--bui-space-3)}.md\:bui-mr-4{margin-right:var(--bui-space-4)}.md\:bui-mr-5{margin-right:var(--bui-space-5)}.md\:bui-mr-6{margin-right:var(--bui-space-6)}.md\:bui-mr-7{margin-right:var(--bui-space-7)}.md\:bui-mr-8{margin-right:var(--bui-space-8)}.md\:bui-mr-9{margin-right:var(--bui-space-9)}.md\:bui-mr-10{margin-right:var(--bui-space-10)}.md\:bui-mr-11{margin-right:var(--bui-space-11)}.md\:bui-mr-12{margin-right:var(--bui-space-12)}.md\:bui-mr-13{margin-right:var(--bui-space-13)}.md\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mr{margin-right:var(--mr-lg)}.lg\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.lg\:bui-mr-1{margin-right:var(--bui-space-1)}.lg\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.lg\:bui-mr-2{margin-right:var(--bui-space-2)}.lg\:bui-mr-3{margin-right:var(--bui-space-3)}.lg\:bui-mr-4{margin-right:var(--bui-space-4)}.lg\:bui-mr-5{margin-right:var(--bui-space-5)}.lg\:bui-mr-6{margin-right:var(--bui-space-6)}.lg\:bui-mr-7{margin-right:var(--bui-space-7)}.lg\:bui-mr-8{margin-right:var(--bui-space-8)}.lg\:bui-mr-9{margin-right:var(--bui-space-9)}.lg\:bui-mr-10{margin-right:var(--bui-space-10)}.lg\:bui-mr-11{margin-right:var(--bui-space-11)}.lg\:bui-mr-12{margin-right:var(--bui-space-12)}.lg\:bui-mr-13{margin-right:var(--bui-space-13)}.lg\:bui-mr-14{margin-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mr{margin-right:var(--mr-xl)}.xl\:bui-mr-0\.5{margin-right:var(--bui-space-0_5)}.xl\:bui-mr-1{margin-right:var(--bui-space-1)}.xl\:bui-mr-1\.5{margin-right:var(--bui-space-1_5)}.xl\:bui-mr-2{margin-right:var(--bui-space-2)}.xl\:bui-mr-3{margin-right:var(--bui-space-3)}.xl\:bui-mr-4{margin-right:var(--bui-space-4)}.xl\:bui-mr-5{margin-right:var(--bui-space-5)}.xl\:bui-mr-6{margin-right:var(--bui-space-6)}.xl\:bui-mr-7{margin-right:var(--bui-space-7)}.xl\:bui-mr-8{margin-right:var(--bui-space-8)}.xl\:bui-mr-9{margin-right:var(--bui-space-9)}.xl\:bui-mr-10{margin-right:var(--bui-space-10)}.xl\:bui-mr-11{margin-right:var(--bui-space-11)}.xl\:bui-mr-12{margin-right:var(--bui-space-12)}.xl\:bui-mr-13{margin-right:var(--bui-space-13)}.xl\:bui-mr-14{margin-right:var(--bui-space-14)}}.bui-mt{margin-top:var(--mt)}.bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.bui-mt-1{margin-top:var(--bui-space-1)}.bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.bui-mt-2{margin-top:var(--bui-space-2)}.bui-mt-3{margin-top:var(--bui-space-3)}.bui-mt-4{margin-top:var(--bui-space-4)}.bui-mt-5{margin-top:var(--bui-space-5)}.bui-mt-6{margin-top:var(--bui-space-6)}.bui-mt-7{margin-top:var(--bui-space-7)}.bui-mt-8{margin-top:var(--bui-space-8)}.bui-mt-9{margin-top:var(--bui-space-9)}.bui-mt-10{margin-top:var(--bui-space-10)}.bui-mt-11{margin-top:var(--bui-space-11)}.bui-mt-12{margin-top:var(--bui-space-12)}.bui-mt-13{margin-top:var(--bui-space-13)}.bui-mt-14{margin-top:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mt{margin-top:var(--mt-xs)}.xs\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.xs\:bui-mt-1{margin-top:var(--bui-space-1)}.xs\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.xs\:bui-mt-2{margin-top:var(--bui-space-2)}.xs\:bui-mt-3{margin-top:var(--bui-space-3)}.xs\:bui-mt-4{margin-top:var(--bui-space-4)}.xs\:bui-mt-5{margin-top:var(--bui-space-5)}.xs\:bui-mt-6{margin-top:var(--bui-space-6)}.xs\:bui-mt-7{margin-top:var(--bui-space-7)}.xs\:bui-mt-8{margin-top:var(--bui-space-8)}.xs\:bui-mt-9{margin-top:var(--bui-space-9)}.xs\:bui-mt-10{margin-top:var(--bui-space-10)}.xs\:bui-mt-11{margin-top:var(--bui-space-11)}.xs\:bui-mt-12{margin-top:var(--bui-space-12)}.xs\:bui-mt-13{margin-top:var(--bui-space-13)}.xs\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mt{margin-top:var(--mt-sm)}.sm\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.sm\:bui-mt-1{margin-top:var(--bui-space-1)}.sm\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.sm\:bui-mt-2{margin-top:var(--bui-space-2)}.sm\:bui-mt-3{margin-top:var(--bui-space-3)}.sm\:bui-mt-4{margin-top:var(--bui-space-4)}.sm\:bui-mt-5{margin-top:var(--bui-space-5)}.sm\:bui-mt-6{margin-top:var(--bui-space-6)}.sm\:bui-mt-7{margin-top:var(--bui-space-7)}.sm\:bui-mt-8{margin-top:var(--bui-space-8)}.sm\:bui-mt-9{margin-top:var(--bui-space-9)}.sm\:bui-mt-10{margin-top:var(--bui-space-10)}.sm\:bui-mt-11{margin-top:var(--bui-space-11)}.sm\:bui-mt-12{margin-top:var(--bui-space-12)}.sm\:bui-mt-13{margin-top:var(--bui-space-13)}.sm\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mt{margin-top:var(--mt-md)}.md\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.md\:bui-mt-1{margin-top:var(--bui-space-1)}.md\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.md\:bui-mt-2{margin-top:var(--bui-space-2)}.md\:bui-mt-3{margin-top:var(--bui-space-3)}.md\:bui-mt-4{margin-top:var(--bui-space-4)}.md\:bui-mt-5{margin-top:var(--bui-space-5)}.md\:bui-mt-6{margin-top:var(--bui-space-6)}.md\:bui-mt-7{margin-top:var(--bui-space-7)}.md\:bui-mt-8{margin-top:var(--bui-space-8)}.md\:bui-mt-9{margin-top:var(--bui-space-9)}.md\:bui-mt-10{margin-top:var(--bui-space-10)}.md\:bui-mt-11{margin-top:var(--bui-space-11)}.md\:bui-mt-12{margin-top:var(--bui-space-12)}.md\:bui-mt-13{margin-top:var(--bui-space-13)}.md\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mt{margin-top:var(--mt-lg)}.lg\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.lg\:bui-mt-1{margin-top:var(--bui-space-1)}.lg\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.lg\:bui-mt-2{margin-top:var(--bui-space-2)}.lg\:bui-mt-3{margin-top:var(--bui-space-3)}.lg\:bui-mt-4{margin-top:var(--bui-space-4)}.lg\:bui-mt-5{margin-top:var(--bui-space-5)}.lg\:bui-mt-6{margin-top:var(--bui-space-6)}.lg\:bui-mt-7{margin-top:var(--bui-space-7)}.lg\:bui-mt-8{margin-top:var(--bui-space-8)}.lg\:bui-mt-9{margin-top:var(--bui-space-9)}.lg\:bui-mt-10{margin-top:var(--bui-space-10)}.lg\:bui-mt-11{margin-top:var(--bui-space-11)}.lg\:bui-mt-12{margin-top:var(--bui-space-12)}.lg\:bui-mt-13{margin-top:var(--bui-space-13)}.lg\:bui-mt-14{margin-top:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mt{margin-top:var(--mt-xl)}.xl\:bui-mt-0\.5{margin-top:var(--bui-space-0_5)}.xl\:bui-mt-1{margin-top:var(--bui-space-1)}.xl\:bui-mt-1\.5{margin-top:var(--bui-space-1_5)}.xl\:bui-mt-2{margin-top:var(--bui-space-2)}.xl\:bui-mt-3{margin-top:var(--bui-space-3)}.xl\:bui-mt-4{margin-top:var(--bui-space-4)}.xl\:bui-mt-5{margin-top:var(--bui-space-5)}.xl\:bui-mt-6{margin-top:var(--bui-space-6)}.xl\:bui-mt-7{margin-top:var(--bui-space-7)}.xl\:bui-mt-8{margin-top:var(--bui-space-8)}.xl\:bui-mt-9{margin-top:var(--bui-space-9)}.xl\:bui-mt-10{margin-top:var(--bui-space-10)}.xl\:bui-mt-11{margin-top:var(--bui-space-11)}.xl\:bui-mt-12{margin-top:var(--bui-space-12)}.xl\:bui-mt-13{margin-top:var(--bui-space-13)}.xl\:bui-mt-14{margin-top:var(--bui-space-14)}}.bui-mb{margin-bottom:var(--mb)}.bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.bui-mb-1{margin-bottom:var(--bui-space-1)}.bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.bui-mb-2{margin-bottom:var(--bui-space-2)}.bui-mb-3{margin-bottom:var(--bui-space-3)}.bui-mb-4{margin-bottom:var(--bui-space-4)}.bui-mb-5{margin-bottom:var(--bui-space-5)}.bui-mb-6{margin-bottom:var(--bui-space-6)}.bui-mb-7{margin-bottom:var(--bui-space-7)}.bui-mb-8{margin-bottom:var(--bui-space-8)}.bui-mb-9{margin-bottom:var(--bui-space-9)}.bui-mb-10{margin-bottom:var(--bui-space-10)}.bui-mb-11{margin-bottom:var(--bui-space-11)}.bui-mb-12{margin-bottom:var(--bui-space-12)}.bui-mb-13{margin-bottom:var(--bui-space-13)}.bui-mb-14{margin-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mb{margin-bottom:var(--mb-xs)}.xs\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.xs\:bui-mb-1{margin-bottom:var(--bui-space-1)}.xs\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.xs\:bui-mb-2{margin-bottom:var(--bui-space-2)}.xs\:bui-mb-3{margin-bottom:var(--bui-space-3)}.xs\:bui-mb-4{margin-bottom:var(--bui-space-4)}.xs\:bui-mb-5{margin-bottom:var(--bui-space-5)}.xs\:bui-mb-6{margin-bottom:var(--bui-space-6)}.xs\:bui-mb-7{margin-bottom:var(--bui-space-7)}.xs\:bui-mb-8{margin-bottom:var(--bui-space-8)}.xs\:bui-mb-9{margin-bottom:var(--bui-space-9)}.xs\:bui-mb-10{margin-bottom:var(--bui-space-10)}.xs\:bui-mb-11{margin-bottom:var(--bui-space-11)}.xs\:bui-mb-12{margin-bottom:var(--bui-space-12)}.xs\:bui-mb-13{margin-bottom:var(--bui-space-13)}.xs\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mb{margin-bottom:var(--mb-sm)}.sm\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.sm\:bui-mb-1{margin-bottom:var(--bui-space-1)}.sm\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.sm\:bui-mb-2{margin-bottom:var(--bui-space-2)}.sm\:bui-mb-3{margin-bottom:var(--bui-space-3)}.sm\:bui-mb-4{margin-bottom:var(--bui-space-4)}.sm\:bui-mb-5{margin-bottom:var(--bui-space-5)}.sm\:bui-mb-6{margin-bottom:var(--bui-space-6)}.sm\:bui-mb-7{margin-bottom:var(--bui-space-7)}.sm\:bui-mb-8{margin-bottom:var(--bui-space-8)}.sm\:bui-mb-9{margin-bottom:var(--bui-space-9)}.sm\:bui-mb-10{margin-bottom:var(--bui-space-10)}.sm\:bui-mb-11{margin-bottom:var(--bui-space-11)}.sm\:bui-mb-12{margin-bottom:var(--bui-space-12)}.sm\:bui-mb-13{margin-bottom:var(--bui-space-13)}.sm\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mb{margin-bottom:var(--mb-md)}.md\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.md\:bui-mb-1{margin-bottom:var(--bui-space-1)}.md\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.md\:bui-mb-2{margin-bottom:var(--bui-space-2)}.md\:bui-mb-3{margin-bottom:var(--bui-space-3)}.md\:bui-mb-4{margin-bottom:var(--bui-space-4)}.md\:bui-mb-5{margin-bottom:var(--bui-space-5)}.md\:bui-mb-6{margin-bottom:var(--bui-space-6)}.md\:bui-mb-7{margin-bottom:var(--bui-space-7)}.md\:bui-mb-8{margin-bottom:var(--bui-space-8)}.md\:bui-mb-9{margin-bottom:var(--bui-space-9)}.md\:bui-mb-10{margin-bottom:var(--bui-space-10)}.md\:bui-mb-11{margin-bottom:var(--bui-space-11)}.md\:bui-mb-12{margin-bottom:var(--bui-space-12)}.md\:bui-mb-13{margin-bottom:var(--bui-space-13)}.md\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mb{margin-bottom:var(--mb-lg)}.lg\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.lg\:bui-mb-1{margin-bottom:var(--bui-space-1)}.lg\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.lg\:bui-mb-2{margin-bottom:var(--bui-space-2)}.lg\:bui-mb-3{margin-bottom:var(--bui-space-3)}.lg\:bui-mb-4{margin-bottom:var(--bui-space-4)}.lg\:bui-mb-5{margin-bottom:var(--bui-space-5)}.lg\:bui-mb-6{margin-bottom:var(--bui-space-6)}.lg\:bui-mb-7{margin-bottom:var(--bui-space-7)}.lg\:bui-mb-8{margin-bottom:var(--bui-space-8)}.lg\:bui-mb-9{margin-bottom:var(--bui-space-9)}.lg\:bui-mb-10{margin-bottom:var(--bui-space-10)}.lg\:bui-mb-11{margin-bottom:var(--bui-space-11)}.lg\:bui-mb-12{margin-bottom:var(--bui-space-12)}.lg\:bui-mb-13{margin-bottom:var(--bui-space-13)}.lg\:bui-mb-14{margin-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mb{margin-bottom:var(--mb-xl)}.xl\:bui-mb-0\.5{margin-bottom:var(--bui-space-0_5)}.xl\:bui-mb-1{margin-bottom:var(--bui-space-1)}.xl\:bui-mb-1\.5{margin-bottom:var(--bui-space-1_5)}.xl\:bui-mb-2{margin-bottom:var(--bui-space-2)}.xl\:bui-mb-3{margin-bottom:var(--bui-space-3)}.xl\:bui-mb-4{margin-bottom:var(--bui-space-4)}.xl\:bui-mb-5{margin-bottom:var(--bui-space-5)}.xl\:bui-mb-6{margin-bottom:var(--bui-space-6)}.xl\:bui-mb-7{margin-bottom:var(--bui-space-7)}.xl\:bui-mb-8{margin-bottom:var(--bui-space-8)}.xl\:bui-mb-9{margin-bottom:var(--bui-space-9)}.xl\:bui-mb-10{margin-bottom:var(--bui-space-10)}.xl\:bui-mb-11{margin-bottom:var(--bui-space-11)}.xl\:bui-mb-12{margin-bottom:var(--bui-space-12)}.xl\:bui-mb-13{margin-bottom:var(--bui-space-13)}.xl\:bui-mb-14{margin-bottom:var(--bui-space-14)}}.bui-my{margin-top:var(--my);margin-bottom:var(--my)}.bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}@media (width>=640px){.xs\:bui-my{margin-top:var(--my-xs);margin-bottom:var(--my-xs)}.xs\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.xs\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.xs\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.xs\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.xs\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.xs\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.xs\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.xs\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.xs\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.xs\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.xs\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.xs\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.xs\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.xs\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.xs\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.xs\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-my{margin-top:var(--my-sm);margin-bottom:var(--my-sm)}.sm\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.sm\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.sm\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.sm\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.sm\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.sm\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.sm\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.sm\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.sm\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.sm\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.sm\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.sm\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.sm\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.sm\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.sm\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.sm\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-my{margin-top:var(--my-md);margin-bottom:var(--my-md)}.md\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.md\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.md\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.md\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.md\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.md\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.md\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.md\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.md\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.md\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.md\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.md\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.md\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.md\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.md\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.md\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-my{margin-top:var(--my-lg);margin-bottom:var(--my-lg)}.lg\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.lg\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.lg\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.lg\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.lg\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.lg\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.lg\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.lg\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.lg\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.lg\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.lg\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.lg\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.lg\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.lg\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.lg\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.lg\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-my{margin-top:var(--my-xl);margin-bottom:var(--my-xl)}.xl\:bui-my-0\.5{margin-top:var(--bui-space-0_5);margin-bottom:var(--bui-space-0_5)}.xl\:bui-my-1{margin-top:var(--bui-space-1);margin-bottom:var(--bui-space-1)}.xl\:bui-my-1\.5{margin-top:var(--bui-space-1_5);margin-bottom:var(--bui-space-1_5)}.xl\:bui-my-2{margin-top:var(--bui-space-2);margin-bottom:var(--bui-space-2)}.xl\:bui-my-3{margin-top:var(--bui-space-3);margin-bottom:var(--bui-space-3)}.xl\:bui-my-4{margin-top:var(--bui-space-4);margin-bottom:var(--bui-space-4)}.xl\:bui-my-5{margin-top:var(--bui-space-5);margin-bottom:var(--bui-space-5)}.xl\:bui-my-6{margin-top:var(--bui-space-6);margin-bottom:var(--bui-space-6)}.xl\:bui-my-7{margin-top:var(--bui-space-7);margin-bottom:var(--bui-space-7)}.xl\:bui-my-8{margin-top:var(--bui-space-8);margin-bottom:var(--bui-space-8)}.xl\:bui-my-9{margin-top:var(--bui-space-9);margin-bottom:var(--bui-space-9)}.xl\:bui-my-10{margin-top:var(--bui-space-10);margin-bottom:var(--bui-space-10)}.xl\:bui-my-11{margin-top:var(--bui-space-11);margin-bottom:var(--bui-space-11)}.xl\:bui-my-12{margin-top:var(--bui-space-12);margin-bottom:var(--bui-space-12)}.xl\:bui-my-13{margin-top:var(--bui-space-13);margin-bottom:var(--bui-space-13)}.xl\:bui-my-14{margin-top:var(--bui-space-14);margin-bottom:var(--bui-space-14)}}.bui-mx{margin-left:var(--mx);margin-right:var(--mx)}.bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}@media (width>=640px){.xs\:bui-mx{margin-left:var(--mx-xs);margin-right:var(--mx-xs)}.xs\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.xs\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.xs\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.xs\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.xs\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.xs\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.xs\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.xs\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.xs\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.xs\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.xs\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.xs\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.xs\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.xs\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.xs\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.xs\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-mx{margin-left:var(--mx-sm);margin-right:var(--mx-sm)}.sm\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.sm\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.sm\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.sm\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.sm\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.sm\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.sm\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.sm\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.sm\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.sm\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.sm\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.sm\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.sm\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.sm\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.sm\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.sm\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-mx{margin-left:var(--mx-md);margin-right:var(--mx-md)}.md\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.md\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.md\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.md\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.md\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.md\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.md\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.md\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.md\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.md\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.md\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.md\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.md\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.md\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.md\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.md\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-mx{margin-left:var(--mx-lg);margin-right:var(--mx-lg)}.lg\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.lg\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.lg\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.lg\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.lg\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.lg\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.lg\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.lg\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.lg\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.lg\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.lg\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.lg\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.lg\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.lg\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.lg\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.lg\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-mx{margin-left:var(--mx-xl);margin-right:var(--mx-xl)}.xl\:bui-mx-0\.5{margin-left:var(--bui-space-0_5);margin-right:var(--bui-space-0_5)}.xl\:bui-mx-1{margin-left:var(--bui-space-1);margin-right:var(--bui-space-1)}.xl\:bui-mx-1\.5{margin-left:var(--bui-space-1_5);margin-right:var(--bui-space-1_5)}.xl\:bui-mx-2{margin-left:var(--bui-space-2);margin-right:var(--bui-space-2)}.xl\:bui-mx-3{margin-left:var(--bui-space-3);margin-right:var(--bui-space-3)}.xl\:bui-mx-4{margin-left:var(--bui-space-4);margin-right:var(--bui-space-4)}.xl\:bui-mx-5{margin-left:var(--bui-space-5);margin-right:var(--bui-space-5)}.xl\:bui-mx-6{margin-left:var(--bui-space-6);margin-right:var(--bui-space-6)}.xl\:bui-mx-7{margin-left:var(--bui-space-7);margin-right:var(--bui-space-7)}.xl\:bui-mx-8{margin-left:var(--bui-space-8);margin-right:var(--bui-space-8)}.xl\:bui-mx-9{margin-left:var(--bui-space-9);margin-right:var(--bui-space-9)}.xl\:bui-mx-10{margin-left:var(--bui-space-10);margin-right:var(--bui-space-10)}.xl\:bui-mx-11{margin-left:var(--bui-space-11);margin-right:var(--bui-space-11)}.xl\:bui-mx-12{margin-left:var(--bui-space-12);margin-right:var(--bui-space-12)}.xl\:bui-mx-13{margin-left:var(--bui-space-13);margin-right:var(--bui-space-13)}.xl\:bui-mx-14{margin-left:var(--bui-space-14);margin-right:var(--bui-space-14)}}.bui-display-none{display:none}.bui-display-inline{display:inline}.bui-display-inline-block{display:inline-block}.bui-display-block{display:block}@media (width>=640px){.xs\:bui-display-none{display:none}.xs\:bui-display-inline{display:inline}.xs\:bui-display-inline-block{display:inline-block}.xs\:bui-display-block{display:block}}@media (width>=768px){.sm\:bui-display-none{display:none}.sm\:bui-display-inline{display:inline}.sm\:bui-display-inline-block{display:inline-block}.sm\:bui-display-block{display:block}}@media (width>=1024px){.md\:bui-display-none{display:none}.md\:bui-display-inline{display:inline}.md\:bui-display-inline-block{display:inline-block}.md\:bui-display-block{display:block}}@media (width>=1280px){.lg\:bui-display-none{display:none}.lg\:bui-display-inline{display:inline}.lg\:bui-display-inline-block{display:inline-block}.lg\:bui-display-block{display:block}}@media (width>=1536px){.xl\:bui-display-none{display:none}.xl\:bui-display-inline{display:inline}.xl\:bui-display-inline-block{display:inline-block}.xl\:bui-display-block{display:block}}.bui-w{width:var(--width)}.bui-min-w{min-width:var(--min-width)}.bui-max-w{max-width:var(--max-width)}@media (width>=640px){.xs\:bui-w{width:var(--width)}.xs\:bui-min-w{min-width:var(--min-width)}.xs\:bui-max-w{max-width:var(--max-width)}}@media (width>=768px){.sm\:bui-w{width:var(--width)}.sm\:bui-min-w{min-width:var(--min-width)}.sm\:bui-max-w{max-width:var(--max-width)}}@media (width>=1024px){.md\:bui-w{width:var(--width)}.md\:bui-min-w{min-width:var(--min-width)}.md\:bui-max-w{max-width:var(--max-width)}}@media (width>=1280px){.lg\:bui-w{width:var(--width)}.lg\:bui-min-w{min-width:var(--min-width)}.lg\:bui-max-w{max-width:var(--max-width)}}@media (width>=1536px){.xl\:bui-w{width:var(--width)}.xl\:bui-min-w{min-width:var(--min-width)}.xl\:bui-max-w{max-width:var(--max-width)}}.bui-h{height:var(--height)}.bui-min-h{min-height:var(--min-height)}.bui-max-h{max-height:var(--max-height)}@media (width>=640px){.xs\:bui-h{height:var(--height)}.xs\:bui-min-h{min-height:var(--min-height)}.xs\:bui-max-h{max-height:var(--max-height)}}@media (width>=768px){.sm\:bui-h{height:var(--height)}.sm\:bui-min-h{min-height:var(--min-height)}.sm\:bui-max-h{max-height:var(--max-height)}}@media (width>=1024px){.md\:bui-h{height:var(--height)}.md\:bui-min-h{min-height:var(--min-height)}.md\:bui-max-h{max-height:var(--max-height)}}@media (width>=1280px){.lg\:bui-h{height:var(--height)}.lg\:bui-min-h{min-height:var(--min-height)}.lg\:bui-max-h{max-height:var(--max-height)}}@media (width>=1536px){.xl\:bui-h{height:var(--height)}.xl\:bui-min-h{min-height:var(--min-height)}.xl\:bui-max-h{max-height:var(--max-height)}}.bui-position-absolute{position:absolute}.bui-position-fixed{position:fixed}.bui-position-sticky{position:sticky}.bui-position-relative{position:relative}.bui-position-static{position:static}@media (width>=640px){.xs\:bui-position-absolute{position:absolute}.xs\:bui-position-fixed{position:fixed}.xs\:bui-position-sticky{position:sticky}.xs\:bui-position-relative{position:relative}.xs\:bui-position-static{position:static}}@media (width>=768px){.sm\:bui-position-absolute{position:absolute}.sm\:bui-position-fixed{position:fixed}.sm\:bui-position-sticky{position:sticky}.sm\:bui-position-relative{position:relative}.sm\:bui-position-static{position:static}}@media (width>=1024px){.md\:bui-position-absolute{position:absolute}.md\:bui-position-fixed{position:fixed}.md\:bui-position-sticky{position:sticky}.md\:bui-position-relative{position:relative}.md\:bui-position-static{position:static}}@media (width>=1280px){.lg\:bui-position-absolute{position:absolute}.lg\:bui-position-fixed{position:fixed}.lg\:bui-position-sticky{position:sticky}.lg\:bui-position-relative{position:relative}.lg\:bui-position-static{position:static}}@media (width>=1536px){.xl\:bui-position-absolute{position:absolute}.xl\:bui-position-fixed{position:fixed}.xl\:bui-position-sticky{position:sticky}.xl\:bui-position-relative{position:relative}.xl\:bui-position-static{position:static}}.bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.bui-col-span-1{grid-column:span 1/span 1}.bui-col-span-2{grid-column:span 2/span 2}.bui-col-span-3{grid-column:span 3/span 3}.bui-col-span-4{grid-column:span 4/span 4}.bui-col-span-5{grid-column:span 5/span 5}.bui-col-span-6{grid-column:span 6/span 6}.bui-col-span-7{grid-column:span 7/span 7}.bui-col-span-8{grid-column:span 8/span 8}.bui-col-span-9{grid-column:span 9/span 9}.bui-col-span-10{grid-column:span 10/span 10}.bui-col-span-11{grid-column:span 11/span 11}.bui-col-span-12{grid-column:span 12/span 12}.bui-col-span-auto{grid-column:span auto/span auto}.bui-col-start-1{grid-column-start:1}.bui-col-start-2{grid-column-start:2}.bui-col-start-3{grid-column-start:3}.bui-col-start-4{grid-column-start:4}.bui-col-start-5{grid-column-start:5}.bui-col-start-6{grid-column-start:6}.bui-col-start-7{grid-column-start:7}.bui-col-start-8{grid-column-start:8}.bui-col-start-9{grid-column-start:9}.bui-col-start-10{grid-column-start:10}.bui-col-start-11{grid-column-start:11}.bui-col-start-12{grid-column-start:12}.bui-col-start-13{grid-column-start:13}.bui-col-start-auto{grid-column-start:auto}.bui-col-end-1{grid-column-end:1}.bui-col-end-2{grid-column-end:2}.bui-col-end-3{grid-column-end:3}.bui-col-end-4{grid-column-end:4}.bui-col-end-5{grid-column-end:5}.bui-col-end-6{grid-column-end:6}.bui-col-end-7{grid-column-end:7}.bui-col-end-8{grid-column-end:8}.bui-col-end-9{grid-column-end:9}.bui-col-end-10{grid-column-end:10}.bui-col-end-11{grid-column-end:11}.bui-col-end-12{grid-column-end:12}.bui-col-end-13{grid-column-end:13}.bui-col-end-auto{grid-column-end:auto}.bui-row-span-1{grid-row:span 1/span 1}.bui-row-span-2{grid-row:span 2/span 2}.bui-row-span-3{grid-row:span 3/span 3}.bui-row-span-4{grid-row:span 4/span 4}.bui-row-span-5{grid-row:span 5/span 5}.bui-row-span-6{grid-row:span 6/span 6}.bui-row-span-7{grid-row:span 7/span 7}.bui-row-span-8{grid-row:span 8/span 8}.bui-row-span-9{grid-row:span 9/span 9}.bui-row-span-10{grid-row:span 10/span 10}.bui-row-span-11{grid-row:span 11/span 11}.bui-row-span-12{grid-row:span 12/span 12}.bui-row-span-auto{grid-row:span auto/span auto}@media (width>=640px){.xs\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xs\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xs\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xs\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xs\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xs\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xs\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xs\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xs\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xs\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xs\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xs\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xs\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xs\:bui-col-span-1{grid-column:span 1/span 1}.xs\:bui-col-span-2{grid-column:span 2/span 2}.xs\:bui-col-span-3{grid-column:span 3/span 3}.xs\:bui-col-span-4{grid-column:span 4/span 4}.xs\:bui-col-span-5{grid-column:span 5/span 5}.xs\:bui-col-span-6{grid-column:span 6/span 6}.xs\:bui-col-span-7{grid-column:span 7/span 7}.xs\:bui-col-span-8{grid-column:span 8/span 8}.xs\:bui-col-span-9{grid-column:span 9/span 9}.xs\:bui-col-span-10{grid-column:span 10/span 10}.xs\:bui-col-span-11{grid-column:span 11/span 11}.xs\:bui-col-span-12{grid-column:span 12/span 12}.xs\:bui-col-span-auto{grid-column:span auto/span auto}.xs\:bui-col-start-1{grid-column-start:1}.xs\:bui-col-start-2{grid-column-start:2}.xs\:bui-col-start-3{grid-column-start:3}.xs\:bui-col-start-4{grid-column-start:4}.xs\:bui-col-start-5{grid-column-start:5}.xs\:bui-col-start-6{grid-column-start:6}.xs\:bui-col-start-7{grid-column-start:7}.xs\:bui-col-start-8{grid-column-start:8}.xs\:bui-col-start-9{grid-column-start:9}.xs\:bui-col-start-10{grid-column-start:10}.xs\:bui-col-start-11{grid-column-start:11}.xs\:bui-col-start-12{grid-column-start:12}.xs\:bui-col-start-13{grid-column-start:13}.xs\:bui-col-start-auto{grid-column-start:auto}.xs\:bui-col-end-1{grid-column-end:1}.xs\:bui-col-end-2{grid-column-end:2}.xs\:bui-col-end-3{grid-column-end:3}.xs\:bui-col-end-4{grid-column-end:4}.xs\:bui-col-end-5{grid-column-end:5}.xs\:bui-col-end-6{grid-column-end:6}.xs\:bui-col-end-7{grid-column-end:7}.xs\:bui-col-end-8{grid-column-end:8}.xs\:bui-col-end-9{grid-column-end:9}.xs\:bui-col-end-10{grid-column-end:10}.xs\:bui-col-end-11{grid-column-end:11}.xs\:bui-col-end-12{grid-column-end:12}.xs\:bui-col-end-13{grid-column-end:13}.xs\:bui-col-end-auto{grid-column-end:auto}.xs\:bui-row-span-1{grid-row:span 1/span 1}.xs\:bui-row-span-2{grid-row:span 2/span 2}.xs\:bui-row-span-3{grid-row:span 3/span 3}.xs\:bui-row-span-4{grid-row:span 4/span 4}.xs\:bui-row-span-5{grid-row:span 5/span 5}.xs\:bui-row-span-6{grid-row:span 6/span 6}.xs\:bui-row-span-7{grid-row:span 7/span 7}.xs\:bui-row-span-8{grid-row:span 8/span 8}.xs\:bui-row-span-9{grid-row:span 9/span 9}.xs\:bui-row-span-10{grid-row:span 10/span 10}.xs\:bui-row-span-11{grid-row:span 11/span 11}.xs\:bui-row-span-12{grid-row:span 12/span 12}.xs\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=768px){.sm\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.sm\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.sm\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.sm\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.sm\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.sm\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.sm\:bui-col-span-1{grid-column:span 1/span 1}.sm\:bui-col-span-2{grid-column:span 2/span 2}.sm\:bui-col-span-3{grid-column:span 3/span 3}.sm\:bui-col-span-4{grid-column:span 4/span 4}.sm\:bui-col-span-5{grid-column:span 5/span 5}.sm\:bui-col-span-6{grid-column:span 6/span 6}.sm\:bui-col-span-7{grid-column:span 7/span 7}.sm\:bui-col-span-8{grid-column:span 8/span 8}.sm\:bui-col-span-9{grid-column:span 9/span 9}.sm\:bui-col-span-10{grid-column:span 10/span 10}.sm\:bui-col-span-11{grid-column:span 11/span 11}.sm\:bui-col-span-12{grid-column:span 12/span 12}.sm\:bui-col-span-auto{grid-column:span auto/span auto}.sm\:bui-col-start-1{grid-column-start:1}.sm\:bui-col-start-2{grid-column-start:2}.sm\:bui-col-start-3{grid-column-start:3}.sm\:bui-col-start-4{grid-column-start:4}.sm\:bui-col-start-5{grid-column-start:5}.sm\:bui-col-start-6{grid-column-start:6}.sm\:bui-col-start-7{grid-column-start:7}.sm\:bui-col-start-8{grid-column-start:8}.sm\:bui-col-start-9{grid-column-start:9}.sm\:bui-col-start-10{grid-column-start:10}.sm\:bui-col-start-11{grid-column-start:11}.sm\:bui-col-start-12{grid-column-start:12}.sm\:bui-col-start-13{grid-column-start:13}.sm\:bui-col-start-auto{grid-column-start:auto}.sm\:bui-col-end-1{grid-column-end:1}.sm\:bui-col-end-2{grid-column-end:2}.sm\:bui-col-end-3{grid-column-end:3}.sm\:bui-col-end-4{grid-column-end:4}.sm\:bui-col-end-5{grid-column-end:5}.sm\:bui-col-end-6{grid-column-end:6}.sm\:bui-col-end-7{grid-column-end:7}.sm\:bui-col-end-8{grid-column-end:8}.sm\:bui-col-end-9{grid-column-end:9}.sm\:bui-col-end-10{grid-column-end:10}.sm\:bui-col-end-11{grid-column-end:11}.sm\:bui-col-end-12{grid-column-end:12}.sm\:bui-col-end-13{grid-column-end:13}.sm\:bui-col-end-auto{grid-column-end:auto}.sm\:bui-row-span-1{grid-row:span 1/span 1}.sm\:bui-row-span-2{grid-row:span 2/span 2}.sm\:bui-row-span-3{grid-row:span 3/span 3}.sm\:bui-row-span-4{grid-row:span 4/span 4}.sm\:bui-row-span-5{grid-row:span 5/span 5}.sm\:bui-row-span-6{grid-row:span 6/span 6}.sm\:bui-row-span-7{grid-row:span 7/span 7}.sm\:bui-row-span-8{grid-row:span 8/span 8}.sm\:bui-row-span-9{grid-row:span 9/span 9}.sm\:bui-row-span-10{grid-row:span 10/span 10}.sm\:bui-row-span-11{grid-row:span 11/span 11}.sm\:bui-row-span-12{grid-row:span 12/span 12}.sm\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1024px){.md\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.md\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.md\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.md\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.md\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.md\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.md\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.md\:bui-col-span-1{grid-column:span 1/span 1}.md\:bui-col-span-2{grid-column:span 2/span 2}.md\:bui-col-span-3{grid-column:span 3/span 3}.md\:bui-col-span-4{grid-column:span 4/span 4}.md\:bui-col-span-5{grid-column:span 5/span 5}.md\:bui-col-span-6{grid-column:span 6/span 6}.md\:bui-col-span-7{grid-column:span 7/span 7}.md\:bui-col-span-8{grid-column:span 8/span 8}.md\:bui-col-span-9{grid-column:span 9/span 9}.md\:bui-col-span-10{grid-column:span 10/span 10}.md\:bui-col-span-11{grid-column:span 11/span 11}.md\:bui-col-span-12{grid-column:span 12/span 12}.md\:bui-col-span-auto{grid-column:span auto/span auto}.md\:bui-col-start-1{grid-column-start:1}.md\:bui-col-start-2{grid-column-start:2}.md\:bui-col-start-3{grid-column-start:3}.md\:bui-col-start-4{grid-column-start:4}.md\:bui-col-start-5{grid-column-start:5}.md\:bui-col-start-6{grid-column-start:6}.md\:bui-col-start-7{grid-column-start:7}.md\:bui-col-start-8{grid-column-start:8}.md\:bui-col-start-9{grid-column-start:9}.md\:bui-col-start-10{grid-column-start:10}.md\:bui-col-start-11{grid-column-start:11}.md\:bui-col-start-12{grid-column-start:12}.md\:bui-col-start-13{grid-column-start:13}.md\:bui-col-start-auto{grid-column-start:auto}.md\:bui-col-end-1{grid-column-end:1}.md\:bui-col-end-2{grid-column-end:2}.md\:bui-col-end-3{grid-column-end:3}.md\:bui-col-end-4{grid-column-end:4}.md\:bui-col-end-5{grid-column-end:5}.md\:bui-col-end-6{grid-column-end:6}.md\:bui-col-end-7{grid-column-end:7}.md\:bui-col-end-8{grid-column-end:8}.md\:bui-col-end-9{grid-column-end:9}.md\:bui-col-end-10{grid-column-end:10}.md\:bui-col-end-11{grid-column-end:11}.md\:bui-col-end-12{grid-column-end:12}.md\:bui-col-end-13{grid-column-end:13}.md\:bui-col-end-auto{grid-column-end:auto}.md\:bui-row-span-1{grid-row:span 1/span 1}.md\:bui-row-span-2{grid-row:span 2/span 2}.md\:bui-row-span-3{grid-row:span 3/span 3}.md\:bui-row-span-4{grid-row:span 4/span 4}.md\:bui-row-span-5{grid-row:span 5/span 5}.md\:bui-row-span-6{grid-row:span 6/span 6}.md\:bui-row-span-7{grid-row:span 7/span 7}.md\:bui-row-span-8{grid-row:span 8/span 8}.md\:bui-row-span-9{grid-row:span 9/span 9}.md\:bui-row-span-10{grid-row:span 10/span 10}.md\:bui-row-span-11{grid-row:span 11/span 11}.md\:bui-row-span-12{grid-row:span 12/span 12}.md\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1280px){.lg\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.lg\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.lg\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.lg\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.lg\:bui-col-span-1{grid-column:span 1/span 1}.lg\:bui-col-span-2{grid-column:span 2/span 2}.lg\:bui-col-span-3{grid-column:span 3/span 3}.lg\:bui-col-span-4{grid-column:span 4/span 4}.lg\:bui-col-span-5{grid-column:span 5/span 5}.lg\:bui-col-span-6{grid-column:span 6/span 6}.lg\:bui-col-span-7{grid-column:span 7/span 7}.lg\:bui-col-span-8{grid-column:span 8/span 8}.lg\:bui-col-span-9{grid-column:span 9/span 9}.lg\:bui-col-span-10{grid-column:span 10/span 10}.lg\:bui-col-span-11{grid-column:span 11/span 11}.lg\:bui-col-span-12{grid-column:span 12/span 12}.lg\:bui-col-span-auto{grid-column:span auto/span auto}.lg\:bui-col-start-1{grid-column-start:1}.lg\:bui-col-start-2{grid-column-start:2}.lg\:bui-col-start-3{grid-column-start:3}.lg\:bui-col-start-4{grid-column-start:4}.lg\:bui-col-start-5{grid-column-start:5}.lg\:bui-col-start-6{grid-column-start:6}.lg\:bui-col-start-7{grid-column-start:7}.lg\:bui-col-start-8{grid-column-start:8}.lg\:bui-col-start-9{grid-column-start:9}.lg\:bui-col-start-10{grid-column-start:10}.lg\:bui-col-start-11{grid-column-start:11}.lg\:bui-col-start-12{grid-column-start:12}.lg\:bui-col-start-13{grid-column-start:13}.lg\:bui-col-start-auto{grid-column-start:auto}.lg\:bui-col-end-1{grid-column-end:1}.lg\:bui-col-end-2{grid-column-end:2}.lg\:bui-col-end-3{grid-column-end:3}.lg\:bui-col-end-4{grid-column-end:4}.lg\:bui-col-end-5{grid-column-end:5}.lg\:bui-col-end-6{grid-column-end:6}.lg\:bui-col-end-7{grid-column-end:7}.lg\:bui-col-end-8{grid-column-end:8}.lg\:bui-col-end-9{grid-column-end:9}.lg\:bui-col-end-10{grid-column-end:10}.lg\:bui-col-end-11{grid-column-end:11}.lg\:bui-col-end-12{grid-column-end:12}.lg\:bui-col-end-13{grid-column-end:13}.lg\:bui-col-end-auto{grid-column-end:auto}.lg\:bui-row-span-1{grid-row:span 1/span 1}.lg\:bui-row-span-2{grid-row:span 2/span 2}.lg\:bui-row-span-3{grid-row:span 3/span 3}.lg\:bui-row-span-4{grid-row:span 4/span 4}.lg\:bui-row-span-5{grid-row:span 5/span 5}.lg\:bui-row-span-6{grid-row:span 6/span 6}.lg\:bui-row-span-7{grid-row:span 7/span 7}.lg\:bui-row-span-8{grid-row:span 8/span 8}.lg\:bui-row-span-9{grid-row:span 9/span 9}.lg\:bui-row-span-10{grid-row:span 10/span 10}.lg\:bui-row-span-11{grid-row:span 11/span 11}.lg\:bui-row-span-12{grid-row:span 12/span 12}.lg\:bui-row-span-auto{grid-row:span auto/span auto}}@media (width>=1536px){.xl\:bui-columns-1{grid-template-columns:repeat(1,minmax(0,1fr))}.xl\:bui-columns-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:bui-columns-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:bui-columns-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:bui-columns-5{grid-template-columns:repeat(5,minmax(0,1fr))}.xl\:bui-columns-6{grid-template-columns:repeat(6,minmax(0,1fr))}.xl\:bui-columns-7{grid-template-columns:repeat(7,minmax(0,1fr))}.xl\:bui-columns-8{grid-template-columns:repeat(8,minmax(0,1fr))}.xl\:bui-columns-9{grid-template-columns:repeat(9,minmax(0,1fr))}.xl\:bui-columns-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:bui-columns-11{grid-template-columns:repeat(11,minmax(0,1fr))}.xl\:bui-columns-12{grid-template-columns:repeat(12,minmax(0,1fr))}.xl\:bui-columns-auto{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.xl\:bui-col-span-1{grid-column:span 1/span 1}.xl\:bui-col-span-2{grid-column:span 2/span 2}.xl\:bui-col-span-3{grid-column:span 3/span 3}.xl\:bui-col-span-4{grid-column:span 4/span 4}.xl\:bui-col-span-5{grid-column:span 5/span 5}.xl\:bui-col-span-6{grid-column:span 6/span 6}.xl\:bui-col-span-7{grid-column:span 7/span 7}.xl\:bui-col-span-8{grid-column:span 8/span 8}.xl\:bui-col-span-9{grid-column:span 9/span 9}.xl\:bui-col-span-10{grid-column:span 10/span 10}.xl\:bui-col-span-11{grid-column:span 11/span 11}.xl\:bui-col-span-12{grid-column:span 12/span 12}.xl\:bui-col-span-auto{grid-column:span auto/span auto}.xl\:bui-col-start-1{grid-column-start:1}.xl\:bui-col-start-2{grid-column-start:2}.xl\:bui-col-start-3{grid-column-start:3}.xl\:bui-col-start-4{grid-column-start:4}.xl\:bui-col-start-5{grid-column-start:5}.xl\:bui-col-start-6{grid-column-start:6}.xl\:bui-col-start-7{grid-column-start:7}.xl\:bui-col-start-8{grid-column-start:8}.xl\:bui-col-start-9{grid-column-start:9}.xl\:bui-col-start-10{grid-column-start:10}.xl\:bui-col-start-11{grid-column-start:11}.xl\:bui-col-start-12{grid-column-start:12}.xl\:bui-col-start-13{grid-column-start:13}.xl\:bui-col-start-auto{grid-column-start:auto}.xl\:bui-col-end-1{grid-column-end:1}.xl\:bui-col-end-2{grid-column-end:2}.xl\:bui-col-end-3{grid-column-end:3}.xl\:bui-col-end-4{grid-column-end:4}.xl\:bui-col-end-5{grid-column-end:5}.xl\:bui-col-end-6{grid-column-end:6}.xl\:bui-col-end-7{grid-column-end:7}.xl\:bui-col-end-8{grid-column-end:8}.xl\:bui-col-end-9{grid-column-end:9}.xl\:bui-col-end-10{grid-column-end:10}.xl\:bui-col-end-11{grid-column-end:11}.xl\:bui-col-end-12{grid-column-end:12}.xl\:bui-col-end-13{grid-column-end:13}.xl\:bui-col-end-auto{grid-column-end:auto}.xl\:bui-row-span-1{grid-row:span 1/span 1}.xl\:bui-row-span-2{grid-row:span 2/span 2}.xl\:bui-row-span-3{grid-row:span 3/span 3}.xl\:bui-row-span-4{grid-row:span 4/span 4}.xl\:bui-row-span-5{grid-row:span 5/span 5}.xl\:bui-row-span-6{grid-row:span 6/span 6}.xl\:bui-row-span-7{grid-row:span 7/span 7}.xl\:bui-row-span-8{grid-row:span 8/span 8}.xl\:bui-row-span-9{grid-row:span 9/span 9}.xl\:bui-row-span-10{grid-row:span 10/span 10}.xl\:bui-row-span-11{grid-row:span 11/span 11}.xl\:bui-row-span-12{grid-row:span 12/span 12}.xl\:bui-row-span-auto{grid-row:span auto/span auto}}.bui-gap{gap:var(--gap)}.bui-gap-0\.5{gap:var(--bui-space-0_5)}.bui-gap-1{gap:var(--bui-space-1)}.bui-gap-1\.5{gap:var(--bui-space-1_5)}.bui-gap-2{gap:var(--bui-space-2)}.bui-gap-3{gap:var(--bui-space-3)}.bui-gap-4{gap:var(--bui-space-4)}.bui-gap-5{gap:var(--bui-space-5)}.bui-gap-6{gap:var(--bui-space-6)}.bui-gap-7{gap:var(--bui-space-7)}.bui-gap-8{gap:var(--bui-space-8)}.bui-gap-9{gap:var(--bui-space-9)}.bui-gap-10{gap:var(--bui-space-10)}.bui-gap-11{gap:var(--bui-space-11)}.bui-gap-12{gap:var(--bui-space-12)}.bui-gap-13{gap:var(--bui-space-13)}.bui-gap-14{gap:var(--bui-space-14)}@media (width>=640px){.xs\:bui-gap{gap:var(--gap-xs)}.xs\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.xs\:bui-gap-1{gap:var(--bui-space-1)}.xs\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.xs\:bui-gap-2{gap:var(--bui-space-2)}.xs\:bui-gap-3{gap:var(--bui-space-3)}.xs\:bui-gap-4{gap:var(--bui-space-4)}.xs\:bui-gap-5{gap:var(--bui-space-5)}.xs\:bui-gap-6{gap:var(--bui-space-6)}.xs\:bui-gap-7{gap:var(--bui-space-7)}.xs\:bui-gap-8{gap:var(--bui-space-8)}.xs\:bui-gap-9{gap:var(--bui-space-9)}.xs\:bui-gap-10{gap:var(--bui-space-10)}.xs\:bui-gap-11{gap:var(--bui-space-11)}.xs\:bui-gap-12{gap:var(--bui-space-12)}.xs\:bui-gap-13{gap:var(--bui-space-13)}.xs\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=768px){.sm\:bui-gap{gap:var(--gap-sm)}.sm\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.sm\:bui-gap-1{gap:var(--bui-space-1)}.sm\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.sm\:bui-gap-2{gap:var(--bui-space-2)}.sm\:bui-gap-3{gap:var(--bui-space-3)}.sm\:bui-gap-4{gap:var(--bui-space-4)}.sm\:bui-gap-5{gap:var(--bui-space-5)}.sm\:bui-gap-6{gap:var(--bui-space-6)}.sm\:bui-gap-7{gap:var(--bui-space-7)}.sm\:bui-gap-8{gap:var(--bui-space-8)}.sm\:bui-gap-9{gap:var(--bui-space-9)}.sm\:bui-gap-10{gap:var(--bui-space-10)}.sm\:bui-gap-11{gap:var(--bui-space-11)}.sm\:bui-gap-12{gap:var(--bui-space-12)}.sm\:bui-gap-13{gap:var(--bui-space-13)}.sm\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1024px){.md\:bui-gap{gap:var(--gap-md)}.md\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.md\:bui-gap-1{gap:var(--bui-space-1)}.md\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.md\:bui-gap-2{gap:var(--bui-space-2)}.md\:bui-gap-3{gap:var(--bui-space-3)}.md\:bui-gap-4{gap:var(--bui-space-4)}.md\:bui-gap-5{gap:var(--bui-space-5)}.md\:bui-gap-6{gap:var(--bui-space-6)}.md\:bui-gap-7{gap:var(--bui-space-7)}.md\:bui-gap-8{gap:var(--bui-space-8)}.md\:bui-gap-9{gap:var(--bui-space-9)}.md\:bui-gap-10{gap:var(--bui-space-10)}.md\:bui-gap-11{gap:var(--bui-space-11)}.md\:bui-gap-12{gap:var(--bui-space-12)}.md\:bui-gap-13{gap:var(--bui-space-13)}.md\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1280px){.lg\:bui-gap{gap:var(--gap-lg)}.lg\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.lg\:bui-gap-1{gap:var(--bui-space-1)}.lg\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.lg\:bui-gap-2{gap:var(--bui-space-2)}.lg\:bui-gap-3{gap:var(--bui-space-3)}.lg\:bui-gap-4{gap:var(--bui-space-4)}.lg\:bui-gap-5{gap:var(--bui-space-5)}.lg\:bui-gap-6{gap:var(--bui-space-6)}.lg\:bui-gap-7{gap:var(--bui-space-7)}.lg\:bui-gap-8{gap:var(--bui-space-8)}.lg\:bui-gap-9{gap:var(--bui-space-9)}.lg\:bui-gap-10{gap:var(--bui-space-10)}.lg\:bui-gap-11{gap:var(--bui-space-11)}.lg\:bui-gap-12{gap:var(--bui-space-12)}.lg\:bui-gap-13{gap:var(--bui-space-13)}.lg\:bui-gap-14{gap:var(--bui-space-14)}}@media (width>=1536px){.xl\:bui-gap{gap:var(--gap-xl)}.xl\:bui-gap-0\.5{gap:var(--bui-space-0_5)}.xl\:bui-gap-1{gap:var(--bui-space-1)}.xl\:bui-gap-1\.5{gap:var(--bui-space-1_5)}.xl\:bui-gap-2{gap:var(--bui-space-2)}.xl\:bui-gap-3{gap:var(--bui-space-3)}.xl\:bui-gap-4{gap:var(--bui-space-4)}.xl\:bui-gap-5{gap:var(--bui-space-5)}.xl\:bui-gap-6{gap:var(--bui-space-6)}.xl\:bui-gap-7{gap:var(--bui-space-7)}.xl\:bui-gap-8{gap:var(--bui-space-8)}.xl\:bui-gap-9{gap:var(--bui-space-9)}.xl\:bui-gap-10{gap:var(--bui-space-10)}.xl\:bui-gap-11{gap:var(--bui-space-11)}.xl\:bui-gap-12{gap:var(--bui-space-12)}.xl\:bui-gap-13{gap:var(--bui-space-13)}.xl\:bui-gap-14{gap:var(--bui-space-14)}}.bui-align-start{align-items:start}.bui-align-center{align-items:center}.bui-align-end{align-items:end}.bui-align-baseline{align-items:baseline}.bui-align-stretch{align-items:stretch}.bui-jc-start{justify-content:start}.bui-jc-center{justify-content:center}.bui-jc-end{justify-content:end}.bui-jc-between{justify-content:space-between}.bui-fd-row{flex-direction:row}.bui-fd-column{flex-direction:column}.bui-fd-row-reverse{flex-direction:row-reverse}.bui-fd-column-reverse{flex-direction:column-reverse}@media (width>=640px){.xs\:bui-align-start{align-items:start}.xs\:bui-align-center{align-items:center}.xs\:bui-align-end{align-items:end}.xs\:bui-align-stretch{align-items:stretch}.xs\:bui-jc-start{justify-content:start}.xs\:bui-jc-center{justify-content:center}.xs\:bui-jc-end{justify-content:end}.xs\:bui-jc-between{justify-content:space-between}.xs\:bui-fd-row{flex-direction:row}.xs\:bui-fd-column{flex-direction:column}.xs\:bui-fd-row-reverse{flex-direction:row-reverse}.xs\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=768px){.sm\:bui-align-start{align-items:start}.sm\:bui-align-center{align-items:center}.sm\:bui-align-end{align-items:end}.sm\:bui-align-stretch{align-items:stretch}.sm\:bui-jc-start{justify-content:start}.sm\:bui-jc-center{justify-content:center}.sm\:bui-jc-end{justify-content:end}.sm\:bui-jc-between{justify-content:space-between}.sm\:bui-fd-row{flex-direction:row}.sm\:bui-fd-column{flex-direction:column}.sm\:bui-fd-row-reverse{flex-direction:row-reverse}.sm\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1024px){.md\:bui-align-start{align-items:start}.md\:bui-align-center{align-items:center}.md\:bui-align-end{align-items:end}.md\:bui-align-stretch{align-items:stretch}.md\:bui-jc-start{justify-content:start}.md\:bui-jc-center{justify-content:center}.md\:bui-jc-end{justify-content:end}.md\:bui-jc-between{justify-content:space-between}.md\:bui-fd-row{flex-direction:row}.md\:bui-fd-column{flex-direction:column}.md\:bui-fd-row-reverse{flex-direction:row-reverse}.md\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1280px){.lg\:bui-align-start{align-items:start}.lg\:bui-align-center{align-items:center}.lg\:bui-align-end{align-items:end}.lg\:bui-align-stretch{align-items:stretch}.lg\:bui-jc-start{justify-content:start}.lg\:bui-jc-center{justify-content:center}.lg\:bui-jc-end{justify-content:end}.lg\:bui-jc-between{justify-content:space-between}.lg\:bui-fd-row{flex-direction:row}.lg\:bui-fd-column{flex-direction:column}.lg\:bui-fd-row-reverse{flex-direction:row-reverse}.lg\:bui-fd-column-reverse{flex-direction:column-reverse}}@media (width>=1536px){.xl\:bui-align-start{align-items:start}.xl\:bui-align-center{align-items:center}.xl\:bui-align-end{align-items:end}.xl\:bui-align-stretch{align-items:stretch}.xl\:bui-jc-start{justify-content:start}.xl\:bui-jc-center{justify-content:center}.xl\:bui-jc-end{justify-content:end}.xl\:bui-jc-between{justify-content:space-between}.xl\:bui-fd-row{flex-direction:row}.xl\:bui-fd-column{flex-direction:column}.xl\:bui-fd-row-reverse{flex-direction:row-reverse}.xl\:bui-fd-column-reverse{flex-direction:column-reverse}}} \ No newline at end of file diff --git a/docs-ui/public/theme-spotify.css b/docs-ui/public/theme-spotify.css index b0bf517701..0f2ecc6081 100644 --- a/docs-ui/public/theme-spotify.css +++ b/docs-ui/public/theme-spotify.css @@ -1 +1 @@ -@font-face{font-family:CircularSpTitle;font-weight:900;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSpTitle-Black-4588c99025b967475c31695b0743dd1a.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSpTitle-Black-506746f387a26f25aa3d023b3e501d34.woff)format("woff")}@font-face{font-family:CircularSpTitle;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-b2586b06a2e1522e9d879d84c2792a58.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-1624fb2df28c20d7203d7fb86ce8b481.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:400;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Book-a00e99ef9996a3a157fb6b746856d04f.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Book-3f73da7d35bd81c706bce7bbb84964de.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)format("woff")}[data-theme-name=spotify]{--bui-font-text:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--bui-font-title:CircularSpTitle,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--bui-font-regular:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;& .bui-Button{border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-3)}& .bui-ButtonIcon{padding:0}& .bui-MenuPopup{box-sizing:border-box;max-width:21.25rem}& .bui-MenuSubmenuTrigger,& .bui-MenuItem{height:auto;min-height:2rem}& .bui-Text{font-family:var(--bui-font-text)}& .bui-Heading{font-family:var(--bui-font-title)}& .bui-TableRow{border-radius:var(--bui-radius-4);border:none}& .bui-TableRow:hover td:first-child{border-top-left-radius:var(--bui-radius-2);border-bottom-left-radius:var(--bui-radius-2)}& .bui-TableRow:hover td:last-child{border-top-right-radius:var(--bui-radius-2);border-bottom-right-radius:var(--bui-radius-2)}& .bui-TableBody:before,& .bui-TableBody:after{line-height:var(--bui-space-1);content:"‌";display:block}& .bui-TableHeader .bui-TableRow{border-bottom:1px solid var(--bui-border)}& .bui-TableHead{font-size:var(--bui-font-size-2);color:var(--bui-fg-secondary);font-weight:var(--bui-font-weight-regular)}& .bui-HeaderToolbar{padding-top:var(--bui-space-2);padding-inline:var(--bui-space-2)}& .bui-HeaderToolbarWrapper{border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-3);border:none}& .bui-HeaderToolbarControls{right:calc(var(--bui-space-3) - 1px)}& .bui-HeaderTabsWrapper{margin-top:var(--bui-space-2);margin-inline:var(--bui-space-2);border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-1);border:none}& .bui-Input{border-radius:var(--bui-radius-3)}& .bui-Tag{border-radius:var(--bui-radius-full)}}[data-theme-mode=light][data-theme-name=spotify]{--bui-bg:var(--bui-gray-1);--bui-bg-surface-1:var(--bui-white);--bui-bg-surface-2:var(--bui-gray-2);--bui-bg-solid:#1ed760;--bui-bg-solid-hover:#3be477;--bui-bg-solid-pressed:#1abc54;--bui-bg-solid-disabled:var(--bui-gray-2);--bui-fg-primary:var(--bui-black);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-solid:var(--bui-black);--bui-border:var(--bui-gray-3);--bui-border-hover:#0000004d;--bui-border-pressed:#00000080;--bui-border-disabled:#0000001a;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#0003;& .bui-HeaderToolbarWrapper,& .bui-HeaderTabsWrapper{border:1px solid var(--bui-border)}}[data-theme-mode=dark][data-theme-name=spotify]{--bui-bg:var(--bui-black);--bui-bg-surface-1:var(--bui-gray-1);--bui-bg-surface-2:var(--bui-gray-2);--bui-bg-solid:#1ed760;--bui-bg-solid-hover:#3be477;--bui-bg-solid-pressed:#1abc54;--bui-bg-solid-disabled:#0f6c30;--bui-bg-tint:#242424;--bui-bg-tint-hover:#202020;--bui-bg-tint-pressed:#292929;--bui-bg-tint-disabled:#fffc;--bui-bg-danger:#3b1219;--bui-bg-warning:#302008;--bui-bg-success:#132d21;--bui-fg-primary:var(--bui-white);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:var(--bui-white);--bui-fg-link-hover:var(--bui-white);--bui-fg-disabled:var(--bui-gray-5);--bui-fg-solid:var(--bui-black);--bui-fg-solid-disabled:#083618;--bui-fg-tint:var(--bui-white);--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:var(--bui-gray-3);--bui-border-hover:#fff6;--bui-border-pressed:#ffffff80;--bui-border-disabled:#fff3;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#fff3} \ No newline at end of file +@font-face{font-family:CircularSpTitle;font-weight:900;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSpTitle-Black-4588c99025b967475c31695b0743dd1a.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSpTitle-Black-506746f387a26f25aa3d023b3e501d34.woff)format("woff")}@font-face{font-family:CircularSpTitle;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-b2586b06a2e1522e9d879d84c2792a58.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-1624fb2df28c20d7203d7fb86ce8b481.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:400;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Book-a00e99ef9996a3a157fb6b746856d04f.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Book-3f73da7d35bd81c706bce7bbb84964de.woff)format("woff")}@font-face{font-family:CircularSp;font-weight:700;font-display:swap;unicode-range:U+0,U+D,U+20-7E,U+A0-17E,U+18F,U+192,U+1A0-1A1,U+1AF-1B0,U+1B5-1B6,U+1C4-1C6,U+1F1-1F3,U+1FA-1FF,U+218-21B,U+237,U+259,U+2BB-2BC,U+2C6-2C7,U+2C9,U+2D8-2DD,U+300-301,U+303,U+309,U+323,U+394,U+3A9,U+3BC,U+3C0,U+1E80-1E85,U+1E8A-1E8B,U+1EA0-1EF9,U+1FD6,U+2007-2008,U+200B,U+2010-2011,U+2013-2014,U+2018-201A,U+201C-201E,U+2020-2022,U+2026,U+2030,U+2032-2033,U+2039-203A,U+2042,U+2044,U+2051,U+2070,U+2074-2079,U+2080-2089,U+20AB-20AC,U+2113,U+2117,U+2122,U+2126,U+2160-2169,U+216C-216F,U+2190-2193,U+2196-2199,U+21A9,U+21B0-21B5,U+21C6,U+2202,U+2206,U+220F,U+2211-2212,U+2215,U+2219-221A,U+221E,U+222B,U+2248,U+2260,U+2264-2265,U+22C5,U+24C5,U+25A0-25A1,U+25AF,U+25B2-25B3,U+25CA-25CB,U+25CF,U+262E,U+2713,U+2715,U+2780-2788,U+E000,U+E002,U+F6C3,U+FB00-FB04,U+FEFF,U+FF0C,U+FF0E,U+FF1A-FF1B,U+FFFF;src:url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)format("woff2"),url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)format("woff")}[data-theme-name=spotify]{--bui-font-text:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--bui-font-title:CircularSpTitle,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;--bui-font-regular:CircularSp,CircularSp-Arab,CircularSp-Hebr,CircularSp-Cyrl,CircularSp-Grek,CircularSp-Deva;& .bui-Button{border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-3)}& .bui-ButtonIcon{padding:0}& .bui-MenuPopup{box-sizing:border-box;max-width:21.25rem}& .bui-MenuSubmenuTrigger,& .bui-MenuItem{height:auto;min-height:2rem}& .bui-Text{font-family:var(--bui-font-text)}& .bui-Heading{font-family:var(--bui-font-title)}& .bui-TableRow{border-radius:var(--bui-radius-4);border:none}& .bui-TableRow:hover td:first-child{border-top-left-radius:var(--bui-radius-2);border-bottom-left-radius:var(--bui-radius-2)}& .bui-TableRow:hover td:last-child{border-top-right-radius:var(--bui-radius-2);border-bottom-right-radius:var(--bui-radius-2)}& .bui-TableBody:before,& .bui-TableBody:after{line-height:var(--bui-space-1);content:"‌";display:block}& .bui-TableHeader .bui-TableRow{border-bottom:1px solid var(--bui-border)}& .bui-TableHead{font-size:var(--bui-font-size-2);color:var(--bui-fg-secondary);font-weight:var(--bui-font-weight-regular)}& .bui-HeaderToolbar{padding-top:var(--bui-space-2);padding-inline:var(--bui-space-2)}& .bui-HeaderToolbarWrapper{border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-3);border:none}& .bui-HeaderToolbarControls{right:calc(var(--bui-space-3) - 1px)}& .bui-HeaderTabsWrapper{margin-top:var(--bui-space-2);margin-inline:var(--bui-space-2);border-radius:var(--bui-radius-3);padding-inline:var(--bui-space-1);border:none}& .bui-Input{border-radius:var(--bui-radius-3)}& .bui-Tag{border-radius:var(--bui-radius-full)}}[data-theme-mode=light][data-theme-name=spotify]{--bui-bg-solid:#1ed760;--bui-bg-solid-hover:#3be477;--bui-bg-solid-pressed:#1abc54;--bui-bg-solid-disabled:var(--bui-gray-2);--bui-fg-primary:var(--bui-black);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-solid:var(--bui-black);--bui-border:var(--bui-gray-3);--bui-border-hover:#0000004d;--bui-border-pressed:#00000080;--bui-border-disabled:#0000001a;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#0003;& .bui-HeaderToolbarWrapper,& .bui-HeaderTabsWrapper{border:1px solid var(--bui-border)}}[data-theme-mode=dark][data-theme-name=spotify]{--bui-bg-surface-0:var(--bui-black);--bui-bg-solid:#1ed760;--bui-bg-solid-hover:#3be477;--bui-bg-solid-pressed:#1abc54;--bui-bg-solid-disabled:#0f6c30;--bui-bg-tint:#242424;--bui-bg-tint-hover:#202020;--bui-bg-tint-pressed:#292929;--bui-bg-tint-disabled:#fffc;--bui-bg-danger:#3b1219;--bui-bg-warning:#302008;--bui-bg-success:#132d21;--bui-fg-primary:var(--bui-white);--bui-fg-secondary:var(--bui-gray-7);--bui-fg-link:var(--bui-white);--bui-fg-link-hover:var(--bui-white);--bui-fg-disabled:var(--bui-gray-5);--bui-fg-solid:var(--bui-black);--bui-fg-solid-disabled:#083618;--bui-fg-tint:var(--bui-white);--bui-fg-tint-disabled:var(--bui-gray-5);--bui-fg-danger:#e22b2b;--bui-fg-warning:#e36d05;--bui-fg-success:#1db954;--bui-border:var(--bui-gray-3);--bui-border-hover:#fff6;--bui-border-pressed:#ffffff80;--bui-border-disabled:#fff3;--bui-border-danger:#f87a7a;--bui-border-warning:#e36d05;--bui-border-success:#53db83;--bui-ring:#fff3} \ No newline at end of file diff --git a/docs-ui/src/app/tokens/page.mdx b/docs-ui/src/app/tokens/page.mdx index 8e9031c81c..97266afbf4 100644 --- a/docs-ui/src/app/tokens/page.mdx +++ b/docs-ui/src/app/tokens/page.mdx @@ -187,7 +187,7 @@ These colors are used for special purposes like ring, scrollbar, ... ## Core background colors These colors are used for the background of your application. We are mostly using for now a -single elevated background for panels. `--bui-bg` should mostly use as the main background +single elevated background for panels. `--bui-bg-surface-0` should mostly use as the main background color of your app. @@ -200,7 +200,7 @@ color of your app. - --bui-bg + --bui-bg-surface-0 The background color of your Backstage instance. diff --git a/docs-ui/src/components/Snippet/styles.module.css b/docs-ui/src/components/Snippet/styles.module.css index 3141564293..ed5bd22def 100644 --- a/docs-ui/src/components/Snippet/styles.module.css +++ b/docs-ui/src/components/Snippet/styles.module.css @@ -7,7 +7,7 @@ .preview { border-radius: 8px; box-shadow: inset 0 0 0 1px var(--border); - background-color: var(--bui-bg); + background-color: var(--bui-bg-surface-0); padding: 1px; position: relative; } diff --git a/docs-ui/src/snippets/code-snippets.ts b/docs-ui/src/snippets/code-snippets.ts index 1a22a24340..57169ae32a 100644 --- a/docs-ui/src/snippets/code-snippets.ts +++ b/docs-ui/src/snippets/code-snippets.ts @@ -4,7 +4,7 @@ export const customTheme = `:root { --bui-font-regular: system-ui; --bui-font-weight-regular: 400; --bui-font-weight-bold: 600; - --bui-bg: #f8f8f8; + --bui-bg-surface-0: #f8f8f8; --bui-bg-surface-1: #fff; /* ... other CSS variables */ @@ -19,7 +19,7 @@ export const customTheme = `:root { --bui-font-regular: system-ui; --bui-font-weight-regular: 400; --bui-font-weight-bold: 600; - --bui-bg: #f8f8f8; + --bui-bg-surface-0: #f8f8f8; --bui-bg-surface-1: #fff; /* ... other CSS variables */ diff --git a/docs-ui/yarn.lock b/docs-ui/yarn.lock index 7d22bb8977..755b88ec09 100644 --- a/docs-ui/yarn.lock +++ b/docs-ui/yarn.lock @@ -1240,11 +1240,11 @@ __metadata: languageName: node linkType: hard -"@storybook/core@npm:8.6.14": - version: 8.6.14 - resolution: "@storybook/core@npm:8.6.14" +"@storybook/core@npm:8.6.15": + version: 8.6.15 + resolution: "@storybook/core@npm:8.6.15" dependencies: - "@storybook/theming": "npm:8.6.14" + "@storybook/theming": "npm:8.6.15" better-opn: "npm:^3.0.2" browser-assert: "npm:^1.2.1" esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0" @@ -1260,7 +1260,7 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 10/8f8c811edd4ea8dcedcc63a79b3168dc83aa0401e3760990cb5995ea6beaac4026c6ccc1046182f41eed7c09333005f3348d8b42f89fc5dd5b2ce011a9d2a48f + checksum: 10/d268d6fa00c38b35e5c363ee33779c2e087ab8e4681e0e205baa2fdb2780ea9feda3c9f6db35d60092778878d2782b2093c744bdf1af173c5688c3e1e0e960ac languageName: node linkType: hard @@ -1334,6 +1334,15 @@ __metadata: languageName: node linkType: hard +"@storybook/theming@npm:8.6.15": + version: 8.6.15 + resolution: "@storybook/theming@npm:8.6.15" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 10/f02760831a13d7af9dbfeb6feea949f4c13c897861cbc75253a6776d133891567889c8d99c7e91a99124d0772c3bde1f978984c83b19117d1d7c908ed7eb8409 + languageName: node + linkType: hard + "@swc/helpers@npm:0.5.15": version: 0.5.15 resolution: "@swc/helpers@npm:0.5.15" @@ -1618,8 +1627,8 @@ __metadata: linkType: hard "@uiw/codemirror-themes@npm:^4.23.7": - version: 4.25.3 - resolution: "@uiw/codemirror-themes@npm:4.25.3" + version: 4.25.4 + resolution: "@uiw/codemirror-themes@npm:4.25.4" dependencies: "@codemirror/language": "npm:^6.0.0" "@codemirror/state": "npm:^6.0.0" @@ -1628,7 +1637,7 @@ __metadata: "@codemirror/language": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 10/f808ac3c4763f623ed6ea6215cc1421bb87234e0a05e7b6d9e917ab304fc6a4977c238996ca538e22093af8136c02bb27512aeeac653cb8fe82b4917ba1668a3 + checksum: 10/aab62e2c16a10dbde4592cef704d386c1a9e3caece4ff0eed85e9d9a5acdeaf3fd8717e2cb6a6795e12e890b8600956effb52d453aacbc618934e7ae8c3e59e3 languageName: node linkType: hard @@ -2188,9 +2197,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001735 - resolution: "caniuse-lite@npm:1.0.30001735" - checksum: 10/4b404ed363a5ccf3ec07144c2360106aa47dcec1f896ea6705a2773c6977e9ffb19a2b58be9492462733170e29b4823211533b0986d5a25f0f65f7ff702470ab + version: 1.0.30001760 + resolution: "caniuse-lite@npm:1.0.30001760" + checksum: 10/ac5c13d00b946c3ace331d25379ed9d85743b1028aba79ae80402cb128b4b491122585144898fefb836d4d9879c13c717a081ae241a00420cbbc7e1b934ec685 languageName: node linkType: hard @@ -2539,7 +2548,7 @@ __metadata: react: "npm:19.1.1" react-dom: "npm:19.1.1" shiki: "npm:^3.13.0" - storybook: "npm:^8.6.12" + storybook: "npm:^8.6.15" typescript: "npm:^5" unified: "npm:^11.0.4" languageName: unknown @@ -3451,9 +3460,9 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^12.23.25": - version: 12.23.25 - resolution: "framer-motion@npm:12.23.25" +"framer-motion@npm:^12.23.26": + version: 12.23.26 + resolution: "framer-motion@npm:12.23.26" dependencies: motion-dom: "npm:^12.23.23" motion-utils: "npm:^12.23.6" @@ -3469,7 +3478,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/0b55dc0a5319cd923cdddcb42726352f0d74a8160f5222a3f090af53bbb2ed0d93c8482da41c9ffa875a3f7f666586e43be7594dca3612e70a1dea6bfbefebb4 + checksum: 10/29d51ac57ce8c2599664bf706d7a83c2aba4fe1dee1c0c7d75d5c45c120b1c2ca5d257c3ff608992b26bf8e9cf258cacf231b0873d7b16f01c5eeb42b9831f78 languageName: node linkType: hard @@ -5265,10 +5274,10 @@ __metadata: linkType: hard "motion@npm:^12.4.1": - version: 12.23.25 - resolution: "motion@npm:12.23.25" + version: 12.23.26 + resolution: "motion@npm:12.23.26" dependencies: - framer-motion: "npm:^12.23.25" + framer-motion: "npm:^12.23.26" tslib: "npm:^2.4.0" peerDependencies: "@emotion/is-prop-valid": "*" @@ -5281,7 +5290,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 10/67e86dd3c695362812fd86d06e82bb53173900212a78802c94adbcff947e70316141ec6e2908fb3ebf70d3686578bb7fbe7a820a359ce553cd2d79ff77fc1428 + checksum: 10/c5e683d2c67e55816587cbbd451c5600dc0602aa04108ab0bf8d4472befd490e90b3177362dbc8b9f96316ec16383924cc574eb7c9e031540f1e88e64a2704ae languageName: node linkType: hard @@ -6473,11 +6482,11 @@ __metadata: languageName: node linkType: hard -"storybook@npm:^8.6.12": - version: 8.6.14 - resolution: "storybook@npm:8.6.14" +"storybook@npm:^8.6.15": + version: 8.6.15 + resolution: "storybook@npm:8.6.15" dependencies: - "@storybook/core": "npm:8.6.14" + "@storybook/core": "npm:8.6.15" peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -6487,7 +6496,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 10/104932fe29ebf49bef24c90285741cec964d1c36b3f0b38da1dace31ac664be457f2a510e41ba69fe8aa0d90c20e3446fec27d1ced41e5eefb3a9ca713d99e79 + checksum: 10/15762c79ec8444a46bc14cddfadbdd54dfd379828acd38555887a246c01e7c9ebb61e4eafafe04efb3ddf6278fb47035216e7f7d9f94fc205da148870173abdf languageName: node linkType: hard diff --git a/docs/api/utility-apis.md b/docs/api/utility-apis.md index 3e60124775..8d882227ec 100644 --- a/docs/api/utility-apis.md +++ b/docs/api/utility-apis.md @@ -10,31 +10,31 @@ Backstage plugins strive to be self-contained, with as much functionality as pos Backstage provides two primary methods for plugins to communicate across their boundaries in client-side code. The first one being the -[`createPlugin`](../reference/core-plugin-api.createplugin.md) API along with the +[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) API along with the extensions that it can provide, and the second one being Utility APIs. While the -[`createPlugin`](../reference/core-plugin-api.createplugin.md) API is focused on +[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) API is focused on the initialization plugins and the app, the Utility APIs provide ways for plugins to communicate during their entire life cycle. ## Consuming APIs -Each Utility API is tied to an [`ApiRef`](../reference/frontend-plugin-api.apiref.md) +Each Utility API is tied to an [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) instance, which is a global singleton object without any additional state or functionality, its only purpose is to reference Utility APIs. -[`ApiRef`](../reference/frontend-plugin-api.apiref.md)s are created using -[`createApiRef`](../reference/frontend-plugin-api.createapiref.md), which is exported -by [`@backstage/core-plugin-api`](../reference/core-plugin-api.md). There are also +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s are created using +[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html), which is exported +by [`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). There are also many predefined Utility APIs in -[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), and they're all +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), and they're all exported with a name of the pattern `*ApiRef`, for example -[`errorApiRef`](../reference/frontend-plugin-api.errorapiref.md). +[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html). To access one of the Utility APIs inside a React component, use the -[`useApi`](../reference/frontend-plugin-api.useapi.md) hook exported by -[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), or the -[`withApis`](../reference/frontend-plugin-api.withapis.md) HOC if you prefer class +[`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) hook exported by +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), or the +[`withApis`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.withApis.html) HOC if you prefer class components. For example, the -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md) can be accessed like this: +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html) can be accessed like this: ```tsx import { useApi, errorApiRef } from '@backstage/core-plugin-api'; @@ -52,14 +52,14 @@ export const MyComponent = () => { ``` Note that there is no explicit type given for -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md). This is because the -[`errorApiRef`](../reference/frontend-plugin-api.errorapiref.md) has the type -embedded, and [`useApi`](../reference/frontend-plugin-api.useapi.md) is able to infer +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html). This is because the +[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) has the type +embedded, and [`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) is able to infer the type. Also note that consuming Utility APIs is not limited to plugins; it can be done from any component inside Backstage, including the ones in -[`@backstage/core-plugin-api`](../reference/core-plugin-api.md). The only +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). The only requirement is that they are beneath the `AppProvider` in the react tree. ## Supplying APIs @@ -67,15 +67,15 @@ requirement is that they are beneath the `AppProvider` in the react tree. ### API Factories APIs are registered in the form of -[`ApiFactory`](../reference/frontend-plugin-api.apifactory.md) instances, which encapsulate +[`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) instances, which encapsulate the process of instantiating an API. It is a collection of three things: the -[`ApiRef`](../reference/frontend-plugin-api.apiref.md) of the API to instantiate, a +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) of the API to instantiate, a list of all required dependencies, and a factory function that returns a new API instance. For example, this is the default -[`ApiFactory`](../reference/frontend-plugin-api.apifactory.md) for the -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md): +[`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) for the +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html): ```ts createApiFactory({ @@ -89,25 +89,25 @@ createApiFactory({ }); ``` -In this example, the [`errorApiRef`](../reference/frontend-plugin-api.errorapiref.md) +In this example, the [`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) is our API, which encapsulates the -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md) type. The -[`alertApiRef`](../reference/frontend-plugin-api.alertapiref.md) is our single +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html) type. The +[`alertApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.alertApiRef.html) is our single dependency, which we give the name `alertApi`, and is then passed on to the factory function, which returns an implementation of the -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md). +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html). -The [`createApiFactory`](../reference/frontend-plugin-api.createapifactory.md) +The [`createApiFactory`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiFactory.html) function is a thin wrapper that enables TypeScript type inference. You may notice that there are no type annotations in the above example, and that is because we're able to infer all types from the -[`ApiRef`](../reference/frontend-plugin-api.apiref.md)s. TypeScript will make sure +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s. TypeScript will make sure that the return value of the `factory` function matches the type embedded in -`api`'s [`ApiRef`](../reference/frontend-plugin-api.apiref.md), in this case the -[`ErrorApi`](../reference/frontend-plugin-api.errorapi.md). It will also match the +`api`'s [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), in this case the +[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html). It will also match the types between the `deps` and the parameters of the `factory` function, again using the type embedded within the -[`ApiRef`](../reference/frontend-plugin-api.apiref.md)s. +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s. ## Registering API Factories @@ -119,13 +119,13 @@ app, and the app itself. Starting with the Backstage core library, it provides implementations for all of the core APIs. The core APIs are the ones exported by -[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), such as the -[`errorApiRef`](../reference/frontend-plugin-api.errorapiref.md) and -[`configApiRef`](../reference/frontend-plugin-api.configapiref.md). +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), such as the +[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) and +[`configApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.configApiRef.html). The core APIs are loaded for any app created with -[`createApp`](../reference/app-defaults.createapp.md) from -[`@backstage/core-plugin-api`](../reference/app-defaults.md), which means that +[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html) from +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), which means that there is no step that needs to be taken to include these APIs in an app. ### Plugin APIs @@ -133,13 +133,13 @@ there is no step that needs to be taken to include these APIs in an app. In addition to the core APIs, plugins can define and export their own APIs. While doing so, they should usually also provide default implementations of their own APIs; for example, the `catalog` plugin exports `catalogApiRef` and also -supplies a default [`ApiFactory`](../reference/frontend-plugin-api.apifactory.md) of +supplies a default [`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) of that API using the `CatalogClient`. There is one restriction to plugin-provided API Factories: plugins may not supply factories for core APIs; trying to do so will cause the app to refuse to start. Plugins supply their APIs through the `apis` option of -[`createPlugin`](../reference/core-plugin-api.createplugin.md), for example: +[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html), for example: ```ts export const techdocsPlugin = createPlugin({ @@ -164,7 +164,7 @@ Lastly, the app itself is the final point where APIs can be added, and what has the final say in what APIs will be loaded at runtime? The app may override the factories for any of the core or plugin APIs, with the exception of the config, app theme, and identity APIs. These are static APIs that are tied into the -[`createApp`](../reference/app-defaults.createapp.md) implementation and +[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html) implementation and therefore, not possible to override. Overriding APIs is useful for apps that want to switch out behavior to tailor it @@ -227,33 +227,33 @@ const app = createApp({ ``` Note that the above line will cause an error if `IgnoreErrorApi` does not fully -implement the [`ErrorApi`](../reference/frontend-plugin-api.errorapi.md), as it is +implement the [`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html), as it is checked by the type embedded in the -[`errorApiRef`](../reference/frontend-plugin-api.errorapiref.md) at compile time. +[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) at compile time. ## Defining custom Utility APIs Plugins are free to define their own Utility APIs. Simply define the TypeScript interface for the API and create an -[`ApiRef`](../reference/frontend-plugin-api.apiref.md) using -[`createApiRef`](../reference/frontend-plugin-api.createapiref.md) exported from -[`@backstage/core-plugin-api`](../reference/core-plugin-api.md). Also, be sure to +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) using +[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html) exported from +[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). Also, be sure to provide at least one implementation of the API and to declare a default factory -for the API in [`createPlugin`](../reference/core-plugin-api.createplugin.md). +for the API in [`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html). Custom Utility APIs can be either public or private, which is up to the plugin to choose. Private APIs do not expose an external API surface, and it's therefore possible to make breaking changes to the API without affecting other users of the plugin. If an API is made public, however, it opens up for other plugins to make use of the API, and it also makes it possible for users for your plugin to override the API in the app. It is, however, important to maintain backward compatibility of public APIs, as you may otherwise break apps that are using your plugin. To make an API public, simply export the -[`ApiRef`](../reference/frontend-plugin-api.apiref.md) of the API, and any associated +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) of the API, and any associated types. To make an API private, just avoid exporting the -[`ApiRef`](../reference/frontend-plugin-api.apiref.md), but still be sure to supply a -default factory to [`createPlugin`](../reference/core-plugin-api.createplugin.md). +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), but still be sure to supply a +default factory to [`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html). Private APIs are useful for plugins that want to depend on other APIs outside of React components, but not have to expose an entire API surface to maintain. When using private APIs, it is fine to use the `typeof` of an implementing class as the type parameter passed to -[`createApiRef`](../reference/frontend-plugin-api.createapiref.md), while public APIs +[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html), while public APIs should always define a separate TypeScript interface type. Plugins may depend on APIs from other plugins, both in React components and as @@ -262,13 +262,13 @@ dependencies between plugins. ## Architecture -The [`ApiRef`](../reference/frontend-plugin-api.apiref.md) instances mentioned above +The [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) instances mentioned above provide a point of indirection between consumers and producers of Utility APIs. It allows for plugins and components to depend on APIs in a type-safe way, without having a direct reference to a concrete implementation of the APIs. The Apps are also given a lot of flexibility in what implementations to provide. As long as they adhere to the contract established by an -[`ApiRef`](../reference/frontend-plugin-api.apiref.md), they are free to choose any +[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), they are free to choose any implementation they want. The figure below shows the relationship between @@ -291,16 +291,16 @@ The indirection provided by Utility APIs also makes it straightforward to test components that depend on APIs, and to provide a standard common development environment for plugins. A proper test wrapper with mocked API implementations is not yet ready, but it will be provided as a part of -[`@backstage/test-utils`](../reference/test-utils.md). It will provide mocked +[`@backstage/test-utils`](https://backstage.io/api/stable/modules/_backstage_test-utils.html). It will provide mocked variants of APIs, with additional methods for asserting a component's interaction with the API. The common development environment for plugins is included in -[`@backstage/dev-utils`](../reference/dev-utils.md), where the exported -[`createDevApp`](../reference/dev-utils.createdevapp.md) function creates an +[`@backstage/dev-utils`](https://backstage.io/api/stable/modules/_backstage_dev-utils.html), where the exported +[`createDevApp`](https://backstage.io/api/stable/functions/_backstage_dev-utils.createDevApp.html) function creates an application with implementations for all core APIs already present. Contrary to the method for wiring up Utility API implementations in an app created with -[`createApp`](../reference/app-defaults.createapp.md), -[`createDevApp`](../reference/dev-utils.createdevapp.md) uses automatic dependency +[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html), +[`createDevApp`](https://backstage.io/api/stable/functions/_backstage_dev-utils.createDevApp.html) uses automatic dependency injection. This is to make it possible to replace any API implementation, and having that be reflected in dependents of that API. diff --git a/docs/assets/getting-started/create-app-output.png b/docs/assets/getting-started/create-app-output.png index 1987ea41e1..305f2e001a 100644 Binary files a/docs/assets/getting-started/create-app-output.png and b/docs/assets/getting-started/create-app-output.png differ diff --git a/docs/assets/getting-started/login-to-app-as-guest-user.png b/docs/assets/getting-started/login-to-app-as-guest-user.png new file mode 100644 index 0000000000..79c897dcb6 Binary files /dev/null and b/docs/assets/getting-started/login-to-app-as-guest-user.png differ diff --git a/docs/assets/getting-started/portal.png b/docs/assets/getting-started/portal.png index b3133f2278..fd7d52d193 100644 Binary files a/docs/assets/getting-started/portal.png and b/docs/assets/getting-started/portal.png differ diff --git a/docs/auth/index.md b/docs/auth/index.md index a3141d0434..1d668f6961 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -340,7 +340,7 @@ The method with which frontend plugins request access to third-party services is through [Utility APIs](../api/utility-apis.md) for each service provider. These are all suffixed with `*AuthApiRef`, for example `githubAuthApiRef`. For a full list of providers, see the -[@backstage/core-plugin-api](../reference/core-plugin-api.md#variables) reference. +[@backstage/core-plugin-api](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.index.html#alertapiref) reference. ## Custom Authentication Provider diff --git a/docs/auth/oidc.md b/docs/auth/oidc.md index 7c4b09d9bf..55827ab1dc 100644 --- a/docs/auth/oidc.md +++ b/docs/auth/oidc.md @@ -241,6 +241,12 @@ These parameters have implicit default values. Don't override them unless you kn - `prompt`: Recommended to use `auto` so the browser will request sign-in to the IDP if the user has no active session. - `sessionDuration`: Lifespan of the user session. +- `startUrlSearchParams`: This is a dictionary of search (query) parameters for the OIDC + authorization start URL. Don't define it unless you want to change the identity + provider's behavior. (For example, you could set the `organization` parameter to guide + users towards a particular sign-in option that your organization prefers.) **Note:** the + start URL is controlled by the browser, so this feature is only for improving the + Backstage user experience. :::note Config Reloading Backstage does not yet support hot reloading of auth provider configuration. Any changes to this YAML file require a restart of Backstage. diff --git a/docs/backend-system/core-services/cache.md b/docs/backend-system/core-services/cache.md index ad4d04b50a..a23332409b 100644 --- a/docs/backend-system/core-services/cache.md +++ b/docs/backend-system/core-services/cache.md @@ -11,24 +11,84 @@ This service lets your plugin interact with a cache. It is bound to your plugin The cache service can be configured using the `backend.cache` section in your `app-config.yaml`: +### In-Memory (default) + ```yaml backend: cache: - store: redis # or 'valkey', 'memcache', 'memory' + store: memory +``` + +### Memcache + +```yaml +backend: + cache: + store: memcache + connection: user:pass@cache.example.com:11211 +``` + +### Redis + +```yaml +backend: + cache: + store: redis connection: redis://localhost:6379 - # Store-specific configuration (Redis/Valkey only) + # Store-specific configuration (optional) redis: client: - # Optional: Global namespace prefix for all cache keys + # Global namespace prefix for all cache keys namespace: 'my-app' - # Optional: Separator used between namespace and plugin ID (default: ':') + # Separator used between namespace and plugin ID (default: ':') keyPrefixSeparator: ':' # Other Redis-specific options... clearBatchSize: 1000 useUnlink: false ``` +### Valkey + +```yaml +backend: + cache: + store: valkey + connection: redis://localhost:6379 + + # Store-specific configuration (optional) + valkey: + # Global namespace prefix for all cache keys (including separator used between namespace and plugin ID) + keyPrefix: 'my-app:' +``` + +### Infinispan + +```yaml +backend: + cache: + store: infinispan + + # Store-specific configuration (optional) + infinispan: + servers: + # IP address or hostname of the server (default: '127.0.0.1') + - host: 127.0.0.1 + # Port number of the server (default: '11222') + port: 11222 + # Name of the cache (default: 'cache') + cacheName: cache + mediaType: application/json + authentication: + # Whether authentication is enabled (default: 'false') + enabled: true + userName: yourusername + password: yourpassword + saslMechanism: PLAIN +``` + +A full list of configuration items is available [here](https://docs.jboss.org/infinispan/hotrod-clients/javascript/1.0/apidocs/module-infinispan.html), including support for backup clusters. + ### Namespace Configuration For Redis and Valkey stores, you can configure a global namespace that will be prefixed to all cache keys: @@ -36,9 +96,10 @@ For Redis and Valkey stores, you can configure a global namespace that will be p - **Without namespace**: Cache keys use only the plugin ID (e.g., `catalog:some-key`) - **With namespace**: Cache keys use the format `namespace:pluginId:key` (e.g., `my-app:catalog:some-key`) -The `keyPrefixSeparator` controls what character is used between the namespace and plugin ID (defaults to `:`). +For **Redis**, `keyPrefixSeparator` controls what character is used between the namespace and plugin ID (defaults to `:`). +For **Valkey**, you set the full `keyPrefix` including the separator. -**Note**: Memory and Memcache stores do not support namespace configuration and will always use the plugin ID directly. +**Note**: In-memory, Memcache and Infinispan stores do not support namespace configuration and will always use the plugin ID directly. ## Using the service diff --git a/docs/conf/reading.md b/docs/conf/reading.md index a565f3a8a3..b6119b0da9 100644 --- a/docs/conf/reading.md +++ b/docs/conf/reading.md @@ -7,7 +7,7 @@ description: Documentation on Reading Backstage Configuration ## Config API There's a common configuration API for by both frontend and backend plugins. An -API reference can be found [here](../reference/config.config.md). +API reference can be found [here](https://backstage.io/api/stable/types/_backstage_config.Config.html). The configuration API is tailored towards failing fast in case of missing or bad config. That's because configuration errors can always be considered programming @@ -115,7 +115,7 @@ example `getString`. These will throw an error if there is no value available. ## Accessing ConfigApi in Frontend Plugins -The [ConfigApi](../reference/frontend-plugin-api.configapi.md) in the frontend is a +The [ConfigApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ConfigApi.html) in the frontend is a [UtilityApi](../api/utility-apis.md). It's accessible as usual via the `configApiRef` exported from `@backstage/core-plugin-api`: diff --git a/docs/conf/user-interface/index.md b/docs/conf/user-interface/index.md index 81acfdf720..e0fb645d78 100644 --- a/docs/conf/user-interface/index.md +++ b/docs/conf/user-interface/index.md @@ -103,13 +103,13 @@ Backstage UI is using light by default under `:root` but you can target it more [data-theme-mode='light'] { /* Light theme specific styles */ -  --bui-bg: #f8f8f8; +  --bui-bg-surface-0: #f8f8f8; --bui-fg-primary: #000; } [data-theme-mode='dark'] { /* Dark theme specific styles */ -  --bui-bg: #333333; +  --bui-bg-surface-0: #333333; --bui-fg-primary: #fff; } ``` @@ -122,18 +122,18 @@ We recommend starting with a core set of CSS variables to quickly achieve a bran And if you’d like to go even further, you can target specific component class names for advanced customization. -| Token Name | Description | -| -------------------- | ----------------------------------------------------------------------------------- | -| `--bui-bg` | This is used to define the background color of your app. It will only be used once. | -| `--bui-bg-surface-1` | We ar using this color to sit on top of `--bui-bg` mostly for `Card`, `Dialog`, ... | -| `--bui-bg-surface-2` | This is for content inside elevated components. This colour is less common. | -| `--bui-bg-solid` | This is used for main actions like primary buttons. | -| `--bui-fg-solid` | This is for texts or icons on top of a solid backgrounds. | -| `--bui-fg-primary` | Your primary text or icon colours. | -| `--bui-fg-secondary` | Your secondary text or icon colours. | -| `--bui-fg-link` | Used for links. | -| `--bui-border` | Main borders around surfaces like `Card`, `Dialog`, ... | -| `--bui-font-regular` | The main font of your app. | +| Token Name | Description | +| -------------------- | --------------------------------------------------------------------------------------------- | +| `--bui-bg-surface-0` | This is used to define the background color of your app. It will only be used once. | +| `--bui-bg-surface-1` | We ar using this color to sit on top of `--bui-bg-surface-0` mostly for `Card`, `Dialog`, ... | +| `--bui-bg-surface-2` | This is for content inside elevated components. This colour is less common. | +| `--bui-bg-solid` | This is used for main actions like primary buttons. | +| `--bui-fg-solid` | This is for texts or icons on top of a solid backgrounds. | +| `--bui-fg-primary` | Your primary text or icon colours. | +| `--bui-fg-secondary` | Your secondary text or icon colours. | +| `--bui-fg-link` | Used for links. | +| `--bui-border` | Main borders around surfaces like `Card`, `Dialog`, ... | +| `--bui-font-regular` | The main font of your app. |
All available CSS variables @@ -157,13 +157,14 @@ These colors are used for special purposes like ring, scrollbar, ... #### Core background colors -These colors are used for the background of your application. We are mostly using for now a single elevated background for panels. `--bui-bg` should mostly use as the main background color of your app. +These colors are used for the background of your application. We are mostly using for now a single elevated background for panels. `--bui-bg-surface-0` should mostly use as the main background color of your app. | Token Name | Description | | ------------------------- | ------------------------------------------------ | -| `--bui-bg` | The background color of your Backstage instance. | +| `--bui-bg-surface-0` | The background color of your Backstage instance. | | `--bui-bg-surface-1` | Use for any panels or elevated surfaces. | | `--bui-bg-surface-2` | Use for any panels or elevated surfaces. | +| `--bui-bg-surface-3` | Use for any panels or elevated surfaces. | | `--bui-bg-solid` | Used for solid background colors. | | `--bui-bg-solid-hover` | Used for solid background colors when hovered. | | `--bui-bg-solid-pressed` | Used for solid background colors when pressed. | diff --git a/docs/deployment/scaling.md b/docs/deployment/scaling.md index 2c3b687f67..dd765d3c1a 100644 --- a/docs/deployment/scaling.md +++ b/docs/deployment/scaling.md @@ -17,7 +17,7 @@ into multiple different services, each running a different set of plugins. This is a more advanced approach and requires you to be able to route requests to the appropriate backends based on the plugin ID. Both for ingress, but also internal traffic between Backstage backends, which is done by creating a custom -implementation of the [DiscoveryService](../reference/backend-plugin-api.discoveryservice.md) interface. See the [backend system docs](../backend-system/building-backends/01-index.md#split-into-multiple-backends) for more details on how to separate your deployment into multiple backend instances. +implementation of the [DiscoveryService](https://backstage.io/api/stable/interfaces/_backstage_backend-plugin-api.index.DiscoveryService.html) interface. See the [backend system docs](../backend-system/building-backends/01-index.md#split-into-multiple-backends) for more details on how to separate your deployment into multiple backend instances. Lastly, you can also replicate the Backstage deployments across multiple regions. This is not a pattern that there is built-in support for and typically only makes diff --git a/docs/features/software-templates/ui-options-examples.md b/docs/features/software-templates/ui-options-examples.md index 1a024569a6..845da8e60b 100644 --- a/docs/features/software-templates/ui-options-examples.md +++ b/docs/features/software-templates/ui-options-examples.md @@ -468,3 +468,59 @@ repoUrl: The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`. If you're also using the `RepoUrlPicker` field extension, you should simply duplicate this part from there. + +## RepoOwnerPicker + +The input props that can be specified under `ui:options` for the `RepoOwnerPicker` field extension. + +### `host` + +The SCM integration host that owners should be fetched from for autocompletion. + +- Fetch owners from `github.com` + +```yaml +repoUrl: + title: Repository Owner + type: string + ui:field: RepoOwnerPicker + ui:options: + host: github.com +``` + +### `excludedOwners` + +List of owners that should be excluded from autocompletion. + +- Exclude owner `owner_1` from autocompletion + +```yaml +repoUrl: + title: Repository Owner + type: string + ui:field: RepoOwnerPicker + ui:options: + excludedOwners: + - owner_1 +``` + +### `requestUserCredentials` + +If defined will request user credentials to auth against the given SCM platform. + +```yaml +repoUrl: + title: Repository Owner + type: string + ui:field: RepoOwnerPicker + ui:options: + requestUserCredentials: + secretsKey: USER_OAUTH_TOKEN + additionalScopes: + github: + - workflow:write +``` + +`secretsKey` is the key used within the template secrets context to store the credential and `additionalScopes` is any additional permission scopes to request. + +The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`. diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 32f17f945f..5d9fcba603 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -555,6 +555,35 @@ The `RepoBranchPicker` is a custom field that we provide part of the `plugin-scaffolder`. You can provide your own custom fields by [writing your own Custom Field Extensions](./writing-custom-field-extensions.md) +### The Repository Owner Picker + +Similar to the repository picker, there is a picker for owners to support autocompletion. A full example could look like this: + +```yaml +- title: Choose an owner + required: + - repoOwner + properties: + repoOwner: + title: Repository Owner + type: string + ui:field: RepoOwnerPicker + ui:options: + host: github.com + excludedOwners: + - backstage + requestUserCredentials: + secretsKey: USER_OAUTH_TOKEN +``` + +Passing the `requestUserCredentials` and `host` properties is required for autocompletion to work. For more information regarding the `requestUserCredentials` object, please refer to the [Using the Users `oauth` token](#using-the-users-oauth-token) section under [The Repository Picker](#the-repository-picker). + +For a list of all possible `ui:options` input props for `RepoOwnerPicker`, please visit [here](./ui-options-examples.md#repoownerpicker). + +The `RepoOwnerPicker` is a custom field that we provide part of the +`plugin-scaffolder`. You can provide your own custom fields by +[writing your own Custom Field Extensions](./writing-custom-field-extensions.md) + ### Accessing the signed-in users details Sometimes when authoring templates, you'll want to access the user that is running the template, and get details from the profile or the users `Entity` in the Catalog. diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 1fd74becfc..88dff704c4 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -698,16 +698,16 @@ import { SidebarContent } from './Sidebar'; export const navModule = createFrontendModule({ pluginId: 'app', - extensions: [sidebarContent], + extensions: [SidebarContent], }); ``` -Then in the actual implementation for the `sidebarContent` extension, you can provide something like the following, where you implement the entire `Sidebar` component. +Then in the actual implementation for the `SidebarContent` extension, you can provide something like the following, where you implement the entire `Sidebar` component. ```tsx title="in packages/app/src/modules/nav/Sidebar.tsx" import { NavContentBlueprint } from '@backstage/frontend-plugin-api'; -export const sidebarContent = NavContentBlueprint.make({ +export const SidebarContent = NavContentBlueprint.make({ params: { component: ({ items }) => ( diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 283c162fa7..fd88478b37 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -220,6 +220,6 @@ export const examplePlugin = createFrontendPlugin({ }); ``` -The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). +The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](https://backstage.io/api/stable/modules/_backstage_plugin-catalog-react.index.html). For a more complete list of the different kinds of extensions that you can create for your plugin, see the [extension blueprints](./03-common-extension-blueprints.md) section. diff --git a/docs/frontend-system/building-plugins/03-common-extension-blueprints.md b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md index 71989e898f..abac1f03f5 100644 --- a/docs/frontend-system/building-plugins/03-common-extension-blueprints.md +++ b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md @@ -11,35 +11,35 @@ This section covers many of the [extension blueprints](../architecture/23-extens These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage frontend framework itself. -### Api - [Reference](../../reference/frontend-plugin-api.apiblueprint.md) +### Api - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.ApiBlueprint.html) An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override. -### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint.md) +### NavItem - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.NavItemBlueprint.html) Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app. -### Page - [Reference](../../reference/frontend-plugin-api.pageblueprint.md) +### Page - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.PageBlueprint.html) Page extensions provide content for a particular route in the app. By default pages are attached to the app routes extensions, which renders the root routes. -### SignInPage - [Reference](../../reference/frontend-plugin-api.signinpageblueprint.md) +### SignInPage - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.SignInPageBlueprint.html) Sign-in page extension have a single purpose - to implement a custom sign-in page. They are always attached to the app root extension and are rendered before the rest of the app until the user is signed in. -### SwappableComponent - [Reference](../../reference/frontend-plugin-api.swappablecomponentblueprint.md) +### SwappableComponent - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.SwappableComponentBlueprint.html) Swappable Components are extensions that are used to replace the implementations of components in the app and plugins. -### Theme - [Reference](../../reference/frontend-plugin-api.themeblueprint.md) +### Theme - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.ThemeBlueprint.html) Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use. -### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md) +### Icons - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.IconBundleBlueprint.html) Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app. -### Translation - [Reference](../../reference/frontend-plugin-api.translationblueprint.md) +### Translation - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.TranslationBlueprint.html) Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages. diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 876af4f0a5..9075afb82c 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -1,8 +1,8 @@ --- id: index -title: Creating your Backstage App -sidebar_label: Introduction -description: How to install Backstage for your own use. +title: Standalone Installation +sidebar_label: Standalone Installation +description: How to create and run a Standalone Backstage. --- Audience: Developers and Admins @@ -11,11 +11,11 @@ Audience: Developers and Admins It is not required, although recommended to have a basic understanding of [Yarn](https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js) and [npm](https://docs.npmjs.com/about-npm) before starting this guide. ::: -## Summary +## Overview -This guide walks through how to get started creating your very own Backstage customizable app. This is the first step in evaluating, developing on, or demoing Backstage. +This guide walks through how to create your own Backstage customizable app. This is the first step in evaluating, developing on, or demoing Backstage. -By the end of this guide, you will have a standalone Backstage installation running locally with a `SQLite` database and demo content. To be clear, this is not a production-ready installation, and it does not contain information specific to your organization. +By the end of this guide, you will have a standalone Backstage installation running locally with an in-memory `SQLite` database and demo content. To be clear, this is not a production-ready installation, and it does not contain information specific to your organization until you set up integrations with your specific data sources! :::note Contributors @@ -23,46 +23,9 @@ If you are planning to contribute a new feature or bug fix to the Backstage proj ::: -## Prerequisites +The instructions make use of `npx`. `npx` is a tool that comes preinstalled with Node.js and lets you run commands straight from `npm` or other registries. -This guide also assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`. - -- Access to a Unix-based operating system, such as Linux, macOS or - [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) -- A GNU-like build environment available at the command line. - For example, on Debian/Ubuntu you will want to have the `make` and `build-essential` packages installed. - On macOS, you will want to run `xcode-select --install` to get the XCode command line build tooling in place. -- An account with elevated rights to install the dependencies -- `curl` or `wget` installed -- Node.js [Active LTS Release](../overview/versioning-policy.md#nodejs-releases) installed using one of these - methods: - - Using `nvm` (recommended) - - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) - - [Install and change Node version with nvm](https://nodejs.org/en/download/package-manager/#nvm) - - Node 20 is a good starting point, this can be installed using `nvm install lts/iron` - - [Binary Download](https://nodejs.org/en/download/) - - [Package manager](https://nodejs.org/en/download/package-manager/) - - [Using NodeSource packages](https://github.com/nodesource/distributions/blob/master/README.md) -- `yarn` [Installation](https://yarnpkg.com/getting-started/install) - - Backstage currently uses Yarn 4.4.1, once you've ran `corepack enable` you'll want to then run `yarn set version 4.4.1` -- `docker` [installation](https://docs.docker.com/engine/install/) -- `git` [installation](https://github.com/git-guides/install-git) -- If the system is not directly accessible over your network the following ports - need to be opened: 3000, 7007. This is quite uncommon, unless you're installing in a container, VM or remote system. - -## 1. Create your Backstage App - -:::caution - -The Backstage app we'll be creating will only have demo data until we set up integrations with your specific data sources! - -::: - -To install the Backstage Standalone app, we will make use of `npx`. `npx` is a tool that comes preinstalled with Node.js and lets you run commands straight from `npm` or other registries. Before we run the command, let's discuss what it does. - -This command will create a new directory with a Backstage app inside. The wizard will ask you for the name of the app. This name will be created as subdirectory in your current working directory. - -![create app](../assets/getting-started/create-app-output.png) +This command creates a new directory with a Backstage app inside. The wizard will ask you for the name of the app. This name will be created as a subdirectory in your current working directory. Inside that directory, it will generate all the files and folder structure needed for you to run your app. @@ -100,65 +63,122 @@ app and [TechDocs](https://backstage.io/docs/features/techdocs/) amongst other things. -Now, that we know what it does, let's run it! +## Prerequisites -```bash -npx @backstage/create-app@latest -``` +This guide also assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`. + +- A minimum of 20 GB disk space to run the standalone Backstage application with demo data. NOTE: As you add more modules and plugins to an installation, the disk space requirements will increase, accordingly. +- A minimum of 6 GB memory. +- Access to a Unix-based operating system, such as Linux, macOS or + [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/). The Linux version must support the required Node.js version. +- A GNU-like build environment available at the command line. + For example, on Debian/Ubuntu you will want to have the `make` and `build-essential` packages installed. + On macOS, you will want to run `xcode-select --install` to get the XCode command line build tooling in place. +- An account with elevated rights to install the dependencies +- `curl` or `wget` installed +- Node.js [Active LTS Release](../overview/versioning-policy.md#nodejs-releases) installed using one of these + methods: + - Using `nvm` (recommended) + - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) + - [Install and change Node version with nvm](https://nodejs.org/en/download/package-manager/#nvm) + - Node 20 is a good starting point, this can be installed using `nvm install lts/iron` + - [Binary Download](https://nodejs.org/en/download/) + - [Package manager](https://nodejs.org/en/download/package-manager/) + - [Using NodeSource packages](https://github.com/nodesource/distributions/blob/master/README.md) +- Install the `isolated-vm` module, following their [requirements section](https://github.com/laverdet/isolated-vm#requirements). +- `yarn` [Installation](https://yarnpkg.com/getting-started/install) + - Backstage currently uses Yarn 4.4.1, once you've ran `corepack enable` you'll want to then run `yarn set version 4.4.1` +- `docker` [installation](https://docs.docker.com/engine/install/) +- `git` [installation](https://github.com/git-guides/install-git) +- If the system is not directly accessible over your network the following ports + need to be opened: 3000, 7007. This is quite uncommon, unless you're installing in a container, VM or remote system. + +## Creating and running a Backstage application This may take a few minutes to fully install everything. Don't stress if the loading seems to be spinning nonstop, there's a lot going on in the background. -:::note +To create the application: -If this fails on the `yarn install` step, it's likely that you will need to install some additional dependencies which are used to configure `isolated-vm`. You can find out more in their [requirements section](https://github.com/laverdet/isolated-vm#requirements), and then run `yarn install` manually again after you've completed those steps. +1. Type the following command to install the Backstage application. -::: +```bash + npx @backstage/create-app@latest +``` -## 2. Run the Backstage app +2. If this is the first time that you are installing a Backstage application on this device, the following question is displayed. Enter `y` and select `Enter` to proceed with the installation. + +``` + Need to install the following packages: + @backstage/create-app@0.7.4 + ok to proceed? (y) +``` + +3. Enter the name for your application and select `Enter`. This is the root directory of your application. In this example, the name is set to `my-backstage-app`. + + ![create app](../assets/getting-started/create-app-output.png) Your Backstage app is fully installed and ready to be run! Now that the installation is complete, you can go to the application directory and start the app using the `yarn start` command. The `yarn start` command will run both the frontend and backend as separate processes (named `[0]` and `[1]`) in the same window. -```bash -cd my-backstage-app # your app name -yarn start +To run the application: + +1. Change to the root directory of your Backstage app. This is the same as the name of your application that you provided during the installation. In this example, it is `my-backstage-app`. + + ```bash + cd my-backstage-app + ``` + +2. Start the Backstage application. + + ```bash + yarn start + ``` + +As the frontend and backend are starting, you will see output similar to the following. The output shows that the app and backend are starting up with the configuration coming from `app-config.yaml`. You will see the plugins being initialized, and authorization and permissions being setup. In addition you will see a series of REST API calls for those plugins that use a service backend, such as the service catalog. + +``` +Starting app, backend +Loaded config from app-config.yaml +. +. +2025-10-15T12:26:41.564Z backstage info Plugin initialization started: 'app', 'proxy', 'scaffolder', 'techdocs', 'auth', 'catalog', 'permission', 'search', 'kubernetes', 'notifications', 'signals' type="initialization" +Rspack compiled successfully +. +. +2025-10-15T15:17:21.130Z auth info Created new signing key eec1a9e4-4395-4698-9a9f-f1b5cbcf152b component="token-factory" +2025-10-15T15:17:21.139Z auth info Issuing token for user:development/guest, with entities user:development/guest component="token-factory" +2025-10-15T15:17:21.223Z rootHttpRouter info [2025-10-15T15:17:21.223Z] "GET /api/auth/guest/refresh HTTP/1.1" 200 802 "http://localhost:3000/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0" type="incomingRequest" date="2025-10-15T15:17:21.223Z" method="GET" url="/api/auth/guest/refresh" status=200 httpVersion="1.1" userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0" contentLength=802 referrer="http://localhost:3000/" +. +. +2025-10-15T15:17:24.051Z rootHttpRouter info [2025-10-15T15:17:24.051Z] "GET /api/catalog/entities?fields=metadata,kind,spec.profile&filter=kind%3Dgroup%2Crelations.hasMember%3Duser%3Adevelopment%2Fguest HTTP/1.1" 304 0 "http://localhost:3000/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0" type="incomingRequest" date="2025-10-15T15:17:24.051Z" method="GET" url="/api/catalog/entities?fields=metadata,kind,spec.profile&filter=kind%3Dgroup%2Crelations.hasMember%3Duser%3Adevelopment%2Fguest" status=304 httpVersion="1.1" userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:143.0) Gecko/20100101 Firefox/143.0" referrer="http://localhost:3000/" +. +. ``` -![Screenshot of the command output, with the message web pack compiled successfully](../assets/getting-started/startup.png) +Once the Backstage UI is displayed, you can start exploring the demo immediately. -Here again, there's a small wait for the frontend to start up. Once the frontend is built, your browser window should automatically open. +:::tip Browser window didn't open with yarn start -:::tip Browser window didn't open - -When you see the message `[0] webpack compiled successfully`, you can navigate directly to `http://localhost:3000` to see your Backstage app. +When you see the message `Rspack compiled successfully`, you can navigate directly to `http://localhost:3000` to see your Backstage app. ::: -You can start exploring the demo immediately. - ![Screenshot of the Backstage portal.](../assets/getting-started/portal.png) -## Recap - -This tutorial walked through how to deploy Backstage using the `npx @backstage/create-app@latest` command. That command created a new directory that holds your new Backstage app. That app is currently only configured for development purposes, as it is using an in-memory database and contains demo data. - ## Next steps Choose the correct next steps for your user role, if you're likely to be deploying and managing a Backstage instance for your organization, look through the [Admin](#admin) section. If you're likely to be developing on/for Backstage, take a look through the [Developer](#developer) section. ### Admin -- Deploying to production - +- Configuring Backstage - [Setting up authentication](./config/authentication.md) - [Configuring a database](./config/database.md) - - [Deploying with Docker](../deployment/docker.md) - - [Deploying with Kubernetes](../deployment/k8s.md) - -- Configuring Backstage - - [Adding plugins](./configure-app-with-plugins.md) - [Customizing Your App's UI](../conf/user-interface/index.md) - [Populating the homepage](./homepage.md) +- Deploying to production + - [Deploying with Docker](../deployment/docker.md) + - [Deploying with Kubernetes](../deployment/k8s.md) ### Developer @@ -171,8 +191,4 @@ Share your experiences, comments, or suggestions with us: [on discord](https://discord.gg/backstage-687207715902193673), file issues for any [feature](https://github.com/backstage/backstage/issues/new?labels=help+wanted&template=feature_template.md) or -[plugin suggestions](https://github.com/backstage/community-plugins/issues/new/choose), -or -[bugs](https://github.com/backstage/backstage/issues/new?labels=bug&template=bug_template.md) -you have, and feel free to -[contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)! +[plugin suggestions](https://github.com/backstage/community-plugins/issues/new/choose) diff --git a/docs/integrations/bitbucketCloud/locations.md b/docs/integrations/bitbucketCloud/locations.md index 6b735171a4..807076c9e9 100644 --- a/docs/integrations/bitbucketCloud/locations.md +++ b/docs/integrations/bitbucketCloud/locations.md @@ -32,6 +32,15 @@ integrations: appPassword: my-password ``` +OAuth 2.0 client credentials flow: + +```yaml +integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret +``` + :::note Note A public Bitbucket Cloud provider is added automatically at startup for @@ -41,7 +50,7 @@ convenience, so you only need to list it if you want to supply credentials. :::note Note -The credential required for this type is either an [Api token](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/) or an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/). An Atlassian Account API key will not work. +The credential required for this type is either an [Api token](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/), an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) or an [OAuth 2.0 client credentials](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/). An Atlassian Account API key will not work. ::: @@ -55,3 +64,5 @@ This one entry will have the following elements: neither a username nor token are supplied, anonymous access will be used. - `token`: The token used to authenticate requests. - `appPassword`: The app password for the Bitbucket Cloud user. +- `clientId`: The OAuth client ID for Bitbucket Cloud (used with `clientSecret` for OAuth 2.0 client credentials flow). +- `clientSecret`: The OAuth client secret for Bitbucket Cloud (used with `clientId` for OAuth 2.0 client credentials flow). diff --git a/docs/notifications/processors.md b/docs/notifications/processors.md index 7ae98a528c..af0b9f8f93 100644 --- a/docs/notifications/processors.md +++ b/docs/notifications/processors.md @@ -156,6 +156,56 @@ notifications: Multiple instances can be added in the `slack` array, allowing you to have multiple configurations if you need to send messages to more than one Slack workspace. Org-Wide App installation is not currently supported. +### Broadcast Channel Routing + +For more granular control over where broadcast notifications are sent, you can use `broadcastRoutes` to route notifications to different Slack channels based on their origin and/or topic. This is useful when you want different types of notifications to go to different channels. + +```yaml +notifications: + processors: + slack: + - token: xoxb-XXXXXXXXX + # Legacy option - used as fallback when no routes match + broadcastChannels: + - general-notifications + # Route broadcasts based on origin and/or topic + broadcastRoutes: + # Most specific: matches both origin AND topic + - origin: plugin:catalog + topic: alerts + channel: catalog-alerts + # Origin only: all notifications from this origin + - origin: plugin:catalog + channel: catalog-updates + # Topic only: all notifications with this topic (any origin) + - topic: security + channel: security-team + # Multiple channels: send to several channels at once + - origin: external:monitoring + channel: + - ops-team + - on-call-alerts +``` + +#### Route Matching Precedence + +Routes are evaluated in the following order of priority: + +1. **Origin + Topic match** (most specific) - A route that specifies both `origin` and `topic` will match first +2. **Origin-only match** - A route with only `origin` specified (no `topic`) +3. **Topic-only match** - A route with only `topic` specified (no `origin`) +4. **Default fallback** - If no routes match, falls back to `broadcastChannels` + +The first matching route wins. If no routes match and no `broadcastChannels` are configured, the broadcast notification will not be sent to Slack. + +#### Configuration Options + +| Property | Type | Description | +| --------- | ---------------------- | ------------------------------------------------------------------------------------------ | +| `origin` | `string` | Optional. The notification origin to match (e.g., `plugin:catalog`, `external:my-service`) | +| `topic` | `string` | Optional. The notification topic to match (e.g., `alerts`, `updates`, `security`) | +| `channel` | `string` or `string[]` | Required. The Slack channel(s) to send to. Can be channel IDs, channel names, or user IDs | + ### Entity Requirements Entities must be annotated with the following annotation: diff --git a/docs/plugins/integrating-plugin-into-software-catalog.md b/docs/plugins/integrating-plugin-into-software-catalog.md index ed2e25c601..3542e073cb 100644 --- a/docs/plugins/integrating-plugin-into-software-catalog.md +++ b/docs/plugins/integrating-plugin-into-software-catalog.md @@ -32,7 +32,7 @@ Creating the plugin... ### Reading entities from within your plugin You can access the currently selected entity using the backstage api -[`useEntity`](../reference/plugin-catalog-react.useentity.md). For example, +[`useEntity`](https://backstage.io/api/stable/functions/_backstage_plugin-catalog-react.index.useEntity.html). For example, ```tsx import { useEntity } from '@backstage/plugin-catalog-react'; diff --git a/docs/plugins/structure-of-a-plugin.md b/docs/plugins/structure-of-a-plugin.md index 8412ead179..7cfaca4561 100644 --- a/docs/plugins/structure-of-a-plugin.md +++ b/docs/plugins/structure-of-a-plugin.md @@ -82,7 +82,7 @@ export const ExamplePage = examplePlugin.provide( This is where the plugin is created and where it creates and exports extensions that can be imported and used in the app. See reference docs for -[`createPlugin`](../reference/core-plugin-api.createplugin.md) or introduction to +[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) or introduction to the new [Composability System](./composability.md). ## Components diff --git a/docs/releases/v1.46.0-changelog.md b/docs/releases/v1.46.0-changelog.md new file mode 100644 index 0000000000..22e6e39dab --- /dev/null +++ b/docs/releases/v1.46.0-changelog.md @@ -0,0 +1,2369 @@ +# Release v1.46.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.46.0](https://backstage.github.io/upgrade-helper/?to=1.46.0) + +## @backstage/plugin-techdocs-addons-test-utils@2.0.0 + +### Major Changes + +- 8d6709e: **BREAKING**: `TechDocsAddonTester.renderWithEffects()` no longer returns a screen; this means that you can no longer grab assertions such as `getByText` from its return value. + + Newer versions of `@testing-library` recommends using the `screen` export for assertions - and removing this from the addon tester contract allows us to more freely iterate on which underlying version of the testing library is being used. + + One notable effect of this, however, is that the `@testing-library` `screen` does NOT support assertions on the shadow DOM, which techdocs relies on. You will therefore want to add a dependency on [the `shadow-dom-testing-library` package](https://github.com/konnorrogers/shadow-dom-testing-library/) in your tests, and using its `screen` and its dedicated `*Shadow*` methods. As an example, if you keep doing `getByText` you will not get matches inside the shadow DOM - switch to `getByShadowText` instead. + + ```ts + import { screen } from 'shadow-dom-testing-library'; + + // ... render the addon ... + await TechDocsAddonTester.buildAddonsInTechDocs([]) + .withDom(TEST_CONTENT) + .renderWithEffects(); + + expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument(); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/test-utils@1.7.14 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + +## @backstage/backend-app-api@1.4.0 + +### Minor Changes + +- 5a2d538: Introduced backend startup result tracking and error handling. The `Backend.start()` method now returns a `BackendStartupResult` with detailed success/failure status and timing information for all plugins and modules. When startup fails, a `BackendStartupError` is thrown that includes the complete startup results, making it easier to diagnose which plugins or modules failed. + + This also improves the default error message when backend startup fails, and of course makes it possible to craft your own custom error reporting based on the startup results. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/backend-defaults@0.14.0 + +### Minor Changes + +- fa43826: Move `better-sqlite3` from dependencies to peer dependencies +- 2bc4e02: **BREAKING** The correct configuration options for Valkey are now being used. + + These changes are **required** to `app-config.yaml`: + + ```diff + backend: + cache: + store: valkey + connection: ... + client: + - namespace: 'my-app' + - keyPrefixSeparator: ':' + + keyPrefix: 'my-app:' + - clearBatchSize: 1000 + - useUnlink: false + ``` + + In comparison to Redis, Valkey requires the full `keyPrefix` including the separator to be specified instead of separate `namespace` and `keyPrefixSeparator` options. Also, Valkey does not support the `clearBatchSize` and `useUnlink` options. + +### Patch Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 + +- aa79251: build(deps): bump `node-forge` from 1.3.1 to 1.3.2 + +- f96edff: Allow configuration of the `referrerPolicy` + +- fb029b6: Updated luxon types + +- d9759a1: **BREAKING ALPHA**: The old `instanceMetadataService` has been removed from alpha. Please switch over to using the stable `coreServices.rootInstanceMetadata` and related types instead, available from `@backstage/backend-plugin-api`. + +- 847a330: Fix for `jose` types + +- 25b560e: Internal change to support new versions of the `logform` library + +- 2a0c4b0: Adds a new experimental `RootSystemMetadataService` for tracking the collection of Backstage instances that may be deployed at any one time. It currently offers a single API, `getInstalledPlugins` that returns a list of installed plugins based on config you have set up in `discovery.endpoints` as well as the plugins installed on the instance you're calling the API with. It does not handle wildcard values or fallback values. The intention is for this plugin to provide plugin authors with a simple interface to fetch a trustworthy list of all installed plugins. + +- 3016a79: Updated dependency `@types/archiver` to `^7.0.0`. + +- 42db6a6: Don't warn when parsing `storeOptions` for `memory` cache + +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/integration@1.19.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + - @backstage/backend-dev-utils@0.1.6 + +## @backstage/backend-plugin-api@1.6.0 + +### Minor Changes + +- 2a0c4b0: Adds a new experimental `RootSystemMetadataService` for tracking the collection of Backstage instances that may be deployed at any one time. It currently offers a single API, `getInstalledPlugins` that returns a list of installed plugins based on config you have set up in `discovery.endpoints` as well as the plugins installed on the instance you're calling the API with. It does not handle wildcard values or fallback values. The intention is for this plugin to provide plugin authors with a simple interface to fetch a trustworthy list of all installed plugins. + +### Patch Changes + +- d9759a1: **BREAKING ALPHA**: The old `instanceMetadataService` has been removed from alpha. Please switch over to using the stable `coreServices.rootInstanceMetadata` and related types instead, available from `@backstage/backend-plugin-api`. +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/cli-common@0.1.16 + +## @backstage/cli@0.35.0 + +### Minor Changes + +- f6f22a9: Provide `--no-node-snapshot` by default when running the `package start` or `package test`. You can disable this behavior by providing `NODE_OPTIONS='--node-snapshot'`. + +- f8dff94: Switched the default module resolution to `bundler` and the `module` setting to `ES2020`. + + You may need to bump some dependencies as part of this change and fix imports in code. The most common source of this is that type checking will now consider the `exports` field in `package.json` when resolving imports. This in turn can break older versions of packages that had incompatible `exports` fields. Generally these issues will have already been fixed in the upstream packages. + + You might be tempted to use `--skipLibCheck` to hide issues due to this change, but it will weaken the type safety of your project. If you run into a large number of issues and want to keep the old behavior, you can reset the `moduleResolution` and `module` settings your own `tsconfig.json` file to `node` and `ESNext` respectively. But keep in mind that the `node` option will be removed in future versions of TypeScript. + + A future version of Backstage will make these new settings mandatory, as we move to rely on the `exports` field for type resolution in packages, rather than the `typesVersions` field. + +- cd0b8a1: **BREAKING**: `jest` is now a peer dependency. If you run tests using Backstage CLI, you must add Jest and its environment dependencies as `devDependencies` in your project. + + You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed. + + - **Jest 29**: Install `jest@^29` and `jest-environment-jsdom@^29`. No migration needed, but you may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations. + - **Jest 30**: Install `jest@^30`, `@jest/environment-jsdom-abstract@^30`, and `jsdom@^27`. Fixes the stylesheet parsing warnings/errors, but requires migration steps. + + See the [Jest 30 migration guide](https://backstage.io/docs/tutorials/jest30-migration) for detailed migration instructions. + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 + +- e7db290: Add missing peer/dev dependencies to the frontend plugin template. + + `react-dom` was not declared as a peer dependency, causing module resolution + errors when generating plugins outside a Backstage monorepo. This adds + `react-dom` to `peerDependencies` (for consuming apps) and `devDependencies` + (for local development). `react-router-dom` is also added to `peerDependencies` (for consuming apps) and `devDependencies` + to support routing during plugin development. + + Fixes: + + - Module not found: Can't resolve 'react-dom' + - Module not found: Can't resolve 'react-router-dom' + +- 1226647: Updated dependency `esbuild` to `^0.27.0`. + +- f89a074: Updated dependency `@pmmmwh/react-refresh-webpack-plugin` to `^0.6.0`. + +- 2b81751: Updated dependency `webpack` to `~5.103.0`. + +- fafd9e1: Fixed internal usage of `yargs`. + +- c8c2329: Add proxy configuration from env-vars to create-app tasks + +- 2bae83a: Switched compilation target to ES2022 in order to match the new set of supported Node.js versions, which are 22 and 24. + + The TypeScript compilation target has been set to ES2022, because setting it to a higher target will break projects on older TypeScript versions. If you use a newer TypeScript version in your own project, you can bump `compilerOptions.target` to ES2023 or ES2024 in your own `tsconfig.json` file. + +- 7fbac5c: Updated to use new utilities from `@backstage/cli-common`. + +- 2bae83a: Bumped dev dependencies `@types/node` + +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/integration@1.19.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + +## @backstage/integration@1.19.0 + +### Minor Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +### Patch Changes + +- a26a322: Added support for using a GitHub App installation to generate tokens for public repository access when the `publicAccess` option is enabled. When all other authentication methods fail (e.g., the app is not installed in that organization), the provider will now use an available installation to generate a token that can be used to access public repositories as read only. +- fb029b6: Updated luxon types +- e15fdae: Made the github urls case insensitive. + +## @backstage/ui@0.10.0 + +### Minor Changes + +- 16543fa: **Breaking change** The `Cell` component has been refactored to be a generic wrapper component that accepts `children` for custom cell content. The text-specific functionality (previously part of `Cell`) has been moved to a new `CellText` component. + + ### Migration Guide + + If you were using `Cell` with text-specific props (`title`, `description`, `leadingIcon`, `href`), you need to update your code to use `CellText` instead: + + **Before:** + + ```tsx + } + href="/path" + /> + ``` + + **After:** + + ```tsx + } + href="/path" + /> + ``` + + For custom cell content, use the new generic `Cell` component: + + ```tsx + {/* Your custom content */} + ``` + +### Patch Changes + +- 50b7927: Fixed Checkbox indicator showing checkmark color when unchecked. + + Affected components: Checkbox + +- 5bacf55: Fixed `ButtonIcon` incorrectly applying `className` to inner elements instead of only the root element. + + Affected components: ButtonIcon + +- b3ad928: Fixed Table Row component to correctly handle cases where no `href` is provided, preventing unnecessary router provider wrapping and fixing the cursor incorrectly showing as a pointer despite the element not being a link. + + Affected components: Row + +- a20d317: Added row selection support with visual state styling for hover, selected, and pressed states. Fixed checkbox rendering to only show for multi-select toggle mode. + + Affected components: Table, TableHeader, Row, Column + +- fe7c751: Fixed `useTable` hook to prioritize `providedRowCount` over data length for accurate row count in server-side pagination scenarios. + +- c145031: Fixed Table column sorting indicator to show up arrow when no sort is active, correctly indicating that clicking will sort ascending. + + Affected components: Column + +## @backstage/plugin-auth-backend-module-github-provider@0.4.0 + +### Minor Changes + +- b3286d5: Added the `github.com/user-id` annotation to store GitHub's user ID (immutable) in user entities. Also includes addition of the `userIdMatchingUserEntityAnnotation` sign-in resolver that matches users by the new ID. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-catalog-backend@3.3.0 + +### Minor Changes + +- dce1824: Added `ActionsRegistry` actions for `register-entity` and `unregister-entity` + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 8101ec1: Fixed default refresh service to go through the whole ancestry of the entity. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-github@0.12.0 + +### Minor Changes + +- b3286d5: Added the `github.com/user-id` annotation to store GitHub's user ID (immutable) in user entities. Also includes addition of the `userIdMatchingUserEntityAnnotation` sign-in resolver that matches users by the new ID. + +### Patch Changes + +- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances. + + When it’s set to true, suspended users won’t be returned when querying the organization users for GitHub Enterprise instances. + Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail. + +- a413977: Added configurable `pageSizes` option to `GithubOrgEntityProvider` for GitHub GraphQL API queries to prevent `RESOURCE_LIMITS_EXCEEDED` errors with organizations with large number of teams and members. This aligns the configuration options with `GithubMultiOrgEntityProvider`. + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-events-backend-module-kafka@0.2.0 + +### Minor Changes + +- 2c74ea9: Added support for multiple named instances in `kafkaConsumingEventPublisher` configuration. The previous single configuration format is still supported for backward compatibility. +- 2c74ea9: Added `KafkaPublishingEventConsumer` to support sending Backstage events to Kafka topics. + + This addition enables Backstage to publish events to external Kafka systems, complementing the existing ability to receive events from Kafka. This allows for better integration with external systems that rely on Kafka for event streaming. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-kubernetes-backend@0.21.0 + +### Minor Changes + +- 7f9846f: Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- fb029b6: Updated luxon types +- e9589d9: Replace `@aws-sdk/signature-v4` with `@smithy/signature-v4`, + as stated in the [package documentation](https://www.npmjs.com/package/@aws-sdk/signature-v4?activeTab=readme) +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas +- Updated dependencies + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-node@0.4.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-kubernetes-node@0.4.0 + +### Minor Changes + +- 7f9846f: Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + +## @backstage/plugin-notifications-backend-module-slack@0.3.0 + +### Minor Changes + +- f95a516: Enables optional routes to Slack channels for broadcast notifications based on origin and/or topics. + +### Patch Changes + +- b80857a: Slack notification handler throttling can now be configured with the `concurrencyLimit` and `throttleInterval` options. +- f8230e4: Updated dependency `@faker-js/faker` to `^10.0.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + +## @backstage/plugin-scaffolder@1.35.0 + +### Minor Changes + +- dab3d3f: Added field extension `RepoOwnerPicker` for retrieving GitHub repository owners. + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-techdocs-react@1.3.6 + +## @backstage/plugin-scaffolder-backend@3.1.0 + +### Minor Changes + +- a4cd405: Add `defaultEnvironment` config to scaffolder to enable more flexible and custom templates. Now it's possible enable access to default parameters and secrets in templates, improving security and reducing complexity. + +### Patch Changes + +- be5972b: Fixed a bug where config was not passed to NunjucksWorkflowRunner, causing defaultEnvironment to be undefined +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 2bae83a: Updated `isolated-vm` to `6.0.1` +- 25b560e: Internal change to support new versions of the `logform` library +- 8f4aded: Fixing OpenAPI definition +- 1226647: Updated dependency `esbuild` to `^0.27.0`. +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.0 + - @backstage/integration@1.19.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.16 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + +### Minor Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.11.0 + +### Minor Changes + +- f2d034b: In the `gitlabRepoPush` action, add 'auto' possibility for `commitAction` input. + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-search-backend-node@1.4.0 + +### Minor Changes + +- 4d3ddb9: Improving method that search tokenizer breaks apart entity names + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/app-defaults@1.7.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/backend-dev-utils@0.1.6 + +### Patch Changes + +- 2bae83a: Internal update for Node.js v24 support. + +## @backstage/backend-dynamic-feature-service@0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-app-node@0.1.40 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-backend@0.5.9 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/backend-openapi-utils@0.6.4 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/backend-test-utils@1.10.2 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 8be23a4: Switched `textextensions` dependency for `text-extensions`. +- 5a737e1: Fix PostgreSQL 18 `TestDatabases` by pinning the data directory +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/cli-common@0.1.16 + +### Patch Changes + +- 5cfb2a4: Added new `run`, `runOutput`, and `runCheck` utilities to help run child processes in a safe and portable way. +- c8c2329: Add proxy configuration from env-vars to create-app tasks +- 2bae83a: Bumped dev dependencies `@types/node` + +## @backstage/cli-node@0.2.16 + +### Patch Changes + +- 4e8c726: Updated to use new utilities from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @backstage/codemods@0.1.53 + +### Patch Changes + +- 688f070: Updated to use new utilities from `@backstage/cli-common`. +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @backstage/config-loader@1.10.7 + +### Patch Changes + +- 741c47a: Updated dependency `typescript-json-schema` to `^0.67.0`. +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @backstage/core-app-api@1.19.3 + +### Patch Changes + +- 75683ed: Added replay functionality to `AlertApiForwarder` to buffer and replay recent alerts to new subscribers, preventing missed alerts that were posted before subscription. +- 97cd16f: Internal update of translation imports. +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + +## @backstage/core-compat-api@0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/core-components@0.18.4 + +### Patch Changes + +- 9a942a4: Fixed bug in the `LogViewer` component where shift + click always opened a new window instead of just changing the selection. + + In addition, improved the `LogViewer` component by a few usability enhancements: + + - Added support for multiple selections using cmd/ctrl + click + - Improved the generated hash that is added to the URL to also support ranges & multiple selections + - Added an hover effect & info tooltip to the "Copy to clipboard" button to indicate its functionality + - Added some color and a separator to the line numbers to improve readability + +- 207c3c8: long words like urls now breaks to new line on warning panels instead of overflowing the container + +- 4c00303: Add `tooltipClasses` prop to `OverflowTooltip` component to allow customisation of the tooltip + +- 5d52dab: Add i18n support for LogViewer search control + +- f6b49ce: added support for wrapLongLines option in CodeSnippet + +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + +## @backstage/core-plugin-api@1.12.1 + +### Patch Changes + +- 358c6f7: The `useApp` and `useRouteRef` functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs. +- 97cd16f: Reversed the relationship between the old `@backstage/core-plugin-api` and the new `@backstage/frontend-plugin-api`. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/create-app@0.7.7 + +### Patch Changes + +- 336db00: Bumped create-app version. +- 2bae83a: Updated engines to support Node 22 or 24 +- c8c2329: Add proxy configuration from env-vars to create-app tasks +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @backstage/dev-utils@1.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/ui@0.10.0 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/app-defaults@1.7.3 + - @backstage/integration-react@1.2.13 + +## @backstage/frontend-app-api@0.13.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-defaults@0.3.4 + +## @backstage/frontend-defaults@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/frontend-app-api@0.13.3 + +## @backstage/frontend-dynamic-feature-loader@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/frontend-plugin-api@0.13.2 + +### Patch Changes + +- 75683ed: Added a new `errorPresentation` prop to `ExtensionBoundary` to control how errors are presented to the user. The default is `'error-display'`, which is the current behavior of showing the error in the `ErrorDisplay` component. The new option is `'error-api'`, posts errors to the `ErrorApi` and does not allow retries. + + The `AppRootElementBlueprint` now wraps its element in an `ErrorBoundary` using the new `'error-api'` presentation mode. + +- 0bc1ce9: Fixed a versioning conflict that could result in a `.withContext` is not a function error. + +- f3f84f1: Made the return type of `.withOverrides` to be simplified. + +- 97cd16f: Reversed the relationship between the old `@backstage/core-plugin-api` and the new `@backstage/frontend-plugin-api`. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old. + +- 9b8bde4: Removed unnecessary dependencies on `@backstage/core-components`, `@backstage/config`, `@material-ui/core`, and `lodash`. + +## @backstage/frontend-test-utils@0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/test-utils@1.7.14 + - @backstage/frontend-app-api@0.13.3 + +## @backstage/integration-react@1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/repo-tools@0.16.1 + +### Patch Changes + +- 688f070: Updated to use new utilities from `@backstage/cli-common`. + +- 85895f9: Updates OpenAPI generator templates to preserve original property names (like 'group-name', 'user-id') from OpenAPI specs when propertyNaming=original is specified. Previously, these were always converted to camelCase regardless of the propertyNaming setting. + + - Updates modelGeneric.mustache templates in both client and server generators + - Updates modelTaggedUnion.mustache templates in both client and server generators + - Uses {{baseName}} when available, falls back to {{name}} for backward compatibility + - Maintains backward compatibility - no changes when propertyNaming=original is not used + +- 2bae83a: Bump `@microsoft/api-documenter` and `@microsoft/api-extractor` to latest versions. + +- d1e38a7: Properly create workspace in OS temporary directory for `generate-patch` command + +- 2bae83a: Bumped dev dependencies `@types/node` + +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + +## @techdocs/cli@1.10.3 + +### Patch Changes + +- 43629b1: Updated to use new utilities from `@backstage/cli-common`. +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-techdocs-node@1.13.10 + - @backstage/cli-common@0.1.16 + +## @backstage/test-utils@1.7.14 + +### Patch Changes + +- 97cd16f: Internal update of translation imports. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/theme@0.7.1 + +### Patch Changes + +- fa06f6b: Added a `themeName` prop to `UnifiedThemeProvider`, enabling Backstage UI `data-theme-name` CSS attribute to be set based on active theme. + +## @backstage/plugin-api-docs@0.13.2 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/plugin-catalog@1.32.1 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-app@0.3.3 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- f7bc228: Support to set `defaultLanguage` and `availableLanguages` for the app language API in the new frontend system +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-app-backend@0.5.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-app-node@0.1.40 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + +## @backstage/plugin-app-node@0.1.40 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + +## @backstage/plugin-app-visualizer@0.1.26 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/ui@0.10.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-auth@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/theme@0.7.1 + +## @backstage/plugin-auth-backend@0.25.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.2.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.15 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.3.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.15 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.4.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.2.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-openshift-provider@0.1.3 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.5.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-node@0.6.10 + +### Patch Changes + +- 2389358: remove leading dot in auth cookie cleanup call +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- b35f8b2: Fixed chunked cookie replacing edge case in OAuthCookieManager class where some of the old chunks would not get removed if new chunked cookie would have fewer chunks. +- e9dd634: fix flawed cookie removal logic with chunked tokens +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-auth-react@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-bitbucket-cloud-common@0.3.5 + +### Patch Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +- Updated dependencies + - @backstage/integration@1.19.0 + +## @backstage/plugin-catalog@1.32.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 91f5ed8: Fixed `catalogAboutEntityCard` to filter icon links before calling useProps(), preventing side effects from hooks in filtered-out links +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/core-compat-api@0.5.5 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-techdocs-react@1.3.6 + +## @backstage/plugin-catalog-backend-module-aws@0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-azure@0.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.5.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.5.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gitea@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.17 + +### Patch Changes + +- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances. + + When it’s set to true, suspended users won’t be returned when querying the organization users for GitHub Enterprise instances. + Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail. + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-catalog-backend-module-github@0.12.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.7.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.6 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- fb029b6: Updated luxon types +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-ldap@0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-logs@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.8.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-common@1.7.4 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.6.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.12 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-graph@0.5.4 + +### Patch Changes + +- a67c144: Fixed zoom out description (replace `&` with &) +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-catalog-import@0.13.8 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-catalog-node@1.20.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-catalog-react@1.21.4 + +### Patch Changes + +- 6d39141: Fixed an issue where `EntityOwnerPicker` failed to filter options when the input text contained uppercase characters. +- b3c0594: Use a versioned context for `useEntityList`, to better work with mixed `@backstage/plugin-catalog-react` versions. +- c51c901: $contains may have string value in an entity filter. Typescript type and Zod parser were not the same. +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/core-compat-api@0.5.5 + - @backstage/frontend-test-utils@0.4.2 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.24 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. + +- df4d646: Moved types, API and client to the common package, allowing both frontend and + backend plugins to use the `CatalogUnprocessedEntitiesClient`. + + The following types, clients and interfaces have been deprecated and should be + imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead: + `CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`, + `UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`. + + All those types, clients and interfaces are re-exported temporarily in the + `@backstage/plugin-catalog-unprocessed-entities` package until cleaned up. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.12 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.12 + +### Patch Changes + +- df4d646: Moved types, API and client to the common package, allowing both frontend and + backend plugins to use the `CatalogUnprocessedEntitiesClient`. + + The following types, clients and interfaces have been deprecated and should be + imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead: + `CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`, + `UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`. + + All those types, clients and interfaces are re-exported temporarily in the + `@backstage/plugin-catalog-unprocessed-entities` package until cleaned up. + +## @backstage/plugin-config-schema@0.1.75 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-devtools@0.1.34 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-devtools-common@0.1.20 + - @backstage/core-compat-api@0.5.5 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-devtools-backend@0.5.12 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + - @backstage/plugin-devtools-common@0.1.20 + +## @backstage/plugin-devtools-common@0.1.20 + +### Patch Changes + +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin + +## @backstage/plugin-events-backend@0.5.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-azure@0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-bitbucket-server@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-github@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-gitlab@0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-module-google-pubsub@0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-events-backend-test-utils@0.1.51 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + +## @backstage/plugin-events-node@0.4.18 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-gateway-backend@1.1.1 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 7e860dd: Updated dependency `eventsource` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-home@0.8.15 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-home-react@0.1.33 + - @backstage/theme@0.7.1 + +## @backstage/plugin-home-react@0.1.33 + +### Patch Changes + +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-kubernetes@0.12.14 + +### Patch Changes + +- f15d5f1: add missing i18n support for kubernetes and kubernetes-react +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-kubernetes-react@0.5.14 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-kubernetes-cluster@0.0.32 + +### Patch Changes + +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.14 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + +## @backstage/plugin-kubernetes-common@0.9.9 + +### Patch Changes + +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas + +## @backstage/plugin-kubernetes-react@0.5.14 + +### Patch Changes + +- f966a85: Enabled a pod terminal at GKE +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas +- f15d5f1: add missing i18n support for kubernetes and kubernetes-react +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-mcp-actions-backend@0.1.6 + +### Patch Changes + +- e83e038: Added `@cfworker/json-schema` as a dependency to this package part of the `@modelcontextprotocol/sdk` bump as it's required in the types +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 79ef471: Clarify error handling in readme and update handleError.ts to include all backstage/errors +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-mui-to-bui@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.10.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + +## @backstage/plugin-notifications@0.5.12 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. + +- 53347cc: Move long notification descriptions behind `Show more/less` button. + + This improves readability of the notifications list by preventing long descriptions from taking up too much space + or rendering very small scrollable areas. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + +## @backstage/plugin-notifications-backend@0.6.1 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + +## @backstage/plugin-notifications-backend-module-email@0.3.17 + +### Patch Changes + +- a5d5b3a: SES config for the notification email processor now supports utilizing an ARN for the SES identity when sending an email after the SES SDK V2 update. + + The `sesConfig.fromArn` will set the `fromEmailAddressIdentityArn` option for the SES `SendEmailCommand`. The `sesConfig.sourceArn` field is removed since no equivalent option is available in the send email command options. Setting `sesConfig.sourceArn` will have no effect and log a warning. Example changes: + + ```diff + notifications: + processors: + email: + transportConfig: + transport: "ses" + region: "us-west-2" + sender: "sender@mycompany.com" + replyTo: "no-reply@mycompany.com" + sesConfig: + - sourceArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" + fromArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" + ``` + +- b267aea: Updated dependency `@types/nodemailer` to `^7.0.0`. + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + +## @backstage/plugin-notifications-node@0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-org@0.6.47 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-org-react@0.1.45 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-permission-backend@0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-permission-node@0.10.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-permission-react@0.4.39 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-proxy-backend@0.6.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-proxy-node@0.1.11 + +## @backstage/plugin-proxy-node@0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + +### Patch Changes + +- 5a6aca2: Improve error message when provided target branch is missing +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-github@0.9.3 + +### Patch Changes + +- dab3d3f: Added autocompletion resource `owners` for retrieving GitHub repository owners. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-notifications-node@0.2.22 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.16 + +### Patch Changes + +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-scaffolder-node-test-utils@0.3.6 + +## @backstage/plugin-scaffolder-common@1.7.4 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + +## @backstage/plugin-scaffolder-node@0.12.2 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-common@1.7.4 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.10.2 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-react@1.19.4 + +### Patch Changes + +- fb029b6: Updated luxon types +- 5ca461e: Fixed bug where custom `review.name` values were incorrectly formatted by `startCase`, preserving them exactly as written. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- 9b38f22: Updated dependency `use-immer` to `^0.11.0`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + +## @backstage/plugin-search@1.5.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-search-backend@2.0.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-search-backend-module-catalog@0.3.11 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-search-backend-module-elasticsearch@1.7.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-search-backend-module-explore@0.3.10 + +### Patch Changes + +- 9b69262: Updated dependency `@backstage-community/plugin-explore-common` to `^0.9.0`. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-search-backend-module-pg@0.5.51 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-search-backend-module-techdocs@0.4.9 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-techdocs-node@1.13.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-search-react@1.10.1 + +### Patch Changes + +- 8947a4e: Skip the very first empty search when going to the landing page +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + +## @backstage/plugin-signals@0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + +## @backstage/plugin-signals-backend@0.3.11 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-signals-node@0.1.27 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-signals-react@0.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-techdocs@1.16.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- 5c33821: Fixed schema type for additionalAllowedURIProtocols +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 592361e: The `techdocs` config is now marked as optional. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-techdocs-react@1.3.6 + +## @backstage/plugin-techdocs-backend@2.1.3 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 2bae83a: Corrected `ErrorCallback` type to work with Node 22 types +- 592361e: The `techdocs` config is now marked as optional. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-techdocs-node@1.13.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + +### Patch Changes + +- 8d6709e: Updated tests to match test-utils change +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + +## @backstage/plugin-techdocs-node@1.13.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 703f8c0: There was an issue in the uploading of large size files to the AWS S3. We have modified the logic by adding retry along with multipart uploading functionality. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + +## @backstage/plugin-techdocs-react@1.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @backstage/plugin-user-settings@0.8.30 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + +## @backstage/plugin-user-settings-backend@0.3.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + +## example-app@0.2.116 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-user-settings@0.8.30 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-devtools@0.1.34 + - @backstage/plugin-home@0.8.15 + - @backstage/theme@0.7.1 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/app-defaults@1.7.3 + - @backstage/frontend-app-api@0.13.3 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-mui-to-bui@0.2.2 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs-react@1.3.6 + +## example-app-next@0.0.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-app@0.3.3 + - @backstage/plugin-org@0.6.47 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-app-visualizer@0.1.26 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-user-settings@0.8.30 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-home@0.8.15 + - @backstage/theme@0.7.1 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/app-defaults@1.7.3 + - @backstage/core-compat-api@0.5.5 + - @backstage/frontend-app-api@0.13.3 + - @backstage/frontend-defaults@0.3.4 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth@0.1.3 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs-react@1.3.6 + +## app-next-example-plugin@0.0.30 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + +## example-backend@0.0.45 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-mcp-actions-backend@0.1.6 + - @backstage/plugin-scaffolder-backend@3.1.0 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-app-backend@0.5.9 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.15 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.3 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-devtools-backend@0.5.12 + - @backstage/plugin-events-backend@0.5.9 + - @backstage/plugin-kubernetes-backend@0.21.0 + - @backstage/plugin-notifications-backend@0.6.1 + - @backstage/plugin-permission-backend@0.7.7 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-proxy-backend@0.6.9 + - @backstage/plugin-search-backend@2.0.9 + - @backstage/plugin-signals-backend@0.3.11 + - @backstage/plugin-techdocs-backend@2.1.3 + - @backstage/plugin-auth-backend-module-github-provider@0.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-search-backend-module-explore@0.3.10 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.9 + - @backstage/plugin-catalog-backend-module-openapi@0.2.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.7 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.7 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.15 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.17 + - @backstage/plugin-search-backend-module-catalog@0.3.11 + - @backstage/plugin-search-backend-module-elasticsearch@1.7.9 + - @backstage/plugin-search-backend-module-techdocs@0.4.9 + +## e2e-test@0.2.35 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.7 + - @backstage/cli-common@0.1.16 + +## @internal/frontend@0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + +## @internal/scaffolder@0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + +## techdocs-cli-embedded-app@0.2.115 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/core-components@0.18.4 + - @backstage/test-utils@1.7.14 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/app-defaults@1.7.3 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + +## yarn-plugin-backstage@0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @internal/plugin-todo-list@1.0.46 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + +## @internal/plugin-todo-list-backend@1.0.46 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 diff --git a/docs/releases/v1.46.0.md b/docs/releases/v1.46.0.md new file mode 100644 index 0000000000..9ee4c68681 --- /dev/null +++ b/docs/releases/v1.46.0.md @@ -0,0 +1,129 @@ +--- +id: v1.46.0 +title: v1.46.0 +description: Backstage Release v1.46.0 +--- + +These are the release notes for the v1.46.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 + +To begin with, this release has a few important framework level updates. + +### **BREAKING:** Updated supported Node.js versions to 22 and 24 + +This release moves up the supported Node.js versions to 22 and 24, according to our [versioning policy](https://backstage.io/docs/overview/versioning-policy#nodejs-releases). As part of this change, we are also setting the compilation targets to ES2023, which lines up with the supported Node.js versions. + +The default TypeScript `target` compiler option is however left at ES2022. This is because older versions of TypeScript will error if they see an unsupported value, even if an override is set in your local `tsconfig.json`. You can still choose to set the TypeScript `target` to either `ES2023` or even `ES2024` in your own `tsconfig.json` if you prefer. + +### **BREAKING:** Switched modules to `ES2020` and resolution mode to `bundler` + +Now that the ecosystem has had some time to mature and adapt, we have finally switched over the default module resolution mode to `bundler` instead of `node`. The `module` setting was also changed to `ES2022`. + +You _may_ need to bump some dependencies as part of this change, or fix imports in code. The most common source of this is that type checking will now consider the `exports` field in `package.json` when resolving imports. This in turn can break older versions of packages that had incompatible `exports` fields. Generally these issues will have already been fixed in the upstream packages, but if you depend on old versions or unmaintained packages, you may still notice some effects of this. + +You might be tempted to use `--skipLibCheck` to hide issues due to this change, but it will weaken the type safety of your project. If you run into a large number of issues and want to keep the old behavior, you can reset the `moduleResolution` and `module` settings of your own `tsconfig.json` file to `node` and `ESNext` respectively. But keep in mind that the `node` option will be removed in future versions of TypeScript. + +A future version of Backstage will make these new settings mandatory, as we move to rely on the `exports` field for type resolution in packages, rather than the `typesVersions` field. + +### **BREAKING:** Moving toward updating `jest` and its DOM + +The `jest` test framework used to be a builtin dependency of the Backstage CLI. In this release, it has been made into a peer dependency to allow for easy upgrades to newer versions as you see fit. + +If you run tests using the Backstage CLI, you must therefore add Jest and its environment dependencies as `devDependencies` in your project root `package.json` when you upgrade. + +You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed. + +- **Jest 29**: Install `jest@^29` and `jest-environment-jsdom@^29` in your root `package.json`. No migration needed, but you may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations. +- **Jest 30**: Install `jest@^30`, `@types/jest@^30`, `@jest/environment-jsdom-abstract@^30`, and `jsdom@^27` in your root `package.json`. Fixes the stylesheet parsing warnings/errors, but requires migration steps. + +See the [Jest 30 migration guide](https://backstage.io/docs/tutorials/jest30-migration) for detailed migration instructions. + +### **BREAKING:** Now using correct configuration options for Valkey + +If you are using Valkey as your backend cache provider, take note. It used to piggyback on the Redis configuration format, but that was not quite correct. So its config options have been updated to better match its capabilities. + +So if you use Valkey, you need to upgrade your `app-config.yaml`: + +```diff +backend: + cache: + store: valkey + connection: ... + client: +- namespace: 'my-app' +- keyPrefixSeparator: ':' ++ keyPrefix: 'my-app:' +- clearBatchSize: 1000 +- useUnlink: false +``` + +Contributed by [@benjidotsh](https://github.com/benjidotsh) in [#31497](https://github.com/backstage/backstage/pull/31497) + +### **BREAKING:** Techdocs addon test utils removed explicit `screen` + +`TechdocsAddonTester.renderWithEffects()` used to return a `screen` that you could use for things like `getByText`. In order to support moving to newer versions of `@testing-library`, we have removed this, and you should import and use the normal `screen` from `@testing-library/react` instead. + +However: that `screen` can’t see inside the shadow DOM, which TechDocs uses. So if your tests need to look inside shadow DOM, you must install `shadow-dom-testing-library` and use its `screen` which provides special shadow-DOM queries, such as `getByShadowText` instead of `getByText. + +Example: + +```tsx +import { screen } from 'shadow-dom-testing-library'; +// ... render the addon ... +await TechDocsAddonTester.buildAddonsInTechDocs([]) + .withDom(TEST_CONTENT) + .renderWithEffects(); +expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument(); +``` + +### **BREAKING:** Backstage-UI advances! + +Again, Backstage-UI has a bunch of updates! One of them is breaking: If you were using the `Cell` component with text-specific props (`title` etc), you should now instead use the `CellText` component for that. Plain `Cell` is now meant to be used with generic child elements instead. + +### Simplified route compatibility + +If you are partway through a migration to the New Frontend System, you may enjoy the fact that the `useApp` and `useRouteRef` hooks now are forwards compatible with NFS. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs. + +### Support for Bitbucket Cloud OAuth + +Support for Bitbucket Cloud OAuth has been added - which was much welcome. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + +As part of this change, some breaking changes were made to low level auth getter functions, such that they now return a promise instead of a plain value. + +Contributed by [@jksmth](https://github.com/jksmth) in [#31848](https://github.com/backstage/backstage/pull/31848) + +### New Catalog actions + +There are two new MCP-usable actions on the block for registering and unregistering entities: `catalog:register-entity` and `catalog:unregister-entity`. + +Contributed by [@gabemontero](https://github.com/gabemontero) in [#32042](https://github.com/backstage/backstage/pull/32042) + +### New `RepoOwnerPicker` for Scaffolder + +A new field extension for selecting an organization or owner for a particular repository has been shipped! Currently, this only supports GitHub autocomplete, but contributions welcome in making this available for other providers! + +Contributed by [@benjidotsh](https://github.com/benjidotsh) in [#32105](https://github.com/backstage/backstage/pull/32105) + +## Security Fixes + +This release does not contain any security fixes. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.46.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.47.0-next.0-changelog.md b/docs/releases/v1.47.0-next.0-changelog.md new file mode 100644 index 0000000000..e1fd3f9ebb --- /dev/null +++ b/docs/releases/v1.47.0-next.0-changelog.md @@ -0,0 +1,578 @@ +# Release v1.47.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.47.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.47.0-next.0) + +## @backstage/ui@0.11.0-next.0 + +### Minor Changes + +- 4ea1d15: **BREAKING**: Renamed CSS variable `--bui-bg` to `--bui-bg-surface-0` for consistency. + +### Patch Changes + +- 1880402: Fixes app background color on dark mode. +- 9c76682: build(deps-dev): bump `storybook` from 10.1.9 to 10.1.10 +- b4a4911: Fixed SearchField `startCollapsed` prop not working correctly in Backstage UI. The field now properly starts in a collapsed state, expands when clicked and focused, and collapses back when unfocused with no input. Also fixed CSS logic to work correctly in all layout contexts (flex row, flex column, and regular containers). + + Affected components: SearchField + +## @backstage/backend-defaults@0.14.1-next.0 + +### Patch Changes + +- 7126bf2: Fixed a spelling mistake in root health service shutdown response. +- Updated dependencies + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-dev-utils@0.1.6 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/integration-aws-node@0.1.19 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + +## @backstage/backend-dynamic-feature-service@0.7.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.40 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-events-backend@0.5.10-next.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-search-common@1.2.21 + +## @backstage/backend-openapi-utils@0.6.5-next.0 + +### Patch Changes + +- 6678b78: Internal update to use native feature from our request validation library for handling base path determination. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/backend-test-utils@1.10.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + +## @backstage/cli@0.35.2-next.0 + +### Patch Changes + +- 320c6a9: Bump `@swc/core` to support `ES2023` and `ES2024` +- 9ee5996: Bump minimum required `@swc/core` to avoid transpilation bug +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/cli-common@0.1.16 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/eslint-plugin@0.2.0 + - @backstage/integration@1.19.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.2 + +## @backstage/create-app@0.7.8-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## @backstage/dev-utils@1.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-catalog-react@1.21.4 + +## @techdocs/cli@1.10.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/cli-common@0.1.16 + - @backstage/config@1.3.6 + - @backstage/plugin-techdocs-node@1.13.10 + +## @backstage/plugin-app-visualizer@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.4.11-next.0 + +### Patch Changes + +- e54fcb2: Added support for custom start URL search parameters (with the new `startUrlSearchParams` config property) +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-auth-node@0.6.10 + +## @backstage/plugin-catalog-backend@3.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + +## @backstage/plugin-catalog-backend-module-aws@0.4.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/integration-aws-node@0.1.19 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-kubernetes-common@0.9.9 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/integration@1.19.0 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.7-next.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.7.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + +## @backstage/plugin-catalog-backend-module-logs@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-events-node@0.4.18 + +## @backstage/plugin-devtools-backend@0.5.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-devtools-common@0.1.20 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + +## @backstage/plugin-events-backend@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.18 + +## @backstage/plugin-mcp-actions-backend@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-node@1.20.1 + +## @backstage/plugin-mui-to-bui@0.2.3-next.0 + +### Patch Changes + +- e4a1180: Updated tokens from `--bui-bg` to `--bui-bg-surface-0` +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/theme@0.7.1 + +## @backstage/plugin-scaffolder-backend@3.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.16 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.17 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.16 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.0 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/backend-test-utils@1.10.3-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + +## @backstage/plugin-search-backend@2.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-search-common@1.2.21 + +## @backstage/plugin-techdocs-backend@2.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-techdocs-node@1.13.10 + +## @backstage/plugin-user-settings-backend@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.117-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/plugin-mui-to-bui@0.2.3-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-app-api@0.13.3 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-devtools@0.1.34 + - @backstage/plugin-home@0.8.15 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-search-common@1.2.21 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-techdocs-react@1.3.6 + - @backstage/plugin-user-settings@0.8.30 + +## example-app-next@0.0.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/plugin-app-visualizer@0.1.27-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-compat-api@0.5.5 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-app-api@0.13.3 + - @backstage/frontend-defaults@0.3.4 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-app@0.3.3 + - @backstage/plugin-auth@0.1.3 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-home@0.8.15 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-search-common@1.2.21 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-techdocs-react@1.3.6 + - @backstage/plugin-user-settings@0.8.30 + +## example-backend@0.0.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-app-backend@0.5.9 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-auth-backend-module-github-provider@0.4.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.15 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.3 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.10-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.7 + - @backstage/plugin-devtools-backend@0.5.13-next.0 + - @backstage/plugin-events-backend@0.5.10-next.0 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.7 + - @backstage/plugin-kubernetes-backend@0.21.0 + - @backstage/plugin-mcp-actions-backend@0.1.7-next.0 + - @backstage/plugin-notifications-backend@0.6.1 + - @backstage/plugin-permission-backend@0.7.7 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.15 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-proxy-backend@0.6.9 + - @backstage/plugin-scaffolder-backend@3.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.17 + - @backstage/plugin-search-backend@2.0.10-next.0 + - @backstage/plugin-search-backend-module-catalog@0.3.11 + - @backstage/plugin-search-backend-module-elasticsearch@1.7.9 + - @backstage/plugin-search-backend-module-explore@0.3.10 + - @backstage/plugin-search-backend-module-techdocs@0.4.9 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-signals-backend@0.3.11 + - @backstage/plugin-techdocs-backend@2.1.4-next.0 + +## e2e-test@0.2.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.8-next.0 + - @backstage/cli-common@0.1.16 + - @backstage/errors@1.2.7 + +## techdocs-cli-embedded-app@0.2.116-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/test-utils@1.7.14 + - @backstage/theme@0.7.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-react@1.3.6 diff --git a/docs/releases/v1.47.0-next.1-changelog.md b/docs/releases/v1.47.0-next.1-changelog.md new file mode 100644 index 0000000000..5c93c23480 --- /dev/null +++ b/docs/releases/v1.47.0-next.1-changelog.md @@ -0,0 +1,648 @@ +# Release v1.47.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.47.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.47.0-next.1) + +## @backstage/backend-defaults@0.14.1-next.1 + +### Patch Changes + +- 3afeab4: Implementing `readTree` for `GoogleGcsReader` +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/backend-dynamic-feature-service@0.7.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-catalog-backend@3.3.1-next.1 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/cli@0.35.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/core-compat-api@0.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/create-app@0.7.8-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @backstage/dev-utils@1.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## @backstage/frontend-app-api@0.13.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-defaults@0.3.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/frontend-defaults@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/frontend-test-utils@0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/integration@1.19.2-next.0 + +### Patch Changes + +- 3afeab4: Implementing `ScmIntegration` for `GoogleGcs` +- 9083273: Rollback the lowercase replacing in GitHub integration config + +## @backstage/integration-react@1.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @techdocs/cli@1.10.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-techdocs-node@1.13.11-next.0 + +## @backstage/plugin-api-docs@0.13.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-app@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog@1.32.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## @backstage/plugin-catalog-backend@3.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.4.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-gitea@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.12.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.12.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.7.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + +## @backstage/plugin-catalog-graph@0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-catalog-import@0.13.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-catalog-react@1.21.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-test-utils@0.4.3-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-devtools@0.1.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-events-backend-module-github@0.4.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-home@0.8.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-kubernetes@0.12.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-kubernetes-cluster@0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## @backstage/plugin-org@0.6.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-org-react@0.1.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## @backstage/plugin-scaffolder@1.35.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-scaffolder-backend@3.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.18-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.1-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.16-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.17-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.9.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.11.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.1 + +## @backstage/plugin-scaffolder-common@1.7.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-scaffolder-node@0.12.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## @backstage/plugin-scaffolder-react@1.19.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-search@1.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## @backstage/plugin-search-backend-module-techdocs@0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs-node@1.13.11-next.0 + +## @backstage/plugin-techdocs@1.16.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## @backstage/plugin-techdocs-addons-test-utils@2.0.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-search-react@1.10.1 + +## @backstage/plugin-techdocs-backend@2.1.4-next.1 + +### Patch Changes + +- b6ff2a5: Some AWS `publisher` config options such as `region`, `endpoint`, `accountId` are now marked as `@visibility backend` instead of `secret`. +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-techdocs-node@1.13.11-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## @backstage/plugin-techdocs-node@1.13.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## @backstage/plugin-user-settings@0.8.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## example-app@0.2.117-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-import@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.35.1-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.32-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/plugin-api-docs@0.13.3-next.0 + - @backstage/plugin-catalog-graph@0.5.5-next.0 + - @backstage/plugin-org@0.6.48-next.0 + - @backstage/plugin-user-settings@0.8.31-next.0 + - @backstage/plugin-home@0.8.16-next.0 + - @backstage/plugin-kubernetes@0.12.15-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.33-next.0 + - @backstage/plugin-search@1.5.2-next.0 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-devtools@0.1.35-next.0 + +## example-app-next@0.0.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-import@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.35.1-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.32-next.0 + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-defaults@0.3.5-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/plugin-api-docs@0.13.3-next.0 + - @backstage/plugin-catalog-graph@0.5.5-next.0 + - @backstage/plugin-org@0.6.48-next.0 + - @backstage/plugin-user-settings@0.8.31-next.0 + - @backstage/plugin-home@0.8.16-next.0 + - @backstage/plugin-kubernetes@0.12.15-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.33-next.0 + - @backstage/plugin-search@1.5.2-next.0 + - @backstage/plugin-app-visualizer@0.1.27-next.0 + - @backstage/plugin-auth@0.1.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## example-backend@0.0.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-techdocs-backend@2.1.4-next.1 + - @backstage/plugin-catalog-backend@3.3.1-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.18-next.0 + - @backstage/plugin-scaffolder-backend@3.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.9.4-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.16-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.18-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.10-next.0 + +## @internal/scaffolder@0.0.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## techdocs-cli-embedded-app@0.2.116-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 diff --git a/docs/tutorials/jest30-migration.md b/docs/tutorials/jest30-migration.md new file mode 100644 index 0000000000..ea79b03009 --- /dev/null +++ b/docs/tutorials/jest30-migration.md @@ -0,0 +1,95 @@ +--- +id: jest30-migration +title: Migrating to Jest 30 +description: A guide to migrating your project to Jest 30 and JSDOM 27 +--- + +Starting with a recent version of `@backstage/cli`, `jest` is a peer dependency. If you run tests using Backstage CLI, you must add Jest and its environment dependencies as `devDependencies` in your project. + +You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed. + +- **Jest 29**: + + ```bash + # in your repository root, run: + yarn add --dev jest@^29 @types/jest@^29 jest-environment-jsdom@^29 + ``` + + Pros: No migration needed + + Cons: You may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations + +- **Jest 30**: + + ```bash + # in your repository root, run: + yarn add --dev jest@^30 @types/jest@^30 @jest/environment-jsdom-abstract@^30 jsdom@^27 + ``` + + Pros: Fixes the stylesheet parsing warnings/errors + + Cons: Requires migration steps (see below) in your tests + +## Migration Guide + +The examples below are issues we encountered while migrating the Backstage repository. For a complete list of breaking changes, see the official documentation: + +- [Jest 30 upgrade guide](https://jestjs.io/docs/upgrading-to-jest30) +- [JSDOM changelog](https://github.com/jsdom/jsdom/releases) + +### Jest 30 + +**Asymmetric matchers with arrays**: `expect.objectContaining()` no longer works with arrays. + +```diff +- expect(result).toEqual(expect.objectContaining([{ id: '123' }])); ++ expect(result).toEqual([{ id: '123' }]); +// or ++ expect(result).toEqual(expect.arrayContaining([{ id: '123' }])); +``` + +**Array length assertions**: `expect.objectContaining({ length: N })` no longer works. + +```diff +- expect(fn).toHaveBeenCalledWith(expect.objectContaining({ length: 2 })); ++ expect(fn).toHaveBeenCalledWith(expect.any(Array)); ++ expect(fn.mock.calls[0][0]).toHaveLength(2); +``` + +**Deprecated matcher aliases removed**: Replace with canonical names. + +```diff +- expect(fn).toBeCalled(); ++ expect(fn).toHaveBeenCalled(); +``` + +**Snapshots**: Regenerate snapshots as the header format has changed. + +```bash +yarn test --no-watch -u +``` + +### JSDOM 27 + +**window.location is non-configurable**: You can no longer mock location via `Object.defineProperty`. + +```diff +- Object.defineProperty(window, 'location', { value: { href: '' } }); ++ // Option 1: Use history API ++ history.replaceState({}, '', '/new-path'); ++ // Option 2: Spy on navigation methods ++ const spy = jest.spyOn(component, 'navigate'); +``` + +**CSS color values**: Colors may be returned as RGB instead of named colors. + +```diff +- expect(element.style.color).toBe('red'); ++ expect(element.style.color).toBe('rgb(255, 0, 0)'); +``` + +**Error format changes**: Error messages and stack traces may have different formatting. + +#### If you run into `Cannot read properties of null (reading 'constructor')` + +Certain Backstage UI-components (e.g. Button) have a combination of CSS that triggers this error in tests. The solution is to make sure you have at least v0.9.25 of `@acemir/cssom`. diff --git a/docs/tutorials/using-backstage-proxy-within-plugin.md b/docs/tutorials/using-backstage-proxy-within-plugin.md index 237a7207a1..bb416bf731 100644 --- a/docs/tutorials/using-backstage-proxy-within-plugin.md +++ b/docs/tutorials/using-backstage-proxy-within-plugin.md @@ -94,15 +94,15 @@ export const AwesomeUsersTable = () => { This section describes the steps to wrap your API client in a [Utility API](../api/utility-apis.md), which are: -- use [`createApiRef`](../reference/frontend-plugin-api.createapiref.md) to create a - new [`ApiRef`](../reference/frontend-plugin-api.apiref.md) -- register an [`ApiFactory`](../reference/frontend-plugin-api.apifactory.md) with +- use [`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html) to create a + new [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) +- register an [`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) with your plugin using - [`createApiFactory`](../reference/frontend-plugin-api.createapifactory.md). This + [`createApiFactory`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiFactory.html). This will wrap your API implementation, associate your `ApiRef` with your implementation and tell backstage how to instantiate it - finally, you can use your API in your components by calling - [`useApi`](../reference/frontend-plugin-api.useapi.md) + [`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) ### Defining the API client interface @@ -187,8 +187,8 @@ export class MyAwesomeApiClient implements MyAwesomeApi { ``` > Check out the docs for more information on the -> [DiscoveryApi](../reference/frontend-plugin-api.discoveryapi.md) or the -> [FetchApi](../reference/frontend-plugin-api.fetchapi.md) +> [DiscoveryApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.DiscoveryApi.html) or the +> [FetchApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.FetchApi.html) ### Bundling your ApiRef with your plugin @@ -233,7 +233,7 @@ export const myCustomPlugin = createPlugin({ ### Using the API in your components Now you should be able to access your API using the backstage hook -[`useApi`](../reference/frontend-plugin-api.useapi.md) from within your plugin code. +[`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) from within your plugin code. ```ts title="plugins/my-awesome-plugin/src/components/AwesomeUsersTable.tsx" import { useApi } from '@backstage/core-plugin-api'; diff --git a/microsite/blog/2025-12-30-backstage-wrapped-2025.mdx b/microsite/blog/2025-12-30-backstage-wrapped-2025.mdx new file mode 100644 index 0000000000..0f8bdd21cf --- /dev/null +++ b/microsite/blog/2025-12-30-backstage-wrapped-2025.mdx @@ -0,0 +1,115 @@ +--- +title: 'Backstage Wrapped 2025: Celebrating a mature framework with modern foundations' +author: Vincenzo Scamporlino, Spotify +authorURL: https://github.com/vinzscam +authorImageURL: https://avatars.githubusercontent.com/u/8433119?v=8 +--- + +![Let's blast into the New Year with a quick look back at all the big hits — backend, frontend, AI, UI, and more! See how today's Backstage is ready to build the future of developer experience.](assets/2025-12-30/wrapped2025.png) + +This year was another big one for Backstage and our worldwide community of adopters, contributors, and partners. Backstage turned five, the New Frontend System became adoption-ready, and your favorite platform for developer experience gained AI superpowers with the introduction of the Actions Registry and MCP server support. Let's blast into the New Year with a quick look back, along with a peek around the corner at what's coming next. + +{/* truncate */} + +--- + +## Busy beavers here, there, and everywhere + +As in years past, we've visualized how our vibrant global community lights up the Backstage open source repo with enthusiasm, creativity, and commits. This year, we're visualizing contributions to the Community Plugins repo, too. Can you spot your name in the videos below? + + + +_All 7.7k commits to `backstage/backstage` in 2025_ + + + +_All 3.3k commits to `backstage/community-plugins` in 2025_ + +Couldn't spot your name in the videos? Here's one more chance — every contributor who helped shape Backstage in 2025, all in one picture. + +![Backstage 2025 contributors](assets/2025-12-30/contributors-wrapped-2025.png) + +## Mature for a five-year-old + +![Backstage community stats: 3.4k+ adopters, 1,8k contributors, 15k Discord members, 7k project forks, 68k total contributions, 250+ open source plugins, 31k stars](assets/2025-12-30/wrapped2025-stats.png) +_The growing Backstage ecosystem, by the numbers_ + +Earlier this year, the Backstage project [celebrated its 5th birthday][bday] on the main stage at [KubeCon + CloudNativeCon in London][kcon-eu]. + +While the framework still isn't old enough to shave, it's matured into the industry standard for internal developer portals (IDPs). According to [this DX survey][dx] released in March: + +> Backstage is dominating the IDP market, holding an impressive 89% market share compared to SaaS competitors and achieving a remarkable 67% overall market penetration. These percentages are even higher for enterprise companies. + +As you can see above in the [latest project stats][video], the Backstage ecosystem continues to expand, growing in adopters and contributors, as well as plugins and third-party service providers. + +Want to dive into more Backstage stats? Check out the project's health scores and more on the relaunched [LFX Insights][lfx] site. + +[bday]: https://www.youtube.com/watch?v=JqG1wey7-Ao&t=563s&list=PL8iP9yIjU0Q3K8LV_a9CcFmhvvNTAUzL1 +[kcon-eu]: https://backstage.io/blog/2025/04/29/backstagecon-kubecon-25-london#big-birthday-energy-on-the-big-stage +[dx]: https://newsletter.getdx.com/p/backstage-and-the-developer-portal-market +[video]: https://www.youtube.com/watch?v=Wih0a1v1Et0&list=PL8iP9yIjU0Q33vpSaBlAvIhgDb-9smXUU +[lfx]: https://insights.linuxfoundation.org/project/backstage + +## Building the future on modern foundations + +Just because Backstage has cemented its place as the standard for IDPs doesn't mean it's sitting still. From backend to frontend, from AI to UI, the technical foundations of the platform have been modernized, updated, and revamped — this is why today's Backstage is ready to build the future of developer experience. + +Top 2025 highlights: + +- Goodbye to the old backend system +- New Frontend System is adoption-ready +- Hello to the Actions Registry + MCP server support +- Introducing a new design system with Backstage UI + +With the [New Backend System][backend] released as a stable 1.0 last year and the [New Frontend System][frontend] becoming [adoption-ready][1-42] this year, Backstage is easier than ever to use, maintain, and build on — making it both more accessible and more capable for adopters, old and new. + +This year also saw the debut of the [Actions Registry][actions] and MCP server support — so now Backstage can empower both your human developers and their AI helpers. + +And [Backstage UI][ui] is coming! The alpha release of the upcoming design system made huge strides in 2025, preparing the way for a new level of usability throughout the Backstage experience. + +Catch up on a whole year's worth of improvements — and see where Backstage is heading next — in the recordings below. + +[backend]: https://backstage.io/docs/backend-system/ +[frontend]: https://backstage.io/docs/frontend-system/ +[1-42]: https://backstage.io/docs/releases/v1.42.0 +[actions]: https://backstage.io/docs/backend-system/core-services/actions-registry +[ui]: https://ui.backstage.io/ + + + +_Watch the Backstage maintainers' talk at [KubeCon in London][lon], where they demoed the New Frontend System and introduced the Actions Registry._ + + +_Watch the maintainers' talk at [KubeCon in Atlanta][atl], where they shared +work towards an AI-Native Backstage, progress on Backstage UI, and more._ + +[lon]: https://backstage.io/blog/2025/04/29/backstagecon-kubecon-25-london +[atl]: https://backstage.io/blog/2025/11/25/backstagecon-kubecon-25-atlanta + +## See you in 2026! + +Happy New Year, Backstage Community! See you in the repos! diff --git a/microsite/blog/assets/2025-12-30/contributors-wrapped-2025.png b/microsite/blog/assets/2025-12-30/contributors-wrapped-2025.png new file mode 100644 index 0000000000..7aa16f106e Binary files /dev/null and b/microsite/blog/assets/2025-12-30/contributors-wrapped-2025.png differ diff --git a/microsite/blog/assets/2025-12-30/wrapped2025-stats.png b/microsite/blog/assets/2025-12-30/wrapped2025-stats.png new file mode 100644 index 0000000000..59d31f142c Binary files /dev/null and b/microsite/blog/assets/2025-12-30/wrapped2025-stats.png differ diff --git a/microsite/blog/assets/2025-12-30/wrapped2025.png b/microsite/blog/assets/2025-12-30/wrapped2025.png new file mode 100644 index 0000000000..b99768dfda Binary files /dev/null and b/microsite/blog/assets/2025-12-30/wrapped2025.png differ diff --git a/microsite/data/plugins/sds_workspace.yaml b/microsite/data/plugins/sds_workspace.yaml new file mode 100644 index 0000000000..43d9a0f20e --- /dev/null +++ b/microsite/data/plugins/sds_workspace.yaml @@ -0,0 +1,10 @@ +--- +title: Citrix Secure Developer Spaces (SDS) +author: Citrix +authorUrl: https://github.com/strong-network +category: Development +description: Connect Backstage with Citrix Secure Developer Spaces (SDS) to view and create developer workspaces. +documentation: https://www.npmjs.com/package/@citrixcloud/backstage-sds-workspaces +iconUrl: /img/citrix_sds.png +npmPackageName: '@citrixcloud/backstage-sds-workspaces' +addedDate: '2025-10-07' diff --git a/microsite/package.json b/microsite/package.json index a3430545f4..edf07abb02 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -28,7 +28,7 @@ "@docusaurus/preset-classic": "^3.1.1", "@docusaurus/types": "^3.1.1", "@mdx-js/react": "^3.0.0", - "@swc/core": "^1.3.46", + "@swc/core": "^1.15.6", "clsx": "^2.0.0", "docusaurus-plugin-openapi-docs": "^4.3.0", "docusaurus-plugin-sass": "^0.2.3", diff --git a/microsite/sidebars.ts b/microsite/sidebars.ts index a68e81aa4f..afe5616bbf 100644 --- a/microsite/sidebars.ts +++ b/microsite/sidebars.ts @@ -18,665 +18,743 @@ const scaffolderSidebar = tryToLoadCustomSidebar( '../docs/features/software-templates/api/sidebar.ts', ); +function sidebarElementWithIndex( + element: { + description?: string; + differentiator?: string; + label: string; + docId?: string; + }, + children: Array, +) { + const { label, description, differentiator } = element; + return { + type: 'category', + label: label, + description, + link: { + type: 'generated-index', + title: label, + slug: `/${differentiator}${label + .toLowerCase() + .replace(/[^a-z0-9 _-]/gi, '-')}/generated-index`, + }, + items: children, + }; +} + export default { - docs: { - Overview: [ + docs: [ + sidebarElementWithIndex({ label: 'Overview' }, [ 'overview/what-is-backstage', 'overview/technical-overview', 'overview/architecture-overview', 'overview/roadmap', 'overview/threat-model', 'overview/versioning-policy', - ], - 'Getting Started': [ + ]), + sidebarElementWithIndex({ label: 'Getting Started' }, [ 'getting-started/index', - { - type: 'category', - label: 'Configuring Backstage', - items: [ - 'getting-started/config/database', - 'getting-started/config/authentication', - 'getting-started/configure-app-with-plugins', - 'getting-started/homepage', - ], - }, - { - type: 'category', - label: 'Deploying Backstage', - items: [ - 'deployment/index', - 'deployment/scaling', - 'deployment/docker', - 'deployment/k8s', - ], - }, - { - type: 'category', - label: 'Using Backstage', - items: [ - 'getting-started/logging-in', - 'getting-started/register-a-component', - 'getting-started/create-a-component', - ], - }, + sidebarElementWithIndex({ label: 'Configuring Backstage' }, [ + 'getting-started/config/database', + 'getting-started/config/authentication', + 'getting-started/configure-app-with-plugins', + 'getting-started/homepage', + ]), + sidebarElementWithIndex({ label: 'Deploying Backstage' }, [ + 'deployment/index', + 'deployment/scaling', + 'deployment/docker', + 'deployment/k8s', + ]), + sidebarElementWithIndex({ label: 'Using Backstage' }, [ + 'getting-started/logging-in', + 'getting-started/register-a-component', + 'getting-started/create-a-component', + ]), 'overview/support', 'getting-started/keeping-backstage-updated', - ], + ]), ...(process.env.GOLDEN_PATH - ? { - 'Golden Paths': [ + ? [ + sidebarElementWithIndex({ label: 'Golden Paths' }, [ + sidebarElementWithIndex({ label: '001 - Create an App' }, [ + 'golden-path/create-app/index', + 'golden-path/create-app/npx-create-app', + 'golden-path/create-app/local-development', + 'golden-path/create-app/installing-plugins', + 'golden-path/create-app/logging-in', + 'golden-path/create-app/custom-theme', + 'golden-path/create-app/keeping-backstage-updated', + ]), + sidebarElementWithIndex({ label: '002 - Plugins' }, [ + 'golden-path/plugins/index', + 'golden-path/plugins/why-build-plugins', + 'golden-path/plugins/sustainable-plugin-development', + sidebarElementWithIndex({ label: 'Backend Plugins' }, [ + 'golden-path/plugins/backend/001-first-steps', + 'golden-path/plugins/backend/002-poking-around', + ]), + ]), + ]), + ] + : []), + sidebarElementWithIndex( + { + label: 'Core Features', + description: 'Features powering the core of Backstage.', + }, + [ + sidebarElementWithIndex( + { + label: 'Auth and Identity', + description: 'Authentication and identity management features.', + }, + [ + 'auth/index', + sidebarElementWithIndex( + { + label: 'Included providers', + description: + 'Pre-configured authentication providers included with Backstage.', + }, + [ + 'auth/auth0/provider', + 'auth/atlassian/provider', + 'auth/aws-alb/provider', + 'auth/microsoft/provider', + 'auth/microsoft/easy-auth', + 'auth/bitbucket/provider', + 'auth/bitbucketServer/provider', + 'auth/cloudflare/provider', + 'auth/github/provider', + 'auth/gitlab/provider', + 'auth/google/provider', + 'auth/google/gcp-iap-auth', + 'auth/guest/provider', + 'auth/okta/provider', + 'auth/oauth2-proxy/provider', + 'auth/onelogin/provider', + 'auth/vmware-cloud/provider', + ], + ), + 'auth/identity-resolver', + 'auth/oauth', + 'auth/oidc', + 'auth/add-auth-provider', + 'auth/service-to-service-auth', + 'auth/autologout', + 'auth/troubleshooting', + ], + ), + sidebarElementWithIndex( + { + label: 'Kubernetes', + description: 'Use Kubernetes right from Backstage.', + }, + [ + 'features/kubernetes/overview', + 'features/kubernetes/installation', + 'features/kubernetes/configuration', + 'features/kubernetes/authentication', + 'features/kubernetes/authentication-strategies', + 'features/kubernetes/troubleshooting', + 'features/kubernetes/proxy', + ], + ), + sidebarElementWithIndex( + { + label: 'Notifications', + description: 'Know when important events happen in Backstage.', + }, + [ + 'notifications/index', + 'notifications/processors', + 'notifications/usage', + ], + ), + sidebarElementWithIndex( + { + label: 'Permissions', + description: 'Access control for your Backstage instance.', + }, + [ + 'permissions/overview', + 'permissions/concepts', + 'permissions/getting-started', + 'permissions/writing-a-policy', + 'permissions/frontend-integration', + 'permissions/custom-rules', + sidebarElementWithIndex( + { + label: 'Tutorial: using Permissions in your plugin', + description: + 'Step-by-step guide for plugin authors on using Permissions.', + }, + [ + 'permissions/plugin-authors/01-setup', + 'permissions/plugin-authors/02-adding-a-basic-permission-check', + 'permissions/plugin-authors/03-adding-a-resource-permission-check', + 'permissions/plugin-authors/04-authorizing-access-to-paginated-data', + 'permissions/plugin-authors/05-frontend-authorization', + ], + ), + ], + ), + sidebarElementWithIndex( + { label: 'Search', description: 'Using Search within Backstage.' }, + [ + 'features/search/search-overview', + 'features/search/getting-started', + 'features/search/concepts', { type: 'category', - label: '001 - create-app', - items: [ - 'golden-path/create-app/index', - 'golden-path/create-app/npx-create-app', - 'golden-path/create-app/local-development', - 'golden-path/create-app/installing-plugins', - 'golden-path/create-app/logging-in', - 'golden-path/create-app/custom-theme', - 'golden-path/create-app/keeping-backstage-updated', - ], + label: 'API', + link: + searchSidebar.length > 0 + ? { + type: 'generated-index', + title: 'Search API', + slug: '/category/search-api', + } + : { + type: 'doc', + id: 'openapi/generated-docs/404', + }, + items: searchSidebar, }, + 'features/search/architecture', + 'features/search/search-engines', + 'features/search/collators', + 'features/search/how-to-guides', + ], + ), + sidebarElementWithIndex( + { + label: 'Software Catalog', + description: 'Manage and explore your software components.', + }, + [ + 'features/software-catalog/software-catalog-overview', + 'features/software-catalog/life-of-an-entity', + 'features/software-catalog/configuration', + 'features/software-catalog/system-model', + 'features/software-catalog/descriptor-format', + 'features/software-catalog/references', + 'features/software-catalog/well-known-annotations', + 'features/software-catalog/well-known-relations', + 'features/software-catalog/well-known-statuses', + 'features/software-catalog/extending-the-model', + 'features/software-catalog/external-integrations', + 'features/software-catalog/catalog-customization', { type: 'category', - label: '002 - Plugins', - items: [ - 'golden-path/plugins/index', - 'golden-path/plugins/why-build-plugins', - 'golden-path/plugins/sustainable-plugin-development', - { - type: 'category', - label: 'Backend Plugins', - items: [ - 'golden-path/plugins/backend/001-first-steps', - 'golden-path/plugins/backend/002-poking-around', - ], - }, - ], + label: 'API', + link: + catalogSidebar.length > 0 + ? { + type: 'generated-index', + title: 'Catalog API', + slug: '/category/catalog-api', + } + : { + type: 'doc', + id: 'openapi/generated-docs/404', + }, + items: catalogSidebar, + }, + 'features/software-catalog/creating-the-catalog-graph', + 'features/software-catalog/faq', + ], + ), + sidebarElementWithIndex( + { + label: 'Software Templates', + description: 'Create and manage software templates.', + }, + [ + 'features/software-templates/software-templates-index', + 'features/software-templates/configuration', + 'features/software-templates/adding-templates', + 'features/software-templates/writing-templates', + 'features/software-templates/input-examples', + 'features/software-templates/builtin-actions', + 'features/software-templates/writing-custom-actions', + 'features/software-templates/writing-tests-for-actions', + 'features/software-templates/writing-custom-field-extensions', + 'features/software-templates/writing-custom-step-layouts', + 'features/software-templates/authorizing-scaffolder-template-details', + 'features/software-templates/migrating-to-rjsf-v5', + 'features/software-templates/migrating-from-v1beta2-to-v1beta3', + 'features/software-templates/dry-run-testing', + 'features/software-templates/experimental', + 'features/software-templates/templating-extensions', + { + type: 'category', + label: 'API', + link: + scaffolderSidebar.length > 0 + ? { + type: 'generated-index', + title: 'Scaffolder API', + slug: '/category/scaffolder-api', + } + : { + type: 'doc', + id: 'openapi/generated-docs/404', + }, + items: scaffolderSidebar, }, ], - } - : {}), - 'Core Features': [ - { - type: 'category', - label: 'Auth and Identity', - items: [ - 'auth/index', + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Included providers', - items: [ - 'auth/auth0/provider', - 'auth/atlassian/provider', - 'auth/aws-alb/provider', - 'auth/microsoft/provider', - 'auth/microsoft/easy-auth', - 'auth/bitbucket/provider', - 'auth/bitbucketServer/provider', - 'auth/cloudflare/provider', - 'auth/github/provider', - 'auth/gitlab/provider', - 'auth/google/provider', - 'auth/google/gcp-iap-auth', - 'auth/guest/provider', - 'auth/okta/provider', - 'auth/oauth2-proxy/provider', - 'auth/onelogin/provider', - 'auth/vmware-cloud/provider', - ], + label: 'TechDocs', + description: 'Documentation as code for your software.', }, - 'auth/identity-resolver', - 'auth/oauth', - 'auth/oidc', - 'auth/add-auth-provider', - 'auth/service-to-service-auth', - 'auth/autologout', - 'auth/troubleshooting', - ], - }, + [ + 'features/techdocs/techdocs-overview', + 'features/techdocs/getting-started', + 'features/techdocs/concepts', + 'features/techdocs/addons', + 'features/techdocs/architecture', + 'features/techdocs/extensions', + 'features/techdocs/creating-and-publishing', + 'features/techdocs/configuration', + 'features/techdocs/using-cloud-storage', + 'features/techdocs/configuring-ci-cd', + 'features/techdocs/cli', + 'features/techdocs/how-to-guides', + 'features/techdocs/troubleshooting', + 'features/techdocs/faqs', + ], + ), + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Kubernetes', - items: [ - 'features/kubernetes/overview', - 'features/kubernetes/installation', - 'features/kubernetes/configuration', - 'features/kubernetes/authentication', - 'features/kubernetes/authentication-strategies', - 'features/kubernetes/troubleshooting', - 'features/kubernetes/proxy', - ], + label: 'Integrations', + description: 'Connect and integrate with external services.', }, - { - type: 'category', - label: 'Notifications', - items: [ - 'notifications/index', - 'notifications/processors', - 'notifications/usage', - ], - }, - { - type: 'category', - label: 'Permissions', - items: [ - 'permissions/overview', - 'permissions/concepts', - 'permissions/getting-started', - 'permissions/writing-a-policy', - 'permissions/frontend-integration', - 'permissions/custom-rules', - { - type: 'category', - label: 'Tutorial: using Permissions in your plugin', - items: [ - 'permissions/plugin-authors/01-setup', - 'permissions/plugin-authors/02-adding-a-basic-permission-check', - 'permissions/plugin-authors/03-adding-a-resource-permission-check', - 'permissions/plugin-authors/04-authorizing-access-to-paginated-data', - 'permissions/plugin-authors/05-frontend-authorization', - ], - }, - ], - }, - { - type: 'category', - label: 'Search', - items: [ - 'features/search/search-overview', - 'features/search/getting-started', - 'features/search/concepts', - { - type: 'category', - label: 'API', - link: - searchSidebar.length > 0 - ? { - type: 'generated-index', - title: 'Search API', - slug: '/category/search-api', - } - : { - type: 'doc', - id: 'openapi/generated-docs/404', - }, - items: searchSidebar, - }, - 'features/search/architecture', - 'features/search/search-engines', - 'features/search/collators', - 'features/search/how-to-guides', - ], - }, - { - type: 'category', - label: 'Software Catalog', - items: [ - 'features/software-catalog/software-catalog-overview', - 'features/software-catalog/life-of-an-entity', - 'features/software-catalog/configuration', - 'features/software-catalog/system-model', - 'features/software-catalog/descriptor-format', - 'features/software-catalog/references', - 'features/software-catalog/well-known-annotations', - 'features/software-catalog/well-known-relations', - 'features/software-catalog/well-known-statuses', - 'features/software-catalog/extending-the-model', - 'features/software-catalog/external-integrations', - 'features/software-catalog/catalog-customization', - { - type: 'category', - label: 'API', - link: - catalogSidebar.length > 0 - ? { - type: 'generated-index', - title: 'Catalog API', - slug: '/category/catalog-api', - } - : { - type: 'doc', - id: 'openapi/generated-docs/404', - }, - items: catalogSidebar, - }, - 'features/software-catalog/creating-the-catalog-graph', - 'features/software-catalog/faq', - ], - }, - { - type: 'category', - label: 'Software Templates', - items: [ - 'features/software-templates/software-templates-index', - 'features/software-templates/configuration', - 'features/software-templates/adding-templates', - 'features/software-templates/writing-templates', - 'features/software-templates/input-examples', - 'features/software-templates/builtin-actions', - 'features/software-templates/writing-custom-actions', - 'features/software-templates/writing-tests-for-actions', - 'features/software-templates/writing-custom-field-extensions', - 'features/software-templates/writing-custom-step-layouts', - 'features/software-templates/authorizing-scaffolder-template-details', - 'features/software-templates/migrating-to-rjsf-v5', - 'features/software-templates/migrating-from-v1beta2-to-v1beta3', - 'features/software-templates/dry-run-testing', - 'features/software-templates/experimental', - 'features/software-templates/templating-extensions', - { - type: 'category', - label: 'API', - link: - scaffolderSidebar.length > 0 - ? { - type: 'generated-index', - title: 'Scaffolder API', - slug: '/category/scaffolder-api', - } - : { - type: 'doc', - id: 'openapi/generated-docs/404', - }, - items: scaffolderSidebar, - }, - ], - }, - { - type: 'category', - label: 'TechDocs', - items: [ - 'features/techdocs/techdocs-overview', - 'features/techdocs/getting-started', - 'features/techdocs/concepts', - 'features/techdocs/addons', - 'features/techdocs/architecture', - 'features/techdocs/extensions', - 'features/techdocs/creating-and-publishing', - 'features/techdocs/configuration', - 'features/techdocs/using-cloud-storage', - 'features/techdocs/configuring-ci-cd', - 'features/techdocs/cli', - 'features/techdocs/how-to-guides', - 'features/techdocs/troubleshooting', - 'features/techdocs/faqs', - ], - }, - ], - Integrations: [ - 'integrations/index', - { - type: 'category', - label: 'AWS S3', - items: [ + [ + 'integrations/index', + sidebarElementWithIndex({ label: 'AWS S3' }, [ 'integrations/aws-s3/locations', 'integrations/aws-s3/discovery', - ], - }, - { - type: 'category', - label: 'Azure Blob Storage', - items: [ + ]), + sidebarElementWithIndex({ label: 'Azure Blob Storage' }, [ 'integrations/azure-blobStorage/locations', 'integrations/azure-blobStorage/discovery', - ], - }, - { - type: 'category', - label: 'Azure', - items: [ + ]), + sidebarElementWithIndex({ label: 'Azure' }, [ 'integrations/azure/locations', 'integrations/azure/discovery', 'integrations/azure/org', - ], - }, - { - type: 'category', - label: 'Bitbucket Cloud', - items: [ + ]), + sidebarElementWithIndex({ label: 'Bitbucket Cloud' }, [ 'integrations/bitbucketCloud/locations', 'integrations/bitbucketCloud/discovery', - ], - }, - { - type: 'category', - label: 'Bitbucket Server', - items: [ + ]), + sidebarElementWithIndex({ label: 'Bitbucket Server' }, [ 'integrations/bitbucketServer/locations', 'integrations/bitbucketServer/discovery', - ], - }, - { - type: 'category', - label: 'Datadog', - items: ['integrations/datadog-rum/installation'], - }, - { - type: 'category', - label: 'Gerrit', - items: [ + ]), + sidebarElementWithIndex({ label: 'Datadog' }, [ + 'integrations/datadog-rum/installation', + ]), + sidebarElementWithIndex({ label: 'Gerrit' }, [ 'integrations/gerrit/locations', 'integrations/gerrit/discovery', - ], - }, - { - type: 'category', - label: 'GitHub', - items: [ + ]), + sidebarElementWithIndex({ label: 'Github' }, [ 'integrations/github/locations', 'integrations/github/discovery', 'integrations/github/org', 'integrations/github/github-apps', - ], - }, - { - type: 'category', - label: 'GitLab', - items: [ + ]), + sidebarElementWithIndex({ label: 'GitLab' }, [ 'integrations/gitlab/locations', 'integrations/gitlab/discovery', 'integrations/gitlab/org', - ], - }, + ]), + sidebarElementWithIndex({ label: 'Gitea' }, [ + 'integrations/gitea/locations', + 'integrations/gitea/discovery', + ]), + sidebarElementWithIndex({ label: 'Harness' }, [ + 'integrations/harness/locations', + ]), + sidebarElementWithIndex({ label: 'Google GCS' }, [ + 'integrations/google-cloud-storage/locations', + ]), + sidebarElementWithIndex({ label: 'LDAP' }, ['integrations/ldap/org']), + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Gitea', - items: ['integrations/gitea/locations', 'integrations/gitea/discovery'], + label: 'Plugins', + description: 'Extend Backstage with custom functionality.', }, - { - type: 'category', - label: 'Harness', - items: ['integrations/harness/locations'], - }, - { - type: 'category', - label: 'Google GCS', - items: ['integrations/google-cloud-storage/locations'], - }, - { - type: 'category', - label: 'LDAP', - items: ['integrations/ldap/org'], - }, - ], - Plugins: [ - 'plugins/index', - 'plugins/existing-plugins', - 'plugins/create-a-plugin', - 'plugins/plugin-development', - 'plugins/structure-of-a-plugin', - 'plugins/integrating-plugin-into-software-catalog', - 'plugins/integrating-search-into-plugins', - 'plugins/composability', - 'plugins/internationalization', - 'plugins/analytics', - 'plugins/feature-flags', - { - type: 'category', - label: 'OpenAPI', - items: [ - 'openapi/01-getting-started', - 'openapi/generate-client', - 'openapi/test-case-validation', - ], - }, - { - type: 'category', - label: 'Backends and APIs', - items: [ - 'plugins/proxying', - 'plugins/backend-plugin', - 'plugins/call-existing-api', - ], - }, - { - type: 'category', - label: 'Testing', - items: ['plugins/testing'], - }, - { - type: 'category', - label: 'Publishing', - items: [ - 'plugins/publish-private', - 'plugins/add-to-directory', - 'plugins/observability', - ], - }, - ], - Configuration: [ - 'conf/index', - 'conf/reading', - 'conf/writing', - 'conf/defining', - ], - Framework: [ - { - type: 'category', - label: 'Backend System', - items: [ - 'backend-system/index', + [ + 'plugins/index', + 'plugins/existing-plugins', + 'plugins/create-a-plugin', + 'plugins/plugin-development', + 'plugins/structure-of-a-plugin', + 'plugins/integrating-plugin-into-software-catalog', + 'plugins/integrating-search-into-plugins', + 'plugins/composability', + 'plugins/internationalization', + 'plugins/analytics', + 'plugins/feature-flags', + sidebarElementWithIndex( { - type: 'category', - label: 'Architecture', - items: [ - 'backend-system/architecture/index', - 'backend-system/architecture/services', - 'backend-system/architecture/plugins', - 'backend-system/architecture/extension-points', - 'backend-system/architecture/modules', - 'backend-system/architecture/feature-loaders', - 'backend-system/architecture/naming-patterns', - ], + label: 'OpenAPI', + description: + 'Work with OpenAPI specifications and generate clients.', }, + [ + 'openapi/01-getting-started', + 'openapi/generate-client', + 'openapi/test-case-validation', + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Building Backends', - items: [ - 'backend-system/building-backends/index', - 'backend-system/building-backends/migrating', - ], + label: 'Backends and APIs', + description: 'Build and manage backend services and APIs.', }, - { - type: 'category', - label: 'Building Plugins & Modules', - items: [ - 'backend-system/building-plugins-and-modules/index', - 'backend-system/building-plugins-and-modules/testing', - 'backend-system/building-plugins-and-modules/migrating', - ], - }, - { - type: 'category', - label: 'Core Services', - items: [ - 'backend-system/core-services/index', - 'backend-system/core-services/auditor', - 'backend-system/core-services/auth', - 'backend-system/core-services/cache', - 'backend-system/core-services/database', - 'backend-system/core-services/discovery', - 'backend-system/core-services/http-auth', - 'backend-system/core-services/http-router', - 'backend-system/core-services/identity', - 'backend-system/core-services/lifecycle', - 'backend-system/core-services/logger', - 'backend-system/core-services/permissions', - 'backend-system/core-services/permissions-registry', - 'backend-system/core-services/plugin-metadata', - 'backend-system/core-services/root-config', - 'backend-system/core-services/root-health', - 'backend-system/core-services/root-instance-metadata', - 'backend-system/core-services/root-http-router', - 'backend-system/core-services/root-lifecycle', - 'backend-system/core-services/root-logger', - 'backend-system/core-services/scheduler', - 'backend-system/core-services/token-manager', - 'backend-system/core-services/url-reader', - 'backend-system/core-services/user-info', - 'backend-system/core-services/actions-registry', - 'backend-system/core-services/actions', - ], - }, - ], - }, + [ + 'plugins/proxying', + 'plugins/backend-plugin', + 'plugins/call-existing-api', + ], + ), + sidebarElementWithIndex( + { label: 'Testing', description: 'Testing plugins and modules.' }, + ['plugins/testing'], + ), + sidebarElementWithIndex( + { label: 'Publishing', description: 'Publishing your plugins.' }, + ['plugins/publish-private', 'plugins/add-to-directory'], + ), + 'plugins/observability', + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'New Frontend System', - items: [ - 'frontend-system/index', + label: 'Configuration', + description: 'Manage static configuration files and settings.', + }, + ['conf/index', 'conf/reading', 'conf/writing', 'conf/defining'], + ), + sidebarElementWithIndex( + { + label: 'Framework', + description: 'Core framework concepts and architecture.', + }, + [ + sidebarElementWithIndex( { - type: 'category', - label: 'Architecture', - items: [ - 'frontend-system/architecture/index', - 'frontend-system/architecture/app', - 'frontend-system/architecture/plugins', - 'frontend-system/architecture/extensions', - 'frontend-system/architecture/extension-blueprints', - 'frontend-system/architecture/extension-overrides', - 'frontend-system/architecture/references', - 'frontend-system/architecture/utility-apis', - 'frontend-system/architecture/routes', - 'frontend-system/architecture/naming-patterns', - 'frontend-system/architecture/migrations', - ], + label: 'Backend System', + description: 'Backend system components and architecture.', }, + [ + 'backend-system/index', + sidebarElementWithIndex( + { + label: 'Architecture', + description: 'Architecture of the backend system.', + }, + [ + 'backend-system/architecture/index', + 'backend-system/architecture/services', + 'backend-system/architecture/plugins', + 'backend-system/architecture/extension-points', + 'backend-system/architecture/modules', + 'backend-system/architecture/feature-loaders', + 'backend-system/architecture/naming-patterns', + ], + ), + sidebarElementWithIndex( + { + label: 'Building Backends', + description: 'Guides on building backend systems.', + }, + [ + 'backend-system/building-backends/index', + 'backend-system/building-backends/migrating', + ], + ), + sidebarElementWithIndex( + { + label: 'Building Plugins & Modules', + description: 'Guides on building plugins and modules.', + }, + [ + 'backend-system/building-plugins-and-modules/index', + 'backend-system/building-plugins-and-modules/testing', + 'backend-system/building-plugins-and-modules/migrating', + ], + ), + sidebarElementWithIndex( + { + label: 'Core Services', + description: 'Core services of the backend system.', + }, + [ + 'backend-system/core-services/index', + 'backend-system/core-services/auditor', + 'backend-system/core-services/auth', + 'backend-system/core-services/cache', + 'backend-system/core-services/database', + 'backend-system/core-services/discovery', + 'backend-system/core-services/http-auth', + 'backend-system/core-services/http-router', + 'backend-system/core-services/identity', + 'backend-system/core-services/lifecycle', + 'backend-system/core-services/logger', + 'backend-system/core-services/permissions', + 'backend-system/core-services/permissions-registry', + 'backend-system/core-services/plugin-metadata', + 'backend-system/core-services/root-config', + 'backend-system/core-services/root-health', + 'backend-system/core-services/root-http-router', + 'backend-system/core-services/root-instance-metadata', + 'backend-system/core-services/root-lifecycle', + 'backend-system/core-services/root-logger', + 'backend-system/core-services/scheduler', + 'backend-system/core-services/token-manager', + 'backend-system/core-services/url-reader', + 'backend-system/core-services/user-info', + 'backend-system/core-services/actions-registry', + 'backend-system/core-services/actions', + ], + ), + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Building Plugins', - items: [ - 'frontend-system/building-plugins/index', - 'frontend-system/building-plugins/testing', - 'frontend-system/building-plugins/common-extension-blueprints', - 'frontend-system/building-plugins/built-in-data-refs', - 'frontend-system/building-plugins/migrating', - ], + label: 'New Frontend System', + description: 'New frontend system components and architecture.', }, + [ + 'frontend-system/index', + sidebarElementWithIndex( + { + label: 'Architecture', + description: 'Architecture of the new frontend system.', + }, + [ + 'frontend-system/architecture/index', + 'frontend-system/architecture/app', + 'frontend-system/architecture/plugins', + 'frontend-system/architecture/extensions', + 'frontend-system/architecture/extension-blueprints', + 'frontend-system/architecture/extension-overrides', + 'frontend-system/architecture/references', + 'frontend-system/architecture/utility-apis', + 'frontend-system/architecture/routes', + 'frontend-system/architecture/naming-patterns', + 'frontend-system/architecture/migrations', + ], + ), + sidebarElementWithIndex( + { + label: 'Building Plugins', + description: 'Guides on building frontend plugins.', + }, + [ + 'frontend-system/building-plugins/index', + 'frontend-system/building-plugins/testing', + 'frontend-system/building-plugins/common-extension-blueprints', + 'frontend-system/building-plugins/built-in-data-refs', + 'frontend-system/building-plugins/migrating', + ], + ), + sidebarElementWithIndex( + { + label: 'Building Apps', + description: 'Guides on building frontend applications.', + }, + [ + 'frontend-system/building-apps/index', + 'frontend-system/building-apps/configuring-extensions', + 'frontend-system/building-apps/built-in-extensions', + 'frontend-system/building-apps/plugin-conversion', + 'frontend-system/building-apps/migrating', + ], + ), + sidebarElementWithIndex( + { + label: 'Utility APIs', + description: 'Utility APIs for the frontend system.', + }, + [ + 'frontend-system/utility-apis/index', + 'frontend-system/utility-apis/creating', + 'frontend-system/utility-apis/consuming', + 'frontend-system/utility-apis/configuring', + ], + ), + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Building Apps', - items: [ - 'frontend-system/building-apps/index', - 'frontend-system/building-apps/configuring-extensions', - 'frontend-system/building-apps/built-in-extensions', - 'frontend-system/building-apps/plugin-conversion', - 'frontend-system/building-apps/migrating', - ], + label: 'Backstage CLI', + description: 'Command-line interface for Backstage.', }, + [ + 'tooling/cli/overview', + 'tooling/cli/build-system', + 'tooling/cli/commands', + 'tooling/cli/templates', + sidebarElementWithIndex( + { + label: 'Local Development', + description: + 'Guides for local development using Backstage CLI.', + }, + [ + 'tooling/local-dev/linking-local-packages', + 'tooling/local-dev/debugging', + 'tooling/local-dev/profiling', + ], + ), + 'tooling/package-metadata', + ], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'Utility APIs', - items: [ - 'frontend-system/utility-apis/index', - 'frontend-system/utility-apis/creating', - 'frontend-system/utility-apis/consuming', - 'frontend-system/utility-apis/configuring', - ], + label: 'User Interface', + description: 'User interface customization and configuration.', }, - ], - }, + [ + 'conf/user-interface/index', + 'conf/user-interface/logo', + 'conf/user-interface/icons', + 'conf/user-interface/sidebar', + ], + ), + ], + ), + sidebarElementWithIndex( { - 'Backstage CLI': [ - 'tooling/cli/overview', - 'tooling/cli/build-system', - 'tooling/cli/commands', - 'tooling/cli/templates', + label: 'Tutorials', + description: + 'Step-by-step tutorials for various Backstage features and use cases.', + }, + [ + sidebarElementWithIndex( { - type: 'category', - label: 'Local Development', - items: [ - 'tooling/local-dev/linking-local-packages', - 'tooling/local-dev/debugging', - 'tooling/local-dev/profiling', - ], + label: 'Non-technical', + description: 'Non-technical tutorials and guides.', }, - 'tooling/package-metadata', - ], - }, + ['overview/adopting'], + ), + sidebarElementWithIndex( + { + label: 'Technical', + description: 'Technical tutorials and guides.', + }, + [ + 'tutorials/quickstart-app-plugin', + 'tutorials/configuring-plugin-databases', + 'tutorials/manual-knex-rollback', + 'tutorials/switching-sqlite-postgres', + 'tutorials/using-backstage-proxy-within-plugin', + 'tutorials/enable-public-entry', + 'tutorials/setup-opentelemetry', + 'tutorials/integrating-event-driven-updates-with-entity-providers', + 'accessibility/index', + ], + ), + sidebarElementWithIndex( + { + label: 'Migrations', + description: + 'Guides for migrating between different versions and systems.', + }, + [ + 'tutorials/jest30-migration', + 'tutorials/react-router-stable-migration', + 'tutorials/react18-migration', + 'tutorials/package-role-migration', + 'tutorials/migrating-away-from-core', + 'tutorials/yarn-migration', + 'tutorials/migrate-to-mui5', + 'tutorials/auth-service-migration', + 'tutorials/jsx-transform-migration', + ], + ), + ], + ), + sidebarElementWithIndex( + { label: 'FAQ', description: 'Frequently asked questions and answers.' }, + ['faq/index', 'faq/product', 'faq/technical'], + ), + sidebarElementWithIndex( { - type: 'category', - label: 'User Interface', - items: [ - 'conf/user-interface/index', - 'conf/user-interface/logo', - 'conf/user-interface/icons', - 'conf/user-interface/sidebar', - ], + label: 'Contribute', + description: 'Information on contributing to Backstage.', }, - ], - Tutorials: [ - { 'Non-technical': ['overview/adopting'] }, + [ + 'contribute/index', + 'contribute/getting-involved', + 'contribute/project-structure', + ], + ), + sidebarElementWithIndex( { - Technical: [ - 'tutorials/quickstart-app-plugin', - 'tutorials/configuring-plugin-databases', - 'tutorials/manual-knex-rollback', - 'tutorials/switching-sqlite-postgres', - 'tutorials/using-backstage-proxy-within-plugin', - 'tutorials/enable-public-entry', - 'tutorials/setup-opentelemetry', - 'tutorials/integrating-event-driven-updates-with-entity-providers', - 'accessibility/index', - ], + label: 'References', + description: 'Reference materials and documentation.', }, - { - Migrations: [ - 'tutorials/react-router-stable-migration', - 'tutorials/react18-migration', - 'tutorials/package-role-migration', - 'tutorials/migrating-away-from-core', - 'tutorials/yarn-migration', - 'tutorials/migrate-to-mui5', - 'tutorials/auth-service-migration', - 'tutorials/jsx-transform-migration', - ], - }, - ], - FAQ: ['faq/index', 'faq/product', 'faq/technical'], - Contribute: [ - 'contribute/index', - 'contribute/getting-involved', - 'contribute/project-structure', - ], - References: [ - { - 'Designing for Backstage': [ - 'dls/design', - 'dls/component-design-guidelines', - 'dls/contributing-to-storybook', - 'dls/figma', - ], - }, - { - type: 'category', - label: 'Architecture Decision Records (ADRs)', - items: [ - 'architecture-decisions/adrs-overview', - 'architecture-decisions/adrs-adr001', - 'architecture-decisions/adrs-adr002', - 'architecture-decisions/adrs-adr003', - 'architecture-decisions/adrs-adr004', - 'architecture-decisions/adrs-adr005', - 'architecture-decisions/adrs-adr006', - 'architecture-decisions/adrs-adr007', - 'architecture-decisions/adrs-adr008', - 'architecture-decisions/adrs-adr009', - 'architecture-decisions/adrs-adr010', - 'architecture-decisions/adrs-adr011', - 'architecture-decisions/adrs-adr012', - 'architecture-decisions/adrs-adr013', - 'architecture-decisions/adrs-adr014', - ], - }, - 'api/deprecations', - 'references/glossary', - 'api/utility-apis', - 'reference/index', - ], - }, + [ + sidebarElementWithIndex( + { + label: 'Designing for Backstage', + description: + 'Guidelines and resources for designing Backstage components.', + }, + [ + 'dls/design', + 'dls/component-design-guidelines', + 'dls/contributing-to-storybook', + 'dls/figma', + ], + ), + sidebarElementWithIndex( + { + label: 'Architecture Decision Records (ADRs)', + description: + 'Documentation of architectural decisions made in Backstage.', + }, + [ + 'architecture-decisions/adrs-overview', + 'architecture-decisions/adrs-adr001', + 'architecture-decisions/adrs-adr002', + 'architecture-decisions/adrs-adr003', + 'architecture-decisions/adrs-adr004', + 'architecture-decisions/adrs-adr005', + 'architecture-decisions/adrs-adr006', + 'architecture-decisions/adrs-adr007', + 'architecture-decisions/adrs-adr008', + 'architecture-decisions/adrs-adr009', + 'architecture-decisions/adrs-adr010', + 'architecture-decisions/adrs-adr011', + 'architecture-decisions/adrs-adr012', + 'architecture-decisions/adrs-adr013', + 'architecture-decisions/adrs-adr014', + 'architecture-decisions/adrs-adr015', + ], + ), + 'api/deprecations', + 'references/glossary', + 'api/utility-apis', + 'reference/index', + ], + ), + ], releases: { 'Release Notes': releases.map(release => `releases/${release}`), }, diff --git a/microsite/static/img/citrix_sds.png b/microsite/static/img/citrix_sds.png new file mode 100644 index 0000000000..fac58411a1 Binary files /dev/null and b/microsite/static/img/citrix_sds.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 2f6e723889..acceac04e2 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2961,90 +2961,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-darwin-arm64@npm:1.15.3" +"@swc/core-darwin-arm64@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-darwin-arm64@npm:1.15.6" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-darwin-x64@npm:1.15.3" +"@swc/core-darwin-x64@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-darwin-x64@npm:1.15.6" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.3" +"@swc/core-linux-arm-gnueabihf@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.6" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm64-gnu@npm:1.15.3" +"@swc/core-linux-arm64-gnu@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm64-gnu@npm:1.15.6" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm64-musl@npm:1.15.3" +"@swc/core-linux-arm64-musl@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm64-musl@npm:1.15.6" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-x64-gnu@npm:1.15.3" +"@swc/core-linux-x64-gnu@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-x64-gnu@npm:1.15.6" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-x64-musl@npm:1.15.3" +"@swc/core-linux-x64-musl@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-x64-musl@npm:1.15.6" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-arm64-msvc@npm:1.15.3" +"@swc/core-win32-arm64-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-arm64-msvc@npm:1.15.6" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-ia32-msvc@npm:1.15.3" +"@swc/core-win32-ia32-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-ia32-msvc@npm:1.15.6" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-x64-msvc@npm:1.15.3" +"@swc/core-win32-x64-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-x64-msvc@npm:1.15.6" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.46": - version: 1.15.3 - resolution: "@swc/core@npm:1.15.3" +"@swc/core@npm:^1.15.6": + version: 1.15.6 + resolution: "@swc/core@npm:1.15.6" dependencies: - "@swc/core-darwin-arm64": "npm:1.15.3" - "@swc/core-darwin-x64": "npm:1.15.3" - "@swc/core-linux-arm-gnueabihf": "npm:1.15.3" - "@swc/core-linux-arm64-gnu": "npm:1.15.3" - "@swc/core-linux-arm64-musl": "npm:1.15.3" - "@swc/core-linux-x64-gnu": "npm:1.15.3" - "@swc/core-linux-x64-musl": "npm:1.15.3" - "@swc/core-win32-arm64-msvc": "npm:1.15.3" - "@swc/core-win32-ia32-msvc": "npm:1.15.3" - "@swc/core-win32-x64-msvc": "npm:1.15.3" + "@swc/core-darwin-arm64": "npm:1.15.6" + "@swc/core-darwin-x64": "npm:1.15.6" + "@swc/core-linux-arm-gnueabihf": "npm:1.15.6" + "@swc/core-linux-arm64-gnu": "npm:1.15.6" + "@swc/core-linux-arm64-musl": "npm:1.15.6" + "@swc/core-linux-x64-gnu": "npm:1.15.6" + "@swc/core-linux-x64-musl": "npm:1.15.6" + "@swc/core-win32-arm64-msvc": "npm:1.15.6" + "@swc/core-win32-ia32-msvc": "npm:1.15.6" + "@swc/core-win32-x64-msvc": "npm:1.15.6" "@swc/counter": "npm:^0.1.3" "@swc/types": "npm:^0.1.25" peerDependencies: @@ -3073,7 +3073,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/280330d82328818138ed64fdcf9ea9abde6b6f16eca65a9d4db27dde06a8dfffd2649f3447d2243387277513c7430fa4142cafcfd64e943d682ce6a713cb8c2d + checksum: 10/d17d1b5e6e81f8c262b668f237b863dd612eaa19fc35e74067b2a27ba3998c0c511ec7f49cd91c02f61fa77dd1b5d7e65d293736f65ec45d6c13989904b1c7eb languageName: node linkType: hard @@ -4274,7 +4274,7 @@ __metadata: "@docusaurus/tsconfig": "npm:^3.1.1" "@docusaurus/types": "npm:^3.1.1" "@mdx-js/react": "npm:^3.0.0" - "@swc/core": "npm:^1.3.46" + "@swc/core": "npm:^1.15.6" "@types/webpack-env": "npm:^1.18.0" clsx: "npm:^2.0.0" docusaurus-plugin-openapi-docs: "npm:^4.3.0" @@ -4721,9 +4721,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001688": - version: 1.0.30001695 - resolution: "caniuse-lite@npm:1.0.30001695" - checksum: 10/8107c5e89b86c7a2fd506b93c658ff945c98c6518260c3b28af9f02bd83bf83939696241f0b413545c5b9895c86bcae64c9370388576440e74e9b848f04170d3 + version: 1.0.30001760 + resolution: "caniuse-lite@npm:1.0.30001760" + checksum: 10/ac5c13d00b946c3ace331d25379ed9d85743b1028aba79ae80402cb128b4b491122585144898fefb836d4d9879c13c717a081ae241a00420cbbc7e1b934ec685 languageName: node linkType: hard diff --git a/package.json b/package.json index caef1349f3..53a8387281 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.46.0-next.2", + "version": "1.47.0-next.1", "backstage": { "cli": { "new": { @@ -117,7 +117,6 @@ "csstype@npm:^3.0.2": "3.0.9", "csstype@npm:^3.1.2": "3.0.9", "csstype@npm:^3.1.3": "3.0.9", - "jest-haste-map@^29.7.0": "patch:jest-haste-map@npm%3A29.7.0#./.yarn/patches/jest-haste-map-npm-29.7.0-e3be419eff.patch", "recast@npm:0.23.9>ast-types": "patch:ast-types@npm%3A0.16.1#./.yarn/patches/ast-types-npm-0.16.1-43c4ac4b0d.patch" }, "dependencies": { @@ -138,11 +137,12 @@ "@octokit/rest": "^19.0.3", "@playwright/test": "^1.32.3", "@spotify/eslint-plugin": "^15.0.0", - "@storybook/addon-a11y": "^9.1.7", - "@storybook/addon-docs": "^9.1.7", - "@storybook/addon-links": "^9.1.7", - "@storybook/addon-themes": "^9.1.7", - "@storybook/react-vite": "^9.1.7", + "@storybook/addon-a11y": "^10.1.9", + "@storybook/addon-docs": "^10.1.9", + "@storybook/addon-links": "^10.1.9", + "@storybook/addon-themes": "^10.1.9", + "@storybook/addon-vitest": "^10.1.9", + "@storybook/react-vite": "^10.1.9", "@techdocs/cli": "workspace:*", "@types/cacheable-request": "^8.3.6", "@types/memjs": "^1.3.3", @@ -168,7 +168,7 @@ "shx": "^0.4.0", "sloc": "^0.3.1", "sort-package-json": "^2.8.0", - "storybook": "^9.1.7", + "storybook": "^10.1.10", "ts-morph": "^24.0.0", "typedoc": "^0.28.0", "typescript": "~5.7.0", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index ee64c2209e..cca956654d 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.7.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + ## 1.7.3-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index ec08c04929..878e5b505b 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.7.3-next.0", + "version": "1.7.3", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index da46f90c56..ee1e797be4 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.30 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + ## 0.0.30-next.0 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index f7d113827d..f632f00de8 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-next-example-plugin", - "version": "0.0.30-next.0", + "version": "0.0.30", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 0a38482bab..81e6fe95aa 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,126 @@ # example-app-next +## 0.0.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-import@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.35.1-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.32-next.0 + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-defaults@0.3.5-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/plugin-api-docs@0.13.3-next.0 + - @backstage/plugin-catalog-graph@0.5.5-next.0 + - @backstage/plugin-org@0.6.48-next.0 + - @backstage/plugin-user-settings@0.8.31-next.0 + - @backstage/plugin-home@0.8.16-next.0 + - @backstage/plugin-kubernetes@0.12.15-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.33-next.0 + - @backstage/plugin-search@1.5.2-next.0 + - @backstage/plugin-app-visualizer@0.1.27-next.0 + - @backstage/plugin-auth@0.1.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## 0.0.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/plugin-app-visualizer@0.1.27-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-compat-api@0.5.5 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-app-api@0.13.3 + - @backstage/frontend-defaults@0.3.4 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-app@0.3.3 + - @backstage/plugin-auth@0.1.3 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-home@0.8.15 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-search-common@1.2.21 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-techdocs-react@1.3.6 + - @backstage/plugin-user-settings@0.8.30 + +## 0.0.30 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-app@0.3.3 + - @backstage/plugin-org@0.6.47 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-app-visualizer@0.1.26 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-user-settings@0.8.30 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-home@0.8.15 + - @backstage/theme@0.7.1 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/app-defaults@1.7.3 + - @backstage/core-compat-api@0.5.5 + - @backstage/frontend-app-api@0.13.3 + - @backstage/frontend-defaults@0.3.4 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth@0.1.3 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs-react@1.3.6 + ## 0.0.30-next.2 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index c6d1ae36cc..c0015ad3ea 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.30-next.2", + "version": "0.0.31-next.1", "backstage": { "role": "frontend" }, diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index ec083df48f..1ae2c67448 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,113 @@ # example-app +## 0.2.117-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-import@0.13.9-next.0 + - @backstage/plugin-scaffolder@1.35.1-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.32-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/plugin-api-docs@0.13.3-next.0 + - @backstage/plugin-catalog-graph@0.5.5-next.0 + - @backstage/plugin-org@0.6.48-next.0 + - @backstage/plugin-user-settings@0.8.31-next.0 + - @backstage/plugin-home@0.8.16-next.0 + - @backstage/plugin-kubernetes@0.12.15-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.33-next.0 + - @backstage/plugin-search@1.5.2-next.0 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-devtools@0.1.35-next.0 + +## 0.2.117-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/plugin-mui-to-bui@0.2.3-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-app-api@0.13.3 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-devtools@0.1.34 + - @backstage/plugin-home@0.8.15 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-search-common@1.2.21 + - @backstage/plugin-search-react@1.10.1 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-techdocs-react@1.3.6 + - @backstage/plugin-user-settings@0.8.30 + +## 0.2.116 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-catalog-graph@0.5.4 + - @backstage/plugin-api-docs@0.13.2 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-search@1.5.1 + - @backstage/plugin-org@0.6.47 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.31 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes@0.12.14 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.24 + - @backstage/plugin-catalog-import@0.13.8 + - @backstage/plugin-notifications@0.5.12 + - @backstage/plugin-user-settings@0.8.30 + - @backstage/plugin-scaffolder@1.35.0 + - @backstage/plugin-devtools@0.1.34 + - @backstage/plugin-home@0.8.15 + - @backstage/theme@0.7.1 + - @backstage/plugin-kubernetes-cluster@0.0.32 + - @backstage/app-defaults@1.7.3 + - @backstage/frontend-app-api@0.13.3 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-mui-to-bui@0.2.2 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-signals@0.0.26 + - @backstage/plugin-techdocs-react@1.3.6 + ## 0.2.116-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 6e6f1dd52d..0c8096df9b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.116-next.2", + "version": "0.2.117-next.1", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index e610d6ef77..398a515fd8 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/backend-app-api +## 1.4.0 + +### Minor Changes + +- 5a2d538: Introduced backend startup result tracking and error handling. The `Backend.start()` method now returns a `BackendStartupResult` with detailed success/failure status and timing information for all plugins and modules. When startup fails, a `BackendStartupError` is thrown that includes the complete startup results, making it easier to diagnose which plugins or modules failed. + + This also improves the default error message when backend startup fails, and of course makes it possible to craft your own custom error reporting based on the startup results. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 1.4.0-next.1 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 36db7175b6..f510dc0832 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "1.4.0-next.1", + "version": "1.4.0", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 603a66f6f1..dea4639dfd 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,101 @@ # @backstage/backend-defaults +## 0.14.1-next.1 + +### Patch Changes + +- 3afeab4: Implementing `readTree` for `GoogleGcsReader` +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.14.1-next.0 + +### Patch Changes + +- 7126bf2: Fixed a spelling mistake in root health service shutdown response. +- Updated dependencies + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-dev-utils@0.1.6 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/integration-aws-node@0.1.19 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + +## 0.14.0 + +### Minor Changes + +- fa43826: Move `better-sqlite3` from dependencies to peer dependencies +- 2bc4e02: **BREAKING** The correct configuration options for Valkey are now being used. + + These changes are **required** to `app-config.yaml`: + + ```diff + backend: + cache: + store: valkey + connection: ... + client: + - namespace: 'my-app' + - keyPrefixSeparator: ':' + + keyPrefix: 'my-app:' + - clearBatchSize: 1000 + - useUnlink: false + ``` + + In comparison to Redis, Valkey requires the full `keyPrefix` including the separator to be specified instead of separate `namespace` and `keyPrefixSeparator` options. Also, Valkey does not support the `clearBatchSize` and `useUnlink` options. + +### Patch Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- aa79251: build(deps): bump `node-forge` from 1.3.1 to 1.3.2 +- f96edff: Allow configuration of the `referrerPolicy` +- fb029b6: Updated luxon types +- d9759a1: **BREAKING ALPHA**: The old `instanceMetadataService` has been removed from alpha. Please switch over to using the stable `coreServices.rootInstanceMetadata` and related types instead, available from `@backstage/backend-plugin-api`. +- 847a330: Fix for `jose` types +- 25b560e: Internal change to support new versions of the `logform` library +- 2a0c4b0: Adds a new experimental `RootSystemMetadataService` for tracking the collection of Backstage instances that may be deployed at any one time. It currently offers a single API, `getInstalledPlugins` that returns a list of installed plugins based on config you have set up in `discovery.endpoints` as well as the plugins installed on the instance you're calling the API with. It does not handle wildcard values or fallback values. The intention is for this plugin to provide plugin authors with a simple interface to fetch a trustworthy list of all installed plugins. +- 3016a79: Updated dependency `@types/archiver` to `^7.0.0`. +- 42db6a6: Don't warn when parsing `storeOptions` for `memory` cache +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/integration@1.19.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + - @backstage/backend-dev-utils@0.1.6 + ## 0.14.0-next.1 ### Patch Changes diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index 6131169d6b..8095e24660 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -710,27 +710,9 @@ export interface Config { */ client?: { /** - * Namespace for the current instance. + * Namespace and separator used for prefixing keys. */ - namespace?: string; - /** - * Separator to use between namespace and key. - */ - keyPrefixSeparator?: string; - /** - * Number of keys to delete in a single batch. - */ - clearBatchSize?: number; - /** - * Enable Unlink instead of using Del for clearing keys. This is more performant but may not be supported by all Redis versions. - */ - useUnlink?: boolean; - /** - * Whether to allow clearing all keys when no namespace is set. - * If set to true and no namespace is set, iterate() will return all keys. - * Defaults to `false`. - */ - noNamespaceAffectsAll?: boolean; + keyPrefix?: string; }; /** * An optional Valkey cluster (redis cluster under the hood) configuration. diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 96b96f1bf7..84df549e6a 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.14.0-next.1", + "version": "0.14.1-next.1", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts index a308caa222..323ca881c5 100644 --- a/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts @@ -336,11 +336,17 @@ describe('CacheManager store options', () => { it('correctly applies namespace configuration to redis and valkey stores', () => { const testCases = [ - { store: 'redis', namespace: 'test1', separator: ':' }, - { store: 'valkey', namespace: 'test2', separator: '!' }, + { + store: 'redis', + client: { + namespace: 'my-app', + keyPrefixSeparator: ':', + }, + }, + { store: 'valkey', client: { keyPrefix: 'my-app:' } }, ]; - testCases.forEach(({ store, namespace, separator }) => { + testCases.forEach(({ store, client }) => { const manager = CacheManager.fromConfig( mockServices.rootConfig({ data: { @@ -349,10 +355,7 @@ describe('CacheManager store options', () => { store, connection: 'redis://localhost:6379', [store]: { - client: { - namespace, - keyPrefixSeparator: separator, - }, + client, }, }, }, @@ -364,16 +367,16 @@ describe('CacheManager store options', () => { if (store === 'redis') { // eslint-disable-next-line jest/no-conditional-expect - expect(KeyvRedis).toHaveBeenCalledWith('redis://localhost:6379', { - namespace, - keyPrefixSeparator: separator, - }); + expect(KeyvRedis).toHaveBeenCalledWith( + 'redis://localhost:6379', + client, + ); } else if (store === 'valkey') { // eslint-disable-next-line jest/no-conditional-expect - expect(KeyvValkey).toHaveBeenCalledWith('redis://localhost:6379', { - namespace, - keyPrefixSeparator: separator, - }); + expect(KeyvValkey).toHaveBeenCalledWith( + 'redis://localhost:6379', + client, + ); } }); }); @@ -408,21 +411,31 @@ describe('CacheManager store options', () => { expect(result).toBe('testPlugin'); }); - it('returns pluginId when store options have no namespace', () => { - const storeOptions = { - client: { - keyPrefixSeparator: ':', - }, - }; - const result = (CacheManager as any).constructNamespace( - 'testPlugin', - storeOptions, - ); - expect(result).toBe('testPlugin'); - }); + it.each([ + { + type: 'redis', + field: 'namespace', + client: { keyPrefixSeparator: ':' }, + }, + { type: 'valkey', field: 'keyPrefix', client: {} }, + ])( + 'returns pluginId when store options have no $field for $type', + ({ type, client }) => { + const storeOptions = { + type, + client, + }; + const result = (CacheManager as any).constructNamespace( + 'testPlugin', + storeOptions, + ); + expect(result).toBe('testPlugin'); + }, + ); - it('combines namespace and pluginId with default separator', () => { + it('combines namespace and pluginId with default separator for redis', () => { const storeOptions = { + type: 'redis', client: { namespace: 'my-app', keyPrefixSeparator: ':', @@ -435,8 +448,9 @@ describe('CacheManager store options', () => { expect(result).toBe('my-app:testPlugin'); }); - it('combines namespace and pluginId with custom separator', () => { + it('combines namespace and pluginId with custom separator for redis', () => { const storeOptions = { + type: 'redis', client: { namespace: 'my-app', keyPrefixSeparator: '-', @@ -449,8 +463,9 @@ describe('CacheManager store options', () => { expect(result).toBe('my-app-testPlugin'); }); - it('uses default separator when keyPrefixSeparator is not provided', () => { + it('uses default separator when keyPrefixSeparator is not provided for redis', () => { const storeOptions = { + type: 'redis', client: { namespace: 'my-app', }, @@ -462,6 +477,20 @@ describe('CacheManager store options', () => { expect(result).toBe('my-app:testPlugin'); }); + it('uses keyPrefix for valkey', () => { + const storeOptions = { + type: 'valkey', + client: { + keyPrefix: 'my-app:', + }, + }; + const result = (CacheManager as any).constructNamespace( + 'testPlugin', + storeOptions, + ); + expect(result).toBe('my-app:testPlugin'); + }); + it('handles empty namespace by falling back to pluginId', () => { const storeOptions = { client: { diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts index 428a4b7592..38c0c761ed 100644 --- a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts @@ -29,6 +29,7 @@ import { RedisCacheStoreOptions, InfinispanClientBehaviorOptions, InfinispanServerConfig, + ValkeyCacheStoreOptions, } from './types'; import { InfinispanOptionsMapper } from './providers/infinispan/InfinispanOptionsMapper'; import { durationToMilliseconds } from '@backstage/types'; @@ -140,37 +141,32 @@ export class CacheManager { ); } - if (store === 'redis' || store === 'valkey') { - return CacheManager.parseRedisOptions( - store, - storeConfigPath, - config, - logger, - ); + switch (store) { + case 'redis': + return CacheManager.parseRedisOptions(storeConfigPath, config, logger); + case 'valkey': + return CacheManager.parseValkeyOptions(storeConfigPath, config, logger); + case 'infinispan': + return InfinispanOptionsMapper.parseInfinispanOptions( + storeConfigPath, + config, + logger, + ); + default: + return undefined; } - - if (store === 'infinispan') { - return InfinispanOptionsMapper.parseInfinispanOptions( - storeConfigPath, - config, - logger, - ); - } - - return undefined; } /** * Parse Redis-specific options from configuration. */ private static parseRedisOptions( - store: string, storeConfigPath: string, config: RootConfigService, logger?: LoggerService, ): RedisCacheStoreOptions { const redisOptions: RedisCacheStoreOptions = { - type: store as 'redis' | 'valkey', + type: 'redis', }; const redisConfig = @@ -213,6 +209,51 @@ export class CacheManager { return redisOptions; } + /** + * Parse Valkey-specific options from configuration. + */ + private static parseValkeyOptions( + storeConfigPath: string, + config: RootConfigService, + logger?: LoggerService, + ): ValkeyCacheStoreOptions { + const valkeyOptions: ValkeyCacheStoreOptions = { + type: 'valkey', + }; + + const valkeyConfig = + config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({}); + + valkeyOptions.client = { + keyPrefix: valkeyConfig.getOptionalString('client.keyPrefix'), + }; + + if (valkeyConfig.has('cluster')) { + const clusterConfig = valkeyConfig.getConfig('cluster'); + + if (!clusterConfig.has('rootNodes')) { + logger?.warn( + `Valkey cluster config has no 'rootNodes' key, defaulting to non-clustered mode`, + ); + return valkeyOptions; + } + + valkeyOptions.cluster = { + rootNodes: clusterConfig.get('rootNodes'), + defaults: clusterConfig.getOptional('defaults'), + minimizeConnections: clusterConfig.getOptionalBoolean( + 'minimizeConnections', + ), + useReplicas: clusterConfig.getOptionalBoolean('useReplicas'), + maxCommandRedirections: clusterConfig.getOptionalNumber( + 'maxCommandRedirections', + ), + }; + } + + return valkeyOptions; + } + /** * Construct the full namespace based on the options and pluginId. * @@ -222,13 +263,23 @@ export class CacheManager { */ private static constructNamespace( pluginId: string, - storeOptions: RedisCacheStoreOptions | undefined, + storeOptions: RedisCacheStoreOptions | ValkeyCacheStoreOptions | undefined, ): string { - const prefix = storeOptions?.client?.namespace - ? `${storeOptions.client.namespace}${ - storeOptions.client.keyPrefixSeparator ?? ':' - }` - : ''; + let prefix: string; + switch (storeOptions?.type) { + case 'redis': + prefix = storeOptions?.client?.namespace + ? `${storeOptions.client.namespace}${ + storeOptions.client.keyPrefixSeparator ?? ':' + }` + : ''; + break; + case 'valkey': + prefix = storeOptions.client?.keyPrefix ?? ''; + break; + default: + prefix = ''; + } return `${prefix}${pluginId}`; } @@ -317,7 +368,9 @@ export class CacheManager { private createValkeyStoreFactory(): StoreFactory { const KeyvValkey = require('@keyv/valkey').default; - const { createCluster } = require('@keyv/valkey'); + // `@keyv/valkey` doesn't export a `createCluster` function, but is compatible with the one from `@keyv/redis` + // See https://keyv.org/docs/storage-adapters/valkey + const { createCluster } = require('@keyv/redis'); const stores: Record = {}; return (pluginId, defaultTtl) => { @@ -327,9 +380,7 @@ export class CacheManager { ); } if (!stores[pluginId]) { - const valkeyOptions = this.storeOptions?.client || { - keyPrefixSeparator: ':', - }; + const valkeyOptions = this.storeOptions?.client; if (this.storeOptions?.cluster) { // Create a Valkey cluster (Redis cluster under the hood) const cluster = createCluster(this.storeOptions?.cluster); diff --git a/packages/backend-defaults/src/entrypoints/cache/types.ts b/packages/backend-defaults/src/entrypoints/cache/types.ts index 522ab2ac3e..60e32e8618 100644 --- a/packages/backend-defaults/src/entrypoints/cache/types.ts +++ b/packages/backend-defaults/src/entrypoints/cache/types.ts @@ -17,6 +17,7 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import { HumanDuration, durationToMilliseconds } from '@backstage/types'; import { RedisClusterOptions, KeyvRedisOptions } from '@keyv/redis'; +import { KeyvValkeyOptions } from '@keyv/valkey'; /** * Options for Redis cache store. @@ -24,11 +25,22 @@ import { RedisClusterOptions, KeyvRedisOptions } from '@keyv/redis'; * @public */ export type RedisCacheStoreOptions = { - type: 'redis' | 'valkey'; + type: 'redis'; client?: KeyvRedisOptions; cluster?: RedisClusterOptions; }; +/** + * Options for Valkey cache store. + * + * @public + */ +export type ValkeyCacheStoreOptions = { + type: 'valkey'; + client?: KeyvValkeyOptions; + cluster?: RedisClusterOptions; +}; + /** * Union type of all cache store options. * @@ -36,6 +48,7 @@ export type RedisCacheStoreOptions = { */ export type CacheStoreOptions = | RedisCacheStoreOptions + | ValkeyCacheStoreOptions | InfinispanCacheStoreOptions; /** diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index ca9085273c..4a5db18f6f 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -69,7 +69,7 @@ describe('DefaultRootHealthService', () => { await expect(service.getReadiness()).resolves.toEqual({ status: 503, payload: { - message: 'Backend is shuttting down', + message: 'Backend is shutting down', status: 'error', }, }); diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index e7255610bc..52812fc6b1 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -50,7 +50,7 @@ export class DefaultRootHealthService implements RootHealthService { if (this.#state === 'down') { return { status: 503, - payload: { message: 'Backend is shuttting down', status: 'error' }, + payload: { message: 'Backend is shutting down', status: 'error' }, }; } diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts index 8f8d1b7656..e9982bc589 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts @@ -285,7 +285,7 @@ describe('rootHttpRouterServiceFactory', () => { // Immediately start failing the readiness health check await request(app).get('/.backstage/health/v1/readiness').expect(503, { - message: 'Backend is shuttting down', + message: 'Backend is shutting down', status: 'error', }); @@ -301,7 +301,7 @@ describe('rootHttpRouterServiceFactory', () => { .expect(200, { status: 'ok' }); await request(app).get('/.backstage/health/v1/readiness').expect(503, { - message: 'Backend is shuttting down', + message: 'Backend is shutting down', status: 'error', }); @@ -312,7 +312,7 @@ describe('rootHttpRouterServiceFactory', () => { .expect(200, { status: 'ok' }); await request(app).get('/.backstage/health/v1/readiness').expect(503, { - message: 'Backend is shuttting down', + message: 'Backend is shutting down', status: 'error', }); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts index ff6ec3bb27..73302d37e5 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts @@ -68,7 +68,15 @@ export class BitbucketCloudUrlReader implements UrlReaderService { ) { this.integration = integration; this.deps = deps; - const { host, username, appPassword, token } = integration.config; + const { host, username, appPassword, token, clientId, clientSecret } = + integration.config; + + // Validate: OAuth requires both clientId and clientSecret + if ((clientId && !clientSecret) || (clientSecret && !clientId)) { + throw new Error( + `Bitbucket Cloud integration has incomplete OAuth configuration. Both clientId and clientSecret are required.`, + ); + } if (username && !token && !appPassword) { throw new Error( @@ -91,7 +99,7 @@ export class BitbucketCloudUrlReader implements UrlReaderService { url, this.integration.config, ); - const requestOptions = getBitbucketCloudRequestOptions( + const requestOptions = await getBitbucketCloudRequestOptions( this.integration.config, ); @@ -149,7 +157,7 @@ export class BitbucketCloudUrlReader implements UrlReaderService { ); const archiveResponse = await fetch( downloadUrl, - getBitbucketCloudRequestOptions(this.integration.config), + await getBitbucketCloudRequestOptions(this.integration.config), ); if (!archiveResponse.ok) { const message = `Failed to read tree from ${url}, ${archiveResponse.status} ${archiveResponse.statusText}`; @@ -250,7 +258,7 @@ export class BitbucketCloudUrlReader implements UrlReaderService { const commitsResponse = await fetch( commitsApiUrl, - getBitbucketCloudRequestOptions(this.integration.config), + await getBitbucketCloudRequestOptions(this.integration.config), ); if (!commitsResponse.ok) { const message = `Failed to retrieve commits from ${commitsApiUrl}, ${commitsResponse.status} ${commitsResponse.statusText}`; diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.test.ts index 7429bae94f..52d9660632 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.test.ts @@ -23,12 +23,18 @@ import { UrlReaderPredicateTuple } from './types'; import packageinfo from '../../../../package.json'; import { mockServices } from '@backstage/backend-test-utils'; import { UrlReaderServiceReadUrlResponse } from '@backstage/backend-plugin-api'; +import { Readable } from 'stream'; const bucketGetFilesMock = jest.fn(); class Bucket { getFiles(query: any) { return bucketGetFilesMock(query); } + file(_name: string) { + return { + createReadStream: () => Readable.from(Buffer.from('mock content')), + }; + } } class Storage { bucket() { @@ -186,4 +192,56 @@ describe('GcsUrlReader', () => { expect((await data.files[0].content()).toString()).toEqual('content'); }); }); + + describe('readTree', () => { + const { reader } = createReader({ integrations: { googleGcs: {} } })[0]; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns files with relative paths', async () => { + const mockFile1 = { + name: 'prefix/file1.yaml', + metadata: { updated: '2024-01-01T00:00:00Z' }, + createReadStream: () => Readable.from(Buffer.from('content1')), + }; + const mockFile2 = { + name: 'prefix/subdir/file2.yaml', + metadata: { updated: '2024-01-02T00:00:00Z' }, + createReadStream: () => Readable.from(Buffer.from('content2')), + }; + bucketGetFilesMock.mockResolvedValue([[mockFile1, mockFile2]]); + + const result = await reader.readTree( + 'https://storage.cloud.google.com/bucket/prefix/', + ); + const files = await result.files(); + + expect(files).toHaveLength(2); + expect(files[0].path).toBe('file1.yaml'); + expect(files[1].path).toBe('subdir/file2.yaml'); + }); + + it('calls getFiles with correct prefix', async () => { + bucketGetFilesMock.mockResolvedValue([[]]); + + await reader.readTree( + 'https://storage.cloud.google.com/bucket/some/prefix/', + ); + + expect(bucketGetFilesMock).toHaveBeenCalledWith({ + autoPaginate: true, + prefix: 'some/prefix/', + }); + }); + + it('throws if readTree url contains glob pattern', async () => { + await expect( + reader.readTree('https://storage.cloud.google.com/bucket/path/*'), + ).rejects.toThrow( + 'GcsUrlReader readTree does not support glob patterns, use search instead', + ); + }); + }); }); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.ts index 0bc5add43f..a29b98eb51 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GoogleGcsUrlReader.ts @@ -17,22 +17,25 @@ import * as GoogleCloud from '@google-cloud/storage'; import { UrlReaderService, + UrlReaderServiceReadTreeOptions, UrlReaderServiceReadTreeResponse, UrlReaderServiceReadUrlOptions, UrlReaderServiceReadUrlResponse, UrlReaderServiceSearchOptions, UrlReaderServiceSearchResponse, } from '@backstage/backend-plugin-api'; -import { ReaderFactory } from './types'; +import { ReaderFactory, ReadTreeResponseFactory } from './types'; import getRawBody from 'raw-body'; import { GoogleGcsIntegrationConfig, readGoogleGcsIntegrationConfig, } from '@backstage/integration'; + import { Readable } from 'stream'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; import packageinfo from '../../../../package.json'; import { assertError } from '@backstage/errors'; +import { relative } from 'path/posix'; const GOOGLE_GCS_HOST = 'storage.cloud.google.com'; @@ -59,7 +62,7 @@ const parseURL = ( * @public */ export class GoogleGcsUrlReader implements UrlReaderService { - static factory: ReaderFactory = ({ config, logger }) => { + static factory: ReaderFactory = ({ config, logger, treeResponseFactory }) => { if (!config.has('integrations.googleGcs')) { return []; } @@ -83,20 +86,29 @@ export class GoogleGcsUrlReader implements UrlReaderService { userAgent: `backstage/backend-defaults.GoogleGcsUrlReader/${packageinfo.version}`, }); } - const reader = new GoogleGcsUrlReader(gcsConfig, storage); + const reader = new GoogleGcsUrlReader(gcsConfig, storage, { + treeResponseFactory, + }); const predicate = (url: URL) => url.host === GOOGLE_GCS_HOST; return [{ reader, predicate }]; }; private readonly integration: GoogleGcsIntegrationConfig; private readonly storage: GoogleCloud.Storage; + private readonly deps: { + treeResponseFactory: ReadTreeResponseFactory; + }; constructor( integration: GoogleGcsIntegrationConfig, storage: GoogleCloud.Storage, + deps: { + treeResponseFactory: ReadTreeResponseFactory; + }, ) { this.integration = integration; this.storage = storage; + this.deps = deps; } private readStreamFromUrl(url: string): Readable { @@ -121,8 +133,32 @@ export class GoogleGcsUrlReader implements UrlReaderService { return ReadUrlResponseFactory.fromReadable(stream); } - async readTree(): Promise { - throw new Error('GcsUrlReader does not implement readTree'); + async readTree( + url: string, + _options?: UrlReaderServiceReadTreeOptions, + ): Promise { + const { bucket, key } = parseURL(url); + + if (key.match(/[*?]/)) { + throw new Error( + 'GcsUrlReader readTree does not support glob patterns, use search instead', + ); + } + + const [files] = await this.storage.bucket(bucket).getFiles({ + autoPaginate: true, + prefix: key, + }); + + const responses = files.map(file => ({ + data: file.createReadStream(), + path: relative(key, file.name), + lastModifiedAt: file.metadata.updated + ? new Date(file.metadata.updated as string) + : undefined, + })); + + return this.deps.treeResponseFactory.fromReadableArray(responses); } async search( diff --git a/packages/backend-dev-utils/CHANGELOG.md b/packages/backend-dev-utils/CHANGELOG.md index 4b89697ee8..d5884588fb 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.6 + +### Patch Changes + +- 2bae83a: Internal update for Node.js v24 support. + ## 0.1.6-next.0 ### Patch Changes diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json index 3eb9c05993..ba46f4b36e 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.6-next.0", + "version": "0.1.6", "backstage": { "role": "node-library" }, diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index aec27109a6..b98fa78082 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,60 @@ # @backstage/backend-dynamic-feature-service +## 0.7.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-catalog-backend@3.3.1-next.1 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.7.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.40 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-events-backend@0.5.10-next.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-search-common@1.2.21 + +## 0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-app-node@0.1.40 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-backend@0.5.9 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.7.7-next.1 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index 416cbfdc1e..1cabe17923 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dynamic-feature-service", - "version": "0.7.7-next.1", + "version": "0.7.8-next.1", "description": "Backstage dynamic feature service", "backstage": { "role": "node-library" diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 2fb0b39cbd..f90fecb9cc 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/backend-openapi-utils +## 0.6.5-next.0 + +### Patch Changes + +- 6678b78: Internal update to use native feature from our request validation library for handling base path determination. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## 0.6.4 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 0.6.4-next.1 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 715c1ddbcb..5efffd1c55 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-openapi-utils", - "version": "0.6.4-next.1", + "version": "0.6.5-next.0", "description": "OpenAPI typescript support.", "backstage": { "role": "node-library" diff --git a/packages/backend-openapi-utils/src/stub.ts b/packages/backend-openapi-utils/src/stub.ts index 8ab00c4df4..717e2ae19b 100644 --- a/packages/backend-openapi-utils/src/stub.ts +++ b/packages/backend-openapi-utils/src/stub.ts @@ -31,13 +31,6 @@ import { middleware as OpenApiValidator } from 'express-openapi-validator'; import { OPENAPI_SPEC_ROUTE } from './constants'; import { isErrorResult, merge } from 'openapi-merge'; -type PropertyOverrideRequest = Request & { - [key: symbol]: string; -}; - -const baseUrlSymbol = Symbol(); -const originalUrlSymbol = Symbol(); - function validatorErrorTransformer(): ErrorRequestHandler { return (error: Error, _: Request, _2: Response, next: NextFunction) => { next(new InputError(error.message)); @@ -75,30 +68,6 @@ function createRouterWithValidation( const router = PromiseRouter(); router.use(options?.middleware || getDefaultRouterMiddleware()); - /** - * Middleware to setup the routing for OpenApiValidator. OpenApiValidator expects `req.originalUrl` - * and `req.baseUrl` to be the full path. We adjust them here to basically be nothing and then - * revive the old values in the last function in this method. We could instead update `req.path` - * but that might affect the routing and I'd rather not. - * - * TODO: I opened https://github.com/cdimascio/express-openapi-validator/issues/843 - * to track this on the middleware side, but there was a similar ticket, https://github.com/cdimascio/express-openapi-validator/issues/113 - * that has had minimal activity. If that changes, update this to use a new option on their side. - */ - router.use((req: Request, _, next) => { - /** - * Express typings are weird. They don't recognize PropertyOverrideRequest as a valid - * Request child and try to overload as PathParams. Just cast it here, since we know - * what we're doing. - */ - const customRequest = req as PropertyOverrideRequest; - customRequest[baseUrlSymbol] = customRequest.baseUrl; - customRequest.baseUrl = ''; - customRequest[originalUrlSymbol] = customRequest.originalUrl; - customRequest.originalUrl = customRequest.url; - next(); - }); - // TODO: Handle errors by converting from OpenApiValidator errors to known @backstage/errors errors. router.use( OpenApiValidator({ @@ -106,6 +75,7 @@ function createRouterWithValidation( coerceTypes: false, allowUnknownQueryParameters: false, }, + useRequestUrl: true, ignoreUndocumented: true, validateResponses: false, ...options?.validatorOptions, @@ -113,19 +83,6 @@ function createRouterWithValidation( }), ); - /** - * Revert `req.baseUrl` and `req.originalUrl` changes. This ensures that any further usage - * of these variables will be unchanged. - */ - router.use((req: Request, _, next) => { - const customRequest = req as PropertyOverrideRequest; - customRequest.baseUrl = customRequest[baseUrlSymbol]; - customRequest.originalUrl = customRequest[originalUrlSymbol]; - delete customRequest[baseUrlSymbol]; - delete customRequest[originalUrlSymbol]; - next(); - }); - // Any errors from the middleware get through here. router.use(validatorErrorTransformer()); diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 84ad95d700..83d63fa97a 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/backend-plugin-api +## 1.6.0 + +### Minor Changes + +- 2a0c4b0: Adds a new experimental `RootSystemMetadataService` for tracking the collection of Backstage instances that may be deployed at any one time. It currently offers a single API, `getInstalledPlugins` that returns a list of installed plugins based on config you have set up in `discovery.endpoints` as well as the plugins installed on the instance you're calling the API with. It does not handle wildcard values or fallback values. The intention is for this plugin to provide plugin authors with a simple interface to fetch a trustworthy list of all installed plugins. + +### Patch Changes + +- d9759a1: **BREAKING ALPHA**: The old `instanceMetadataService` has been removed from alpha. Please switch over to using the stable `coreServices.rootInstanceMetadata` and related types instead, available from `@backstage/backend-plugin-api`. +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/cli-common@0.1.16 + ## 1.6.0-next.1 ### Minor Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index c26c0ce1de..4867fcd0a4 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "1.6.0-next.1", + "version": "1.6.0", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 921eac9383..ca456b8491 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/backend-test-utils +## 1.10.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + +## 1.10.2 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 8be23a4: Switched `textextensions` dependency for `text-extensions`. +- 5a737e1: Fix PostgreSQL 18 `TestDatabases` by pinning the data directory +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-app-api@1.4.0 + - @backstage/backend-plugin-api@1.6.0 + ## 1.10.2-next.1 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 08b5da6630..1f6df8457d 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "1.10.2-next.1", + "version": "1.10.3-next.0", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index dc0f2fc708..b3eab5806b 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,102 @@ # example-backend +## 0.0.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-techdocs-backend@2.1.4-next.1 + - @backstage/plugin-catalog-backend@3.3.1-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.18-next.0 + - @backstage/plugin-scaffolder-backend@3.1.1-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.9.4-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.16-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.18-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.10-next.0 + +## 0.0.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-app-backend@0.5.9 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-auth-backend-module-github-provider@0.4.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.15 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.3 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.10-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.7 + - @backstage/plugin-devtools-backend@0.5.13-next.0 + - @backstage/plugin-events-backend@0.5.10-next.0 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.7 + - @backstage/plugin-kubernetes-backend@0.21.0 + - @backstage/plugin-mcp-actions-backend@0.1.7-next.0 + - @backstage/plugin-notifications-backend@0.6.1 + - @backstage/plugin-permission-backend@0.7.7 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.15 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-proxy-backend@0.6.9 + - @backstage/plugin-scaffolder-backend@3.1.1-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.17 + - @backstage/plugin-search-backend@2.0.10-next.0 + - @backstage/plugin-search-backend-module-catalog@0.3.11 + - @backstage/plugin-search-backend-module-elasticsearch@1.7.9 + - @backstage/plugin-search-backend-module-explore@0.3.10 + - @backstage/plugin-search-backend-module-techdocs@0.4.9 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-signals-backend@0.3.11 + - @backstage/plugin-techdocs-backend@2.1.4-next.0 + +## 0.0.45 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-mcp-actions-backend@0.1.6 + - @backstage/plugin-scaffolder-backend@3.1.0 + - @backstage/plugin-search-backend-node@1.4.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-app-backend@0.5.9 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.15 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.3 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-devtools-backend@0.5.12 + - @backstage/plugin-events-backend@0.5.9 + - @backstage/plugin-kubernetes-backend@0.21.0 + - @backstage/plugin-notifications-backend@0.6.1 + - @backstage/plugin-permission-backend@0.7.7 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-proxy-backend@0.6.9 + - @backstage/plugin-search-backend@2.0.9 + - @backstage/plugin-signals-backend@0.3.11 + - @backstage/plugin-techdocs-backend@2.1.3 + - @backstage/plugin-auth-backend-module-github-provider@0.4.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-search-backend-module-explore@0.3.10 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.9 + - @backstage/plugin-catalog-backend-module-openapi@0.2.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.7 + - @backstage/plugin-events-backend-module-google-pubsub@0.1.7 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.15 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.17 + - @backstage/plugin-search-backend-module-catalog@0.3.11 + - @backstage/plugin-search-backend-module-elasticsearch@1.7.9 + - @backstage/plugin-search-backend-module-techdocs@0.4.9 + ## 0.0.45-next.1 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 10a2eeded3..918d809d2e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.45-next.1", + "version": "0.0.46-next.1", "backstage": { "role": "backend" }, diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index 145e04ddb3..a8e4872744 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/cli-common +## 0.1.16 + +### Patch Changes + +- 5cfb2a4: Added new `run`, `runOutput`, and `runCheck` utilities to help run child processes in a safe and portable way. +- c8c2329: Add proxy configuration from env-vars to create-app tasks +- 2bae83a: Bumped dev dependencies `@types/node` + ## 0.1.16-next.2 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 80857bffff..0ab0a9f1fd 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-common", - "version": "0.1.16-next.2", + "version": "0.1.16", "description": "Common functionality used by cli, backend, and create-app", "backstage": { "role": "node-library" diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index 4c4005c0c9..bdacd69297 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/cli-node +## 0.2.16 + +### Patch Changes + +- 4e8c726: Updated to use new utilities from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.1.16 + ## 0.2.16-next.1 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index dcedc6b76c..52242bdd48 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.16-next.1", + "version": "0.2.16", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6dd279fadb..03f4533e4c 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,85 @@ # @backstage/cli +## 0.35.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.35.2-next.0 + +### Patch Changes + +- 320c6a9: Bump `@swc/core` to support `ES2023` and `ES2024` +- 9ee5996: Bump minimum required `@swc/core` to avoid transpilation bug +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/cli-common@0.1.16 + - @backstage/cli-node@0.2.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/eslint-plugin@0.2.0 + - @backstage/integration@1.19.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.2 + +## 0.35.0 + +### Minor Changes + +- f6f22a9: Provide `--no-node-snapshot` by default when running the `package start` or `package test`. You can disable this behavior by providing `NODE_OPTIONS='--node-snapshot'`. +- f8dff94: Switched the default module resolution to `bundler` and the `module` setting to `ES2020`. + + You may need to bump some dependencies as part of this change and fix imports in code. The most common source of this is that type checking will now consider the `exports` field in `package.json` when resolving imports. This in turn can break older versions of packages that had incompatible `exports` fields. Generally these issues will have already been fixed in the upstream packages. + + You might be tempted to use `--skipLibCheck` to hide issues due to this change, but it will weaken the type safety of your project. If you run into a large number of issues and want to keep the old behavior, you can reset the `moduleResolution` and `module` settings your own `tsconfig.json` file to `node` and `ESNext` respectively. But keep in mind that the `node` option will be removed in future versions of TypeScript. + + A future version of Backstage will make these new settings mandatory, as we move to rely on the `exports` field for type resolution in packages, rather than the `typesVersions` field. + +- cd0b8a1: **BREAKING**: `jest` is now a peer dependency. If you run tests using Backstage CLI, you must add Jest and its environment dependencies as `devDependencies` in your project. + + You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed. + + - **Jest 29**: Install `jest@^29` and `jest-environment-jsdom@^29`. No migration needed, but you may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations. + - **Jest 30**: Install `jest@^30`, `@jest/environment-jsdom-abstract@^30`, and `jsdom@^27`. Fixes the stylesheet parsing warnings/errors, but requires migration steps. + + See the [Jest 30 migration guide](https://backstage.io/docs/tutorials/jest30-migration) for detailed migration instructions. + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- e7db290: Add missing peer/dev dependencies to the frontend plugin template. + + `react-dom` was not declared as a peer dependency, causing module resolution + errors when generating plugins outside a Backstage monorepo. This adds + `react-dom` to `peerDependencies` (for consuming apps) and `devDependencies` + (for local development). `react-router-dom` is also added to `peerDependencies` (for consuming apps) and `devDependencies` + to support routing during plugin development. + + Fixes: + + - Module not found: Can't resolve 'react-dom' + - Module not found: Can't resolve 'react-router-dom' + +- 1226647: Updated dependency `esbuild` to `^0.27.0`. +- f89a074: Updated dependency `@pmmmwh/react-refresh-webpack-plugin` to `^0.6.0`. +- 2b81751: Updated dependency `webpack` to `~5.103.0`. +- fafd9e1: Fixed internal usage of `yargs`. +- c8c2329: Add proxy configuration from env-vars to create-app tasks +- 2bae83a: Switched compilation target to ES2022 in order to match the new set of supported Node.js versions, which are 22 and 24. + + The TypeScript compilation target has been set to ES2022, because setting it to a higher target will break projects on older TypeScript versions. If you use a newer TypeScript version in your own project, you can bump `compilerOptions.target` to ES2023 or ES2024 in your own `tsconfig.json` file. + +- 7fbac5c: Updated to use new utilities from `@backstage/cli-common`. +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/integration@1.19.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + ## 0.35.0-next.2 ### Minor Changes diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index a8df5242ad..26bd89e909 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -324,7 +324,7 @@ Options: ### `backstage-cli package test` ``` -Usage: backstage-cli [--config=] [TestPathPattern] +Usage: backstage-cli [--config=] [TestPathPatterns] Options: --all @@ -349,7 +349,6 @@ Options: --debug --detectLeaks --detectOpenHandles - --env --errorOnDeprecated --filter --findRelatedTests @@ -359,7 +358,6 @@ Options: --globals --haste --ignoreProjects - --init --injectGlobals --json --lastCommit @@ -400,13 +398,13 @@ Options: --silent --skipFilter --snapshotSerializers - --testEnvironment + --testEnvironment, --env --testEnvironmentOptions --testFailureExitCode --testLocationInResults --testMatch --testPathIgnorePatterns - --testPathPattern + --testPathPatterns --testRegex --testResultsProcessor --testRunner @@ -418,6 +416,7 @@ Options: --useStderr --verbose --version + --waitForUnhandledRejections --watch --watchAll --watchPathIgnorePatterns diff --git a/packages/cli/config/getJestEnvironment.js b/packages/cli/config/getJestEnvironment.js new file mode 100644 index 0000000000..aac2f79021 --- /dev/null +++ b/packages/cli/config/getJestEnvironment.js @@ -0,0 +1,49 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function getJestMajorVersion() { + const jestVersion = require('jest/package.json').version; + const majorVersion = parseInt(jestVersion.split('.')[0], 10); + return majorVersion; +} + +function getJestEnvironment() { + const majorVersion = getJestMajorVersion(); + + if (majorVersion >= 30) { + try { + require.resolve('@jest/environment-jsdom-abstract'); + require.resolve('jsdom'); + } catch { + throw new Error( + 'Jest 30+ requires @jest/environment-jsdom-abstract and jsdom. ' + + 'Please install them as dev dependencies.', + ); + } + return require.resolve('./jest-environment-jsdom'); + } + try { + require.resolve('jest-environment-jsdom'); + } catch { + throw new Error( + 'Jest 29 requires jest-environment-jsdom. ' + + 'Please install it as a dev dependency.', + ); + } + return require.resolve('jest-environment-jsdom'); +} + +module.exports = { getJestMajorVersion, getJestEnvironment }; diff --git a/packages/cli/config/jest-environment-jsdom/index.js b/packages/cli/config/jest-environment-jsdom/index.js new file mode 100644 index 0000000000..9d8b76eaf5 --- /dev/null +++ b/packages/cli/config/jest-environment-jsdom/index.js @@ -0,0 +1,61 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const JSDOMEnvironment = require('@jest/environment-jsdom-abstract').default; +const jsdom = require('jsdom'); + +/** + * A custom JSDOM environment that extends the abstract base and applies + * fixes for Web API globals that are missing or incorrectly implemented + * in JSDOM. + * + * Based on https://github.com/mswjs/jest-fixed-jsdom + */ +class FixedJSDOMEnvironment extends JSDOMEnvironment { + constructor(config, context) { + super(config, context, jsdom); + + // Fix Web API globals that JSDOM doesn't properly expose + this.global.TextDecoder = TextDecoder; + this.global.TextEncoder = TextEncoder; + this.global.TextDecoderStream = TextDecoderStream; + this.global.TextEncoderStream = TextEncoderStream; + this.global.ReadableStream = ReadableStream; + + this.global.Blob = Blob; + this.global.Headers = Headers; + this.global.FormData = FormData; + this.global.Request = Request; + this.global.Response = Response; + this.global.fetch = fetch; + this.global.AbortController = AbortController; + this.global.AbortSignal = AbortSignal; + this.global.structuredClone = structuredClone; + this.global.URL = URL; + this.global.URLSearchParams = URLSearchParams; + + this.global.BroadcastChannel = BroadcastChannel; + this.global.TransformStream = TransformStream; + this.global.WritableStream = WritableStream; + + // Needed to ensure `e instanceof Error` works as expected with errors thrown from + // any of the native APIs above. Without this, the JSDOM `Error` is what the test + // code will use for comparison with `e`, which fails the instanceof check. + this.global.Error = Error; + } +} + +module.exports = FixedJSDOMEnvironment; diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index f011d14b19..94e5b9c4a8 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -20,6 +20,10 @@ const crypto = require('crypto'); const glob = require('util').promisify(require('glob')); const { version } = require('../package.json'); const paths = require('@backstage/cli-common').findPaths(process.cwd()); +const { + getJestEnvironment, + getJestMajorVersion, +} = require('./getJestEnvironment'); const SRC_EXTS = ['ts', 'js', 'tsx', 'jsx', 'mts', 'cts', 'mjs', 'cjs']; @@ -211,7 +215,7 @@ function getRoleConfig(role, pkgJson) { }; if (FRONTEND_ROLES.includes(role)) { return { - testEnvironment: require.resolve('jest-environment-jsdom'), + testEnvironment: getJestEnvironment(), // The caching module loader is only used to speed up frontend tests, // as it breaks real dynamic imports of ESM modules. runtime: envOptions.oldTests @@ -279,7 +283,10 @@ async function getProjectConfig(targetPath, extraConfig, extraOptions) { ); } - if (options.testEnvironment === require.resolve('jest-environment-jsdom')) { + if ( + options.testEnvironment === getJestEnvironment() && + getJestMajorVersion() < 30 // Only needed when not running the custom env for Jest 30+ + ) { // FIXME https://github.com/jsdom/jsdom/issues/1724 options.setupFilesAfterEnv.unshift(require.resolve('cross-fetch/polyfill')); } diff --git a/packages/cli/config/jestCachingModuleLoader.js b/packages/cli/config/jestCachingModuleLoader.js index a3fdf106e9..5652ff67e7 100644 --- a/packages/cli/config/jestCachingModuleLoader.js +++ b/packages/cli/config/jestCachingModuleLoader.js @@ -14,6 +14,8 @@ * limitations under the License. */ +// 'jest-runtime' is included with jest and should be kept in sync with the installed jest version +// eslint-disable-next-line @backstage/no-undeclared-imports const { default: JestRuntime } = require('jest-runtime'); module.exports = class CachingJestRuntime extends JestRuntime { diff --git a/packages/cli/config/jestRejectNetworkRequests.js b/packages/cli/config/jestRejectNetworkRequests.js index de6b486809..ef577b3a22 100644 --- a/packages/cli/config/jestRejectNetworkRequests.js +++ b/packages/cli/config/jestRejectNetworkRequests.js @@ -22,7 +22,7 @@ const errorMessage = 'Network requests are not allowed in tests'; const origHttpAgent = http.globalAgent; const origHttpsAgent = https.globalAgent; const origFetch = global.fetch; -const origXMLHttpRequest = global.fetch; +const origXMLHttpRequest = global.XMLHttpRequest; http.globalAgent = new http.Agent({ lookup() { @@ -36,10 +36,21 @@ https.globalAgent = new https.Agent({ }, }); +const BLOCKING_FETCH_SYMBOL = Symbol.for( + 'backstage.jestRejectNetworkRequests.blockingFetch', +); + if (global.fetch) { - global.fetch = async () => { - throw new Error(errorMessage); + const blockingFetch = async (input, init) => { + // If global.fetch still has our marker, block the request + if (global.fetch[BLOCKING_FETCH_SYMBOL]) { + throw new Error(errorMessage); + } + // MSW (or something else) wrapped us - pass through + return origFetch(input, init); }; + blockingFetch[BLOCKING_FETCH_SYMBOL] = true; + global.fetch = blockingFetch; } if (global.XMLHttpRequest) { diff --git a/packages/cli/package.json b/packages/cli/package.json index c48b529551..fbefa70eff 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.35.0-next.2", + "version": "0.35.2-next.1", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" @@ -70,10 +70,9 @@ "@spotify/eslint-config-base": "^15.0.0", "@spotify/eslint-config-react": "^15.0.0", "@spotify/eslint-config-typescript": "^15.0.0", - "@swc/core": "^1.3.46", - "@swc/helpers": "^0.5.0", - "@swc/jest": "^0.2.22", - "@types/jest": "^29.5.11", + "@swc/core": "^1.15.6", + "@swc/helpers": "^0.5.17", + "@swc/jest": "^0.2.39", "@types/webpack-env": "^1.15.2", "@typescript-eslint/eslint-plugin": "^8.17.0", "@typescript-eslint/parser": "^8.16.0", @@ -109,11 +108,7 @@ "handlebars": "^4.7.3", "html-webpack-plugin": "^5.6.3", "inquirer": "^8.2.0", - "jest": "^29.7.0", - "jest-cli": "^29.7.0", "jest-css-modules": "^2.1.0", - "jest-environment-jsdom": "^29.0.2", - "jest-runtime": "^29.0.2", "json-schema": "^0.4.0", "lodash": "^4.17.21", "minimatch": "^9.0.0", @@ -167,6 +162,7 @@ "@backstage/plugin-scaffolder-node-test-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@backstage/theme": "workspace:^", + "@jest/environment-jsdom-abstract": "^30.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "@types/cross-spawn": "^6.0.2", "@types/ejs": "^3.1.3", @@ -174,6 +170,7 @@ "@types/fs-extra": "^11.0.0", "@types/http-proxy": "^1.17.4", "@types/inquirer": "^8.1.3", + "@types/jest": "^30.0.0", "@types/node": "^22.13.14", "@types/npm-packlist": "^3.0.0", "@types/recursive-readdir": "^2.2.0", @@ -188,6 +185,8 @@ "esbuild-loader": "^4.0.0", "eslint-webpack-plugin": "^4.2.0", "fork-ts-checker-webpack-plugin": "^9.0.0", + "jest": "^30.2.0", + "jsdom": "^27.1.0", "mini-css-extract-plugin": "^2.4.2", "msw": "^1.0.0", "nodemon": "^3.0.1", @@ -196,17 +195,24 @@ "webpack-dev-server": "^5.0.0" }, "peerDependencies": { + "@jest/environment-jsdom-abstract": "^30.0.0", "@module-federation/enhanced": "^0.9.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.6.0", "esbuild-loader": "^4.0.0", "eslint-webpack-plugin": "^4.2.0", "fork-ts-checker-webpack-plugin": "^9.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-environment-jsdom": "*", + "jsdom": "^27.1.0", "mini-css-extract-plugin": "^2.4.2", "terser-webpack-plugin": "^5.1.3", "webpack": "~5.103.0", "webpack-dev-server": "^5.0.0" }, "peerDependenciesMeta": { + "@jest/environment-jsdom-abstract": { + "optional": true + }, "@module-federation/enhanced": { "optional": true }, @@ -222,6 +228,12 @@ "fork-ts-checker-webpack-plugin": { "optional": true }, + "jest-environment-jsdom": { + "optional": true + }, + "jsdom": { + "optional": true + }, "mini-css-extract-plugin": { "optional": true }, diff --git a/packages/cli/src/modules/test/commands/package/test.ts b/packages/cli/src/modules/test/commands/package/test.ts index 72e78eae7b..992697d19c 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -91,5 +91,23 @@ export default async (_opts: OptionValues, cmd: Command) => { (process.stdout as any)._handle.setBlocking(true); } + // Because of the ongoing migration to v30 of jest, jest is no longer hard-depended to allow + // opt-in migration. Users instead need to add jest as a devDependency themselves and specify + // the version they want. This prints a helpful error message if jest is not found, i.e. they + // forgot/didn't know they had to add jest themselves. + try { + require.resolve('jest'); + } catch { + console.error( + [ + 'No Jest installation found in this project.', + '', + 'To support opt-in migration to Jest v30, the Backstage CLI now expects Jest to be installed as a devDependency.', + 'See the migration guide in the changelog for version options and their consequences.', + ].join('\n'), + ); + process.exit(1); + } + await require('jest').run(args); }; diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index 40e6666dcf..2288d13476 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -17,6 +17,8 @@ import os from 'os'; import crypto from 'node:crypto'; import yargs from 'yargs'; +// 'jest-cli' is included with jest and should be kept in sync with the installed jest version +// eslint-disable-next-line @backstage/no-undeclared-imports import { run as runJest, yargsOptions as jestYargsOptions } from 'jest-cli'; import { relative as relativePath } from 'path'; import { Command, OptionValues } from 'commander'; diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 3f85216f69..22dd2a5df7 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/codemods +## 0.1.53 + +### Patch Changes + +- 688f070: Updated to use new utilities from `@backstage/cli-common`. +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.16 + ## 0.1.53-next.2 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 1a84ba417a..01f5ae9168 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/codemods", - "version": "0.1.53-next.2", + "version": "0.1.53", "description": "A collection of codemods for Backstage projects", "backstage": { "role": "cli" diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 7055741def..84ad0e04a1 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/config-loader +## 1.10.7 + +### Patch Changes + +- 741c47a: Updated dependency `typescript-json-schema` to `^0.67.0`. +- Updated dependencies + - @backstage/cli-common@0.1.16 + ## 1.10.7-next.1 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index bedbbff518..e48723e5f7 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config-loader", - "version": "1.10.7-next.1", + "version": "1.10.7", "description": "Config loading functionality used by Backstage backend, and CLI", "backstage": { "role": "node-library" @@ -57,7 +57,7 @@ "@backstage/cli": "workspace:^", "@types/json-schema-merge-allof": "^0.6.0", "@types/minimist": "^1.2.5", - "msw": "^1.0.0", + "msw": "^2.0.0", "zen-observable": "^0.10.0" } } diff --git a/packages/config-loader/src/loader.test.ts b/packages/config-loader/src/loader.test.ts index 8908b4268b..ea226aa557 100644 --- a/packages/config-loader/src/loader.test.ts +++ b/packages/config-loader/src/loader.test.ts @@ -17,7 +17,7 @@ import { AppConfig } from '@backstage/config'; import { loadConfig } from './loader'; import fs from 'fs-extra'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { createDeferred } from '@backstage/types'; @@ -74,32 +74,28 @@ describe('loadConfig', () => { }); const server = setupServer(); - const initialLoaderHandler = rest.get( + const initialLoaderHandler = http.get( `https://some.domain.io/app-config.yaml`, - (_req, res, ctx) => { - return res( - ctx.body( - `app: + () => { + return new HttpResponse( + `app: title: Remote Example App sessionKey: 'abc123' escaped: \$\${Escaped} `, - ), ); }, ); - const reloadHandler = rest.get( + const reloadHandler = http.get( `https://some.domain.io/app-config.yaml`, - (_req, res, ctx) => { - return res( - ctx.body( - `app: + () => { + return new HttpResponse( + `app: title: NEW ReMOTe ExaMPLe App sessionKey: 'abc123' escaped: \$\${Escaped} `, - ), ); }, ); diff --git a/packages/config-loader/src/schema/collect.test.ts b/packages/config-loader/src/schema/collect.test.ts index d48c98fbe4..a732d982d3 100644 --- a/packages/config-loader/src/schema/collect.test.ts +++ b/packages/config-loader/src/schema/collect.test.ts @@ -15,14 +15,9 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; -import { collectConfigSchemas } from './collect'; +import { collectConfigSchemas, internal } from './collect'; import path from 'path'; - -// cwd must be restored -const origDir = process.cwd(); -afterAll(() => { - process.chdir(origDir); -}); +import { execSync } from 'child_process'; const mockSchema = { type: 'object', @@ -37,6 +32,36 @@ const mockSchema = { describe('collectConfigSchemas', () => { const mockDir = createMockDirectory(); + // Jest 30's module resolver doesn't find nested node_modules in mock directories. + // Use a child process for native Node.js resolution instead. + const originalResolvePackagePath = internal.resolvePackagePath; + beforeAll(() => { + internal.resolvePackagePath = (name, options) => { + const basePath = (options && options.paths?.[0]) ?? process.cwd(); + const baseDir = basePath.endsWith('.json') + ? path.dirname(basePath) + : basePath; + + try { + return execSync('node', { + input: `console.log(require.resolve(${JSON.stringify( + name, + )}, { paths: [${JSON.stringify(baseDir)}] }))`, + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + }).trim(); + } catch { + const error = new Error(`Cannot find module '${name}'`); + (error as NodeJS.ErrnoException).code = 'MODULE_NOT_FOUND'; + throw error; + } + }; + }); + + afterAll(() => { + internal.resolvePackagePath = originalResolvePackagePath; + }); + afterEach(() => { mockDir.clear(); }); diff --git a/packages/config-loader/src/schema/collect.ts b/packages/config-loader/src/schema/collect.ts index 16bd654946..5f4e54387d 100644 --- a/packages/config-loader/src/schema/collect.ts +++ b/packages/config-loader/src/schema/collect.ts @@ -37,6 +37,17 @@ const req = ? require : __non_webpack_require__; +/** + * Exported for test mocking. Jest 30's module resolver has issues with + * nested node_modules, requiring tests to use an alternative resolution strategy. + * @internal + */ +export const internal = { + resolvePackagePath(name: string, options?: { paths: string[] }): string { + return req.resolve(name, options); + }, +}; + /** * This collects all known config schemas across all dependencies of the app. */ @@ -62,11 +73,9 @@ export async function collectConfigSchemas( const { name, parentPath } = item; try { - pkgPath = req.resolve( + pkgPath = internal.resolvePackagePath( `${name}/package.json`, - parentPath && { - paths: [parentPath], - }, + parentPath ? { paths: [parentPath] } : undefined, ); } catch { // We can somewhat safely ignore packages that don't export package.json, diff --git a/packages/config-loader/src/sources/RemoteConfigSource.test.ts b/packages/config-loader/src/sources/RemoteConfigSource.test.ts index 372dc91823..acb5870c7d 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.test.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; import { RemoteConfigSource } from './RemoteConfigSource'; @@ -26,15 +26,15 @@ describe('RemoteConfigSource', () => { it('should load config from a remote URL', async () => { worker.use( - rest.get('http://localhost/config.yaml', (_req, res, ctx) => - res( - ctx.body(` + http.get( + 'http://localhost/config.yaml', + () => + new HttpResponse(` app: title: Example App substituted: \${VALUE} escaped: \$\${VALUE} `), - ), ), ); @@ -61,9 +61,10 @@ app: it('should load and parse config from a remote URL', async () => { worker.use( - rest.get('http://localhost/config.json', (_req, res, ctx) => - res( - ctx.body( + http.get( + 'http://localhost/config.json', + () => + new HttpResponse( JSON.stringify({ app: { title: 'Example App', @@ -72,7 +73,6 @@ app: }, }), ), - ), ), ); @@ -102,12 +102,12 @@ app: let fetched = false; worker.use( - rest.get('http://localhost/config.yaml', (_req, res, ctx) => { + http.get('http://localhost/config.yaml', () => { if (!fetched) { fetched = true; - return res(ctx.body('x: 1')); + return new HttpResponse('x: 1'); } - return res(ctx.body('x: 2')); + return new HttpResponse('x: 2'); }), ); diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 19720d0c7e..2b2dbeccfd 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/core-app-api +## 1.19.3 + +### Patch Changes + +- 75683ed: Added replay functionality to `AlertApiForwarder` to buffer and replay recent alerts to new subscribers, preventing missed alerts that were posted before subscription. +- 97cd16f: Internal update of translation imports. +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + ## 1.19.3-next.1 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 70670fa27d..cd56c90ce8 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-app-api", - "version": "1.19.3-next.1", + "version": "1.19.3", "description": "Core app API used by Backstage apps", "backstage": { "role": "web-library" diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts index bd82d58736..2b2545f52f 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts @@ -60,12 +60,6 @@ describe('PluginProtocolResolverFetchMiddleware', () => { 'https://real.com:8080/base', 'https://real.com:8080/base?c=d&e=f#g', ], - [ - 'plugin://username:password@x?c=d&e=f#g', - 'x', - 'https://real.com:8080/base', - 'https://username:password@real.com:8080/base?c=d&e=f#g', - ], [ 'plugin://x?c=d&e=f#g', 'x', @@ -106,14 +100,14 @@ describe('PluginProtocolResolverFetchMiddleware', () => { expect(inner.mock.calls[0][0]).toBe('https://elsewhere.com'); expect(inner.mock.calls[0][1].body).toBe('123'); - await outer( - new Request('plugin://a', { - method: 'POST', - body: '123', - }), - ); + const inputRequest = new Request('plugin://a', { + method: 'POST', + body: '123', + }); + + await outer(inputRequest); expect(inner.mock.calls[1][0]).toBe('https://elsewhere.com'); - expect(inner.mock.calls[1][1].body).toEqual(Buffer.from('123', 'utf8')); + expect(inner.mock.calls[1][1]).toBe(inputRequest); }); }); diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts index 5993543c33..9d320c4033 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts @@ -83,12 +83,9 @@ describe('AppIdentityProxy', () => { it('should navigate to target URL on sign out', async () => { const proxy = new AppIdentityProxy(); proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/foo' }); - Object.defineProperty(window, 'location', { - writable: true, - value: {}, - }); + const navigateSpy = jest.spyOn(proxy as any, 'navigateToUrl'); await proxy.signOut(); - expect(window.location.href).toBe('/foo'); + expect(navigateSpy).toHaveBeenCalledWith('/foo'); }); }); diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts index 941ec90d66..161092fe9f 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.ts @@ -133,7 +133,11 @@ export class AppIdentityProxy implements IdentityApi { await this.#cookieAuthSignOut?.(); - window.location.href = this.signOutTargetUrl; + this.navigateToUrl(this.signOutTargetUrl); + } + + private navigateToUrl(url: string): void { + window.location.href = url; } enableCookieAuth(ctx: { 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 095fc88627..4273587c00 100644 --- a/packages/core-app-api/src/apis/system/ApiProvider.test.tsx +++ b/packages/core-app-api/src/apis/system/ApiProvider.test.tsx @@ -117,16 +117,12 @@ 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', - }), - expect.stringMatching( - /^The above error occurred in the component/, + expect.stringContaining('Error: API context is not available'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('Error: API context is not available'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'The above error occurred in the component', ), ]); @@ -137,16 +133,12 @@ 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', - }), - expect.stringMatching( - /^The above error occurred in the component/, + expect.stringContaining('Error: API context is not available'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('Error: API context is not available'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'The above error occurred in the component', ), ]); }); @@ -163,16 +155,16 @@ 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', - }), - expect.stringMatching( - /^The above error occurred in the component/, + expect.stringContaining( + 'Error: No implementation available for apiRef{x}', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'Error: No implementation available for apiRef{x}', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'The above error occurred in the component', ), ]); @@ -187,16 +179,16 @@ 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', - }), - expect.stringMatching( - /^The above error occurred in the component/, + expect.stringContaining( + 'Error: No implementation available for apiRef{x}', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'Error: No implementation available for apiRef{x}', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'The above error occurred in the component', ), ]); }); diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 3981da56ad..4a146678bc 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -670,14 +670,10 @@ describe('Integration Test', () => { }); expect(errorLogs).toEqual([ - expect.objectContaining({ - detail: new Error(expectedMessage), - type: 'unhandled exception', - }), - expect.objectContaining({ - detail: new Error(expectedMessage), - type: 'unhandled exception', - }), + expect.stringContaining(`Error: ${expectedMessage}`), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining(`Error: ${expectedMessage}`), + expect.objectContaining({ type: 'unhandled-exception' }), expect.stringContaining( 'The above error occurred in the component:', ), @@ -714,14 +710,10 @@ describe('Integration Test', () => { ).rejects.toThrow(expectedMessage); }); expect(errorLogs).toEqual([ - expect.objectContaining({ - detail: new Error(expectedMessage), - type: 'unhandled exception', - }), - expect.objectContaining({ - detail: new Error(expectedMessage), - type: 'unhandled exception', - }), + expect.stringContaining(`Error: ${expectedMessage}`), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining(`Error: ${expectedMessage}`), + expect.objectContaining({ type: 'unhandled-exception' }), expect.stringContaining( 'The above error occurred in the component:', ), diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 4f3d30deda..55980561f4 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/core-compat-api +## 0.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.5.5-next.0 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 7bb92d26fc..2894bfdca2 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.5.5-next.0", + "version": "0.5.6-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/core-compat-api/src/convertLegacyApp.test.tsx b/packages/core-compat-api/src/convertLegacyApp.test.tsx index 1cb2b757e3..7094eb798c 100644 --- a/packages/core-compat-api/src/convertLegacyApp.test.tsx +++ b/packages/core-compat-api/src/convertLegacyApp.test.tsx @@ -262,13 +262,16 @@ describe('convertLegacyApp', () => { ], }); + // Increase timeout for async rendering of complex catalog entity pages + const findOptions = { timeout: 5000 }; + // Overview const renderOverviewTest = await renderTestApp({ features: [catalogOverride, ...converted], initialRouteEntries: ['/catalog/default/test/x'], }); await expect( - renderOverviewTest.findByText('overview content'), + renderOverviewTest.findByText('overview content', {}, findOptions), ).resolves.toBeInTheDocument(); renderOverviewTest.unmount(); @@ -277,7 +280,7 @@ describe('convertLegacyApp', () => { initialRouteEntries: ['/catalog/default/other/x'], }); await expect( - renderOverviewOther.findByText('other overview content'), + renderOverviewOther.findByText('other overview content', {}, findOptions), ).resolves.toBeInTheDocument(); renderOverviewOther.unmount(); @@ -287,7 +290,7 @@ describe('convertLegacyApp', () => { initialRouteEntries: ['/catalog/default/test/x/foo'], }); await expect( - renderFooTest.findByText('foo content'), + renderFooTest.findByText('foo content', {}, findOptions), ).resolves.toBeInTheDocument(); renderFooTest.unmount(); @@ -296,7 +299,7 @@ describe('convertLegacyApp', () => { initialRouteEntries: ['/catalog/default/other/x/foo'], }); await expect( - renderFooOther.findByText('other foo content'), + renderFooOther.findByText('other foo content', {}, findOptions), ).resolves.toBeInTheDocument(); renderFooOther.unmount(); @@ -306,7 +309,7 @@ describe('convertLegacyApp', () => { initialRouteEntries: ['/catalog/default/test/x/bar'], }); await expect( - renderBarTest.findByText('bar content'), + renderBarTest.findByText('bar content', {}, findOptions), ).resolves.toBeInTheDocument(); renderBarTest.unmount(); @@ -315,7 +318,7 @@ describe('convertLegacyApp', () => { initialRouteEntries: ['/catalog/default/other/x/bar'], }); await expect( - renderBarOther.findByText('other overview content'), + renderBarOther.findByText('other overview content', {}, findOptions), ).resolves.toBeInTheDocument(); // /bar does not exist, fall back to rendering overview renderBarOther.unmount(); }); diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index b5f5ae226f..7346287cf6 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/core-components +## 0.18.4 + +### Patch Changes + +- 9a942a4: Fixed bug in the `LogViewer` component where shift + click always opened a new window instead of just changing the selection. + + In addition, improved the `LogViewer` component by a few usability enhancements: + + - Added support for multiple selections using cmd/ctrl + click + - Improved the generated hash that is added to the URL to also support ranges & multiple selections + - Added an hover effect & info tooltip to the "Copy to clipboard" button to indicate its functionality + - Added some color and a separator to the line numbers to improve readability + +- 207c3c8: long words like urls now breaks to new line on warning panels instead of overflowing the container +- 4c00303: Add `tooltipClasses` prop to `OverflowTooltip` component to allow customisation of the tooltip +- 5d52dab: Add i18n support for LogViewer search control +- f6b49ce: added support for wrapLongLines option in CodeSnippet +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + ## 0.18.4-next.2 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index da266d1b66..536f0ee9f0 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-components", - "version": "0.18.4-next.2", + "version": "0.18.4", "description": "Core components used by Backstage plugins and apps", "backstage": { "role": "web-library" diff --git a/packages/core-components/src/components/Link/Link.test.tsx b/packages/core-components/src/components/Link/Link.test.tsx index c132d832a2..c178ba6cbf 100644 --- a/packages/core-components/src/components/Link/Link.test.tsx +++ b/packages/core-components/src/components/Link/Link.test.tsx @@ -50,7 +50,7 @@ describe('', () => { External Link, ); const externalLink = screen.getByRole('link', { - name: 'External Link , Opens in a new window', + name: 'External Link, Opens in a new window', }); const externalLinkIcon = container.querySelector('svg'); expect(externalLink).not.toContainElement(externalLinkIcon); @@ -62,6 +62,7 @@ describe('', () => { External Link , ); + // Note: when externalLinkIcon is present, the SVG adds whitespace to the accessible name const externalLink = screen.getByRole('link', { name: 'External Link , Opens in a new window', }); diff --git a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx index 1be58d2dcf..3e4ab1df7c 100644 --- a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -47,18 +47,20 @@ describe('TabbedLayout', () => { }); expect(error).toEqual([ + expect.stringContaining( + 'Error: Child of TabbedLayout must be an TabbedLayout.Route', + ), expect.objectContaining({ - detail: new Error( - 'Child of TabbedLayout must be an TabbedLayout.Route', - ), + type: 'unhandled-exception', }), + expect.stringContaining( + 'Error: Child of TabbedLayout must be an TabbedLayout.Route', + ), expect.objectContaining({ - detail: new Error( - 'Child of TabbedLayout must be an TabbedLayout.Route', - ), + type: 'unhandled-exception', }), - expect.stringMatching( - /The above error occurred in the component/, + expect.stringContaining( + 'The above error occurred in the component', ), ]); }); diff --git a/packages/core-components/src/components/Table/Table.test.tsx b/packages/core-components/src/components/Table/Table.test.tsx index dfae66d1c2..dab5a462c2 100644 --- a/packages/core-components/src/components/Table/Table.test.tsx +++ b/packages/core-components/src/components/Table/Table.test.tsx @@ -68,7 +68,7 @@ describe('', () => {
, ); expect(rendered.getByText('second value, first row')).toHaveStyle({ - color: 'blue', + color: 'rgb(0, 0, 255)', // blue }); }); @@ -85,7 +85,7 @@ describe('
', () => {
, ); expect(rendered.getByText('second value, first row')).toHaveStyle({ - color: 'blue', + color: 'rgb(0, 0, 255)', // blue 'font-weight': 700, }); }); @@ -115,10 +115,10 @@ describe('
', () => {
, ); expect(rendered.getByText('second value, first row')).toHaveStyle({ - color: 'green', + color: 'rgb(0, 128, 0)', // green }); expect(rendered.getByText('second value, second row')).toHaveStyle({ - color: 'red', + color: 'rgb(255, 0, 0)', // red }); }); @@ -135,11 +135,11 @@ describe('
', () => {
, ); expect(rendered.getByText('second value, first row')).toHaveStyle({ - color: 'green', + color: 'rgb(0, 128, 0)', // green 'font-weight': 700, }); expect(rendered.getByText('second value, second row')).toHaveStyle({ - color: 'red', + color: 'rgb(255, 0, 0)', // red 'font-weight': 700, }); }); @@ -165,11 +165,11 @@ describe('
', () => { expect(rendered.getByText(column1.title).closest('th')).not.toHaveStyle( { - backgroundColor: 'pink', + backgroundColor: 'rgb(255, 192, 203)', // pink }, ); expect(rendered.getByText(column2.title).closest('th')).toHaveStyle({ - backgroundColor: 'pink', + backgroundColor: 'rgb(255, 192, 203)', // pink }); }); diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx index 4011fd2125..65e8a55801 100644 --- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx +++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx @@ -67,18 +67,20 @@ describe('', () => { }); expect(error).toEqual([ + expect.stringContaining('Error: Bomb'), expect.objectContaining({ - detail: new Error('Bomb'), + type: 'unhandled-exception', }), + expect.stringContaining('Error: Bomb'), expect.objectContaining({ - detail: new Error('Bomb'), + type: 'unhandled-exception', }), - expect.stringMatching( - /^The above error occurred in the component:/, + expect.stringContaining( + 'The above error occurred in the component:', ), - expect.stringMatching(/^ErrorBoundary/), - expect.stringMatching(/Warning: findDOMNode/), // React warning, unfortunate but currently true + expect.stringContaining('ErrorBoundary'), + expect.stringContaining('Warning: findDOMNode'), // React warning, unfortunate but currently true ]); - expect(error.length).toEqual(5); + expect(error.length).toEqual(7); }); }); diff --git a/packages/core-components/src/layout/Sidebar/Items.test.tsx b/packages/core-components/src/layout/Sidebar/Items.test.tsx index 3121228ccd..35a0793409 100644 --- a/packages/core-components/src/layout/Sidebar/Items.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.test.tsx @@ -96,7 +96,7 @@ describe('Items', () => { it('should render a button with custom style', async () => { expect( await screen.findByRole('button', { name: /create/i }), - ).toHaveStyle(`background-color: transparent`); + ).toHaveStyle(`background-color: rgba(0, 0, 0, 0)`); // transparent }); it('should send button clicks to analytics', async () => { diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index a47e87fe66..8c6c617bcb 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/core-plugin-api +## 1.12.1 + +### Patch Changes + +- 358c6f7: The `useApp` and `useRouteRef` functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs. +- 97cd16f: Reversed the relationship between the old `@backstage/core-plugin-api` and the new `@backstage/frontend-plugin-api`. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + ## 1.12.1-next.0 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 11e4a911c5..ef4982e07e 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-plugin-api", - "version": "1.12.1-next.0", + "version": "1.12.1", "description": "Core API used by Backstage plugins", "backstage": { "role": "web-library" diff --git a/packages/core-plugin-api/src/extensions/extensions.test.tsx b/packages/core-plugin-api/src/extensions/extensions.test.tsx index 75bb4ae443..59fe0d118d 100644 --- a/packages/core-plugin-api/src/extensions/extensions.test.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.test.tsx @@ -26,7 +26,6 @@ import { createReactExtension, createRoutableExtension, } from './extensions'; -import { ForwardedError } from '@backstage/errors'; jest.mock('../app'); @@ -117,7 +116,13 @@ describe('extensions', () => { render(); }); screen.getByText('Error in my-plugin'); - expect(errors[0]).toMatchObject({ detail: new Error('Test error') }); + expect(errors).toEqual([ + expect.stringContaining('Error: Test error'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('Error: Test error'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('The above error occurred in'), + ]); }); it('should handle failed lazy loads', async () => { @@ -154,12 +159,17 @@ describe('extensions', () => { screen.getByText( 'Error in my-plugin: Error: Failed lazy loading of the BrokenComponent extension, try to reload the page; caused by Error: Test error', ); - expect(errors[0]).toMatchObject({ - detail: new ForwardedError( - 'Failed lazy loading of the BrokenComponent extension, try to reload the page', - new Error('Test error'), + expect(errors).toEqual([ + expect.stringContaining( + 'Error: Failed lazy loading of the BrokenComponent extension, try to reload the page', ), - }); + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'Error: Failed lazy loading of the BrokenComponent extension, try to reload the page', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('The above error occurred in'), + ]); }); it('should wrap extended component with analytics context', async () => { diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index e26b1347a3..96cb8fe09a 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/create-app +## 0.7.8-next.1 + +### Patch Changes + +- Bumped create-app version. + +## 0.7.8-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.16 + +## 0.7.7 + +### Patch Changes + +- 336db00: Bumped create-app version. +- 2bae83a: Updated engines to support Node 22 or 24 +- c8c2329: Add proxy configuration from env-vars to create-app tasks +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.16 + ## 0.7.7-next.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 029cec855a..cddd0f458c 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/create-app", - "version": "0.7.7-next.2", + "version": "0.7.8-next.1", "description": "A CLI that helps you create your own Backstage app", "backstage": { "role": "cli" diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index d0a088a7d1..c1e4a51140 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -32,6 +32,10 @@ "@backstage/cli": "^{{version '@backstage/cli'}}", "@backstage/e2e-test-utils": "^{{version '@backstage/e2e-test-utils'}}", "@playwright/test": "^1.32.3", + "@jest/environment-jsdom-abstract": "^30.0.0", + "@types/jest": "^30.0.0", + "jest": "^30.2.0", + "jsdom": "^27.1.0", "node-gyp": "^10.0.0", "prettier": "^2.3.2", "typescript": "~5.8.0" diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 1b26653336..09cb8957fe 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/dev-utils +## 1.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## 1.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/theme@0.7.1 + - @backstage/plugin-catalog-react@1.21.4 + +## 1.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/ui@0.10.0 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/app-defaults@1.7.3 + - @backstage/integration-react@1.2.13 + ## 1.1.18-next.1 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 5b0c9bbee7..87a4b346f4 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.1.18-next.1", + "version": "1.1.19-next.1", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index e65f1ffaf5..76fd95f56e 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,22 @@ # e2e-test +## 0.2.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.8-next.0 + - @backstage/cli-common@0.1.16 + - @backstage/errors@1.2.7 + +## 0.2.35 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.7.7 + - @backstage/cli-common@0.1.16 + ## 0.2.35-next.0 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index e70f2f8105..5773464cb1 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,6 +1,6 @@ { "name": "e2e-test", - "version": "0.2.35-next.0", + "version": "0.2.36-next.0", "description": "E2E test for verifying Backstage packages", "backstage": { "role": "cli" diff --git a/packages/errors/src/errors/common.test.ts b/packages/errors/src/errors/common.test.ts index dfa9743616..4c496614ab 100644 --- a/packages/errors/src/errors/common.test.ts +++ b/packages/errors/src/errors/common.test.ts @@ -23,7 +23,7 @@ describe('common', () => { const error = new E('abcdef'); expect(error.name).toBe(name); expect(error.message).toBe('abcdef'); - expect(error.stack).toContain(__filename); + expect(error.stack).toContain('common.test.ts'); expect(error.toString()).toContain(name); expect(error.toString()).toContain('abcdef'); } diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 2d46087f47..e56d018fc7 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/frontend-app-api +## 0.13.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-defaults@0.3.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.13.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-defaults@0.3.4 + ## 0.13.3-next.0 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index f69d3d1f13..d142ae15c6 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.13.3-next.0", + "version": "0.13.4-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-defaults/CHANGELOG.md b/packages/frontend-defaults/CHANGELOG.md index aeacb83d31..dda4f5679e 100644 --- a/packages/frontend-defaults/CHANGELOG.md +++ b/packages/frontend-defaults/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/frontend-defaults +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/frontend-app-api@0.13.3 + ## 0.3.4-next.0 ### Patch Changes diff --git a/packages/frontend-defaults/package.json b/packages/frontend-defaults/package.json index 17b11a391d..c90076693d 100644 --- a/packages/frontend-defaults/package.json +++ b/packages/frontend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-defaults", - "version": "0.3.4-next.0", + "version": "0.3.5-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-dynamic-feature-loader/CHANGELOG.md b/packages/frontend-dynamic-feature-loader/CHANGELOG.md index 43df44d8dc..58cb740bd5 100644 --- a/packages/frontend-dynamic-feature-loader/CHANGELOG.md +++ b/packages/frontend-dynamic-feature-loader/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/frontend-dynamic-feature-loader +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + ## 0.1.8-next.0 ### Patch Changes diff --git a/packages/frontend-dynamic-feature-loader/package.json b/packages/frontend-dynamic-feature-loader/package.json index 11a10cfee6..c8771ca154 100644 --- a/packages/frontend-dynamic-feature-loader/package.json +++ b/packages/frontend-dynamic-feature-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-dynamic-feature-loader", - "version": "0.1.8-next.0", + "version": "0.1.8", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx index b2f6486766..c0bf5822cc 100644 --- a/packages/frontend-dynamic-feature-loader/src/loader.test.tsx +++ b/packages/frontend-dynamic-feature-loader/src/loader.test.tsx @@ -655,7 +655,7 @@ describe('dynamicFrontendFeaturesLoader', () => { const errorCalls = mocks.console.error.mock.calls.flatMap(e => e[0]); expect(errorCalls).toEqual([ - `Failed fetching module federation configuration of dynamic frontend plugins: FetchError: invalid json response body at http://localhost:7007/.backstage/dynamic-features/remotes reason: Unexpected end of JSON input`, + `Failed fetching module federation configuration of dynamic frontend plugins: SyntaxError: Unexpected end of JSON input`, ]); const warnCalls = mocks.console.warn.mock.calls.flatMap(e => e[0]); expect(warnCalls).toEqual([]); diff --git a/packages/frontend-internal/CHANGELOG.md b/packages/frontend-internal/CHANGELOG.md index d1adc69391..de5b02e547 100644 --- a/packages/frontend-internal/CHANGELOG.md +++ b/packages/frontend-internal/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/frontend +## 0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + ## 0.0.16-next.0 ### Patch Changes diff --git a/packages/frontend-internal/package.json b/packages/frontend-internal/package.json index f2268f38f4..705aec5835 100644 --- a/packages/frontend-internal/package.json +++ b/packages/frontend-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/frontend", - "version": "0.0.16-next.0", + "version": "0.0.16", "backstage": { "role": "web-library", "inline": true diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 6c5ede72df..f2c4f2029c 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/frontend-plugin-api +## 0.13.2 + +### Patch Changes + +- 75683ed: Added a new `errorPresentation` prop to `ExtensionBoundary` to control how errors are presented to the user. The default is `'error-display'`, which is the current behavior of showing the error in the `ErrorDisplay` component. The new option is `'error-api'`, posts errors to the `ErrorApi` and does not allow retries. + + The `AppRootElementBlueprint` now wraps its element in an `ErrorBoundary` using the new `'error-api'` presentation mode. + +- 0bc1ce9: Fixed a versioning conflict that could result in a `.withContext` is not a function error. +- f3f84f1: Made the return type of `.withOverrides` to be simplified. +- 97cd16f: Reversed the relationship between the old `@backstage/core-plugin-api` and the new `@backstage/frontend-plugin-api`. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old. +- 9b8bde4: Removed unnecessary dependencies on `@backstage/core-components`, `@backstage/config`, `@material-ui/core`, and `lodash`. + ## 0.13.2-next.1 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index af3359ff22..bda034ac78 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.13.2-next.1", + "version": "0.13.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/src/components/AppNodeProvider.test.tsx b/packages/frontend-plugin-api/src/components/AppNodeProvider.test.tsx index fcc3b74c59..0a73f90dde 100644 --- a/packages/frontend-plugin-api/src/components/AppNodeProvider.test.tsx +++ b/packages/frontend-plugin-api/src/components/AppNodeProvider.test.tsx @@ -70,12 +70,10 @@ describe('AppNodeProvider', () => { ).toThrow('AppNodeContext v1 not available'); }); expect(error).toEqual([ - expect.objectContaining({ - detail: new Error('AppNodeContext v1 not available'), - }), - expect.objectContaining({ - detail: new Error('AppNodeContext v1 not available'), - }), + expect.stringContaining('Error: AppNodeContext v1 not available'), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('Error: AppNodeContext v1 not available'), + expect.objectContaining({ type: 'unhandled-exception' }), expect.stringContaining( 'The above error occurred in the component:', ), diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 3adc1d0f0b..b4500f6d50 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/frontend-test-utils +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.4-next.0 + - @backstage/frontend-app-api@0.13.4-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.3.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/test-utils@1.7.14 + - @backstage/frontend-app-api@0.13.3 + ## 0.4.2-next.0 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 48ed1b6827..f72d2a90d6 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.4.2-next.0", + "version": "0.4.3-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index cf30e3fadc..02738a50de 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/integration-react +## 1.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/core-plugin-api@1.12.1 + ## 1.2.13-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index d5cc25c5c2..e335c70ac2 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.2.13-next.0", + "version": "1.2.14-next.0", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration-react/src/api/ScmIntegrationsApi.test.ts b/packages/integration-react/src/api/ScmIntegrationsApi.test.ts index 0a1f1b1b8f..55acd29eec 100644 --- a/packages/integration-react/src/api/ScmIntegrationsApi.test.ts +++ b/packages/integration-react/src/api/ScmIntegrationsApi.test.ts @@ -26,6 +26,6 @@ describe('scmIntegrationsApiRef', () => { it('should be instantiated', () => { const i = ScmIntegrationsApi.fromConfig(new ConfigReader({})); - expect(i.list().length).toBe(7); // The default ones + expect(i.list().length).toBe(8); // The default ones }); }); diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 3e412d5d88..f361879e5e 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/integration +## 1.19.2-next.0 + +### Patch Changes + +- 3afeab4: Implementing `ScmIntegration` for `GoogleGcs` +- 9083273: Rollback the lowercase replacing in GitHub integration config + +## 1.19.0 + +### Minor Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +### Patch Changes + +- a26a322: Added support for using a GitHub App installation to generate tokens for public repository access when the `publicAccess` option is enabled. When all other authentication methods fail (e.g., the app is not installed in that organization), the provider will now use an available installation to generate a token that can be used to access public repositories as read only. +- fb029b6: Updated luxon types +- e15fdae: Made the github urls case insensitive. + ## 1.18.3-next.1 ### Patch Changes diff --git a/packages/integration/config.d.ts b/packages/integration/config.d.ts index a49c4cc0d6..4278a8fcfe 100644 --- a/packages/integration/config.d.ts +++ b/packages/integration/config.d.ts @@ -174,7 +174,7 @@ export interface Config { * The username to use for authenticated requests. * @visibility secret */ - username: string; + username?: string; /** * Token used to authenticate requests. * @visibility secret @@ -186,6 +186,16 @@ export interface Config { * @deprecated Use `token` instead. */ appPassword?: string; + /** + * OAuth client ID for Bitbucket Cloud. + * @visibility secret + */ + clientId?: string; + /** + * OAuth client secret for Bitbucket Cloud. + * @visibility secret + */ + clientSecret?: string; /** * PGP signing key for signing commits. * @visibility secret diff --git a/packages/integration/package.json b/packages/integration/package.json index f984c2b249..75498b4869 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.18.3-next.1", + "version": "1.19.2-next.0", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" diff --git a/packages/integration/report.api.md b/packages/integration/report.api.md index d065f441f0..abcdb8898b 100644 --- a/packages/integration/report.api.md +++ b/packages/integration/report.api.md @@ -250,6 +250,8 @@ export type BitbucketCloudIntegrationConfig = { username?: string; appPassword?: string; token?: string; + clientId?: string; + clientSecret?: string; commitSigningKey?: string; }; @@ -450,12 +452,18 @@ export function getBitbucketCloudFileFetchUrl( config: BitbucketCloudIntegrationConfig, ): string; +// @public +export function getBitbucketCloudOAuthToken( + clientId: string, + clientSecret: string, +): Promise; + // @public export function getBitbucketCloudRequestOptions( config: BitbucketCloudIntegrationConfig, -): { +): Promise<{ headers: Record; -}; +}>; // @public @deprecated export function getBitbucketDefaultBranch( @@ -773,8 +781,30 @@ export type GitLabIntegrationConfig = { commitSigningKey?: string; }; +// @public +export class GoogleGcsIntegration implements ScmIntegration { + constructor(integrationConfig: GoogleGcsIntegrationConfig); + // (undocumented) + get config(): GoogleGcsIntegrationConfig; + // (undocumented) + static factory: ScmIntegrationsFactory; + // (undocumented) + resolveEditUrl(url: string): string; + // (undocumented) + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string; + // (undocumented) + get title(): string; + // (undocumented) + get type(): string; +} + // @public export type GoogleGcsIntegrationConfig = { + host: string; clientEmail?: string; privateKey?: string; }; @@ -832,6 +862,8 @@ export interface IntegrationsByType { // (undocumented) gitlab: ScmIntegrationsGroup; // (undocumented) + googleGcs: ScmIntegrationsGroup; + // (undocumented) harness: ScmIntegrationsGroup; } @@ -1102,6 +1134,8 @@ export class ScmIntegrations implements ScmIntegrationRegistry { // (undocumented) get gitlab(): ScmIntegrationsGroup; // (undocumented) + get googleGcs(): ScmIntegrationsGroup; + // (undocumented) get harness(): ScmIntegrationsGroup; // (undocumented) list(): ScmIntegration[]; diff --git a/packages/integration/src/ScmIntegrations.test.ts b/packages/integration/src/ScmIntegrations.test.ts index 0e0c181861..7f75ab44fc 100644 --- a/packages/integration/src/ScmIntegrations.test.ts +++ b/packages/integration/src/ScmIntegrations.test.ts @@ -43,6 +43,7 @@ import { AzureBlobStorageIntegrationConfig, AzureBlobStorageIntergation, } from './azureBlobStorage'; +import { GoogleGcsIntegration, GoogleGcsIntegrationConfig } from './googleGcs'; describe('ScmIntegrations', () => { const awsS3 = new AwsS3Integration({ @@ -93,6 +94,10 @@ describe('ScmIntegrations', () => { host: 'harness.local', } as HarnessIntegrationConfig); + const googleGcs = new GoogleGcsIntegration({ + host: 'storage.cloud.google.com', + } as GoogleGcsIntegrationConfig); + const i = new ScmIntegrations({ awsS3: basicIntegrations([awsS3], item => item.config.host), awsCodeCommit: basicIntegrations([awsCodeCommit], item => item.config.host), @@ -108,6 +113,7 @@ describe('ScmIntegrations', () => { github: basicIntegrations([github], item => item.config.host), gitlab: basicIntegrations([gitlab], item => item.config.host), gitea: basicIntegrations([gitea], item => item.config.host), + googleGcs: basicIntegrations([googleGcs], item => item.config.host), harness: basicIntegrations([harness], item => item.config.host), }); diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index f11cb3c17e..573975da0e 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -30,6 +30,7 @@ import { ScmIntegrationRegistry } from './registry'; import { GiteaIntegration } from './gitea'; import { HarnessIntegration } from './harness/HarnessIntegration'; import { AzureBlobStorageIntergation } from './azureBlobStorage'; +import { GoogleGcsIntegration } from './googleGcs/GoogleGcsIntegration'; /** * The set of supported integrations. @@ -51,6 +52,7 @@ export interface IntegrationsByType { github: ScmIntegrationsGroup; gitlab: ScmIntegrationsGroup; gitea: ScmIntegrationsGroup; + googleGcs: ScmIntegrationsGroup; harness: ScmIntegrationsGroup; } @@ -75,6 +77,7 @@ export class ScmIntegrations implements ScmIntegrationRegistry { github: GithubIntegration.factory({ config }), gitlab: GitLabIntegration.factory({ config }), gitea: GiteaIntegration.factory({ config }), + googleGcs: GoogleGcsIntegration.factory({ config }), harness: HarnessIntegration.factory({ config }), }); } @@ -130,6 +133,10 @@ export class ScmIntegrations implements ScmIntegrationRegistry { return this.byType.gitea; } + get googleGcs(): ScmIntegrationsGroup { + return this.byType.googleGcs; + } + get harness(): ScmIntegrationsGroup { return this.byType.harness; } diff --git a/packages/integration/src/azure/core.test.ts b/packages/integration/src/azure/core.test.ts index 601057e499..fbd6747f56 100644 --- a/packages/integration/src/azure/core.test.ts +++ b/packages/integration/src/azure/core.test.ts @@ -73,7 +73,7 @@ describe('azure core', () => { }, { url: 'com/a/b/blob/master/path/to/c.yaml', - error: 'Invalid URL: com/a/b/blob/master/path/to/c.yaml', + error: 'Invalid URL', }, ])('should handle error path %#', ({ url, error }) => { expect(() => getAzureFileFetchUrl(url)).toThrow(error); diff --git a/packages/integration/src/bitbucketCloud/config.test.ts b/packages/integration/src/bitbucketCloud/config.test.ts index 9488c8b5f7..57e8803a14 100644 --- a/packages/integration/src/bitbucketCloud/config.test.ts +++ b/packages/integration/src/bitbucketCloud/config.test.ts @@ -85,6 +85,39 @@ describe('readBitbucketCloudIntegrationConfig', () => { ).toThrow(/token/); }); + it('reads OAuth configuration', () => { + const output = readBitbucketCloudIntegrationConfig( + buildConfig({ + clientId: 'my-client-id', + clientSecret: 'my-client-secret', + }), + ); + expect(output).toEqual({ + host: BITBUCKET_CLOUD_HOST, + apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, + clientId: 'my-client-id', + clientSecret: 'my-client-secret', + }); + }); + + it('rejects incomplete OAuth configuration', () => { + expect(() => + readBitbucketCloudIntegrationConfig( + buildConfig({ + clientId: 'my-client-id', + }), + ), + ).toThrow(/incomplete OAuth configuration/); + + expect(() => + readBitbucketCloudIntegrationConfig( + buildConfig({ + clientSecret: 'my-client-secret', + }), + ), + ).toThrow(/incomplete OAuth configuration/); + }); + it('credentials hidden on the frontend', async () => { const frontendConfig = await buildFrontendConfig({ token: 't', @@ -103,6 +136,24 @@ describe('readBitbucketCloudIntegrationConfig', () => { ]); }); + it('OAuth credentials hidden on the frontend', async () => { + const frontendConfig = await buildFrontendConfig({ + clientId: 'my-client-id', + clientSecret: 'my-client-secret', + }); + expect( + readBitbucketCloudIntegrationConfigs( + frontendConfig.getOptionalConfigArray('integrations.bitbucketCloud') ?? + [], + ), + ).toEqual([ + { + host: BITBUCKET_CLOUD_HOST, + apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, + }, + ]); + }); + // TODO: appPassword can be removed once fully // deprecated by BitBucket on 9th June 2026. describe('handles deprecated appPassword', () => { diff --git a/packages/integration/src/bitbucketCloud/config.ts b/packages/integration/src/bitbucketCloud/config.ts index 0e08e95a79..e47b215f98 100644 --- a/packages/integration/src/bitbucketCloud/config.ts +++ b/packages/integration/src/bitbucketCloud/config.ts @@ -54,6 +54,20 @@ export type BitbucketCloudIntegrationConfig = { */ token?: string; + /** + * The OAuth client ID for Bitbucket Cloud. + * + * See https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/ + */ + clientId?: string; + + /** + * The OAuth client secret for Bitbucket Cloud. + * + * See https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/ + */ + clientSecret?: string; + /** PGP private key for signing commits. */ commitSigningKey?: string; }; @@ -71,24 +85,36 @@ export function readBitbucketCloudIntegrationConfig( const apiBaseUrl = BITBUCKET_CLOUD_API_BASE_URL; // If config is provided, we assume authenticated access is desired // (as the anonymous one is provided by default). - const username = config.getString('username'); + const username = config.getOptionalString('username'); // TODO: appPassword can be removed once fully // deprecated by BitBucket on 9th June 2026. const appPassword = config.getOptionalString('appPassword')?.trim(); const token = config.getOptionalString('token'); + const clientId = config.getOptionalString('clientId')?.trim(); + const clientSecret = config.getOptionalString('clientSecret')?.trim(); - if (!token && !appPassword) { + // Validate: if username is provided, token or appPassword is required + if (username && !token && !appPassword) { throw new Error( `Bitbucket Cloud integration must be configured with as username and either a token or an appPassword.`, ); } + // Validate: OAuth requires both clientId and clientSecret + if ((clientId && !clientSecret) || (clientSecret && !clientId)) { + throw new Error( + `Bitbucket Cloud integration has incomplete OAuth configuration. Both clientId and clientSecret are required.`, + ); + } + return { host, apiBaseUrl, username, appPassword, token, + clientId, + clientSecret, commitSigningKey: config.getOptionalString('commitSigningKey'), }; } diff --git a/packages/integration/src/bitbucketCloud/core.test.ts b/packages/integration/src/bitbucketCloud/core.test.ts index fa8fc2ae43..4f46b5ad42 100644 --- a/packages/integration/src/bitbucketCloud/core.test.ts +++ b/packages/integration/src/bitbucketCloud/core.test.ts @@ -28,13 +28,15 @@ import { // Mock constants const BITBUCKET_CLOUD_HOST = 'bitbucket.org'; const BITBUCKET_CLOUD_API_BASE_URL = 'https://api.bitbucket.org/2.0'; +const BITBUCKET_CLOUD_OAUTH_TOKEN_URL = + 'https://bitbucket.org/site/oauth2/access_token'; describe('bitbucketCloud core', () => { const worker = setupServer(); registerMswTestHooks(worker); describe('getBitbucketCloudRequestOptions', () => { - it('insert basic auth when needed', () => { + it('insert basic auth when needed', async () => { const withUsernameAndToken: BitbucketCloudIntegrationConfig = { host: BITBUCKET_CLOUD_HOST, apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, @@ -54,20 +56,72 @@ describe('bitbucketCloud core', () => { apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, }; expect( - (getBitbucketCloudRequestOptions(withUsernameAndToken).headers as any) + (await getBitbucketCloudRequestOptions(withUsernameAndToken)).headers .Authorization, ).toEqual('Basic c29tZS11c2VyQGRvbWFpbi5jb206bXktdG9rZW4='); expect( - ( - getBitbucketCloudRequestOptions(withUsernameAndPassword) - .headers as any - ).Authorization, + (await getBitbucketCloudRequestOptions(withUsernameAndPassword)).headers + .Authorization, ).toEqual('Basic c29tZS11c2VyOm15LXNlY3JldA=='); expect( - (getBitbucketCloudRequestOptions(withoutUsername).headers as any) + (await getBitbucketCloudRequestOptions(withoutUsername)).headers .Authorization, ).toBeUndefined(); }); + + it('handles OAuth token fetch errors', async () => { + // Test error handling + worker.use( + rest.post(BITBUCKET_CLOUD_OAUTH_TOKEN_URL, (_, res, ctx) => + res(ctx.status(401), ctx.json({ error: 'invalid_client' })), + ), + ); + + const withOAuth: BitbucketCloudIntegrationConfig = { + host: BITBUCKET_CLOUD_HOST, + apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, + clientId: 'test-client-id', + clientSecret: 'test-client-secret', + }; + + await expect(getBitbucketCloudRequestOptions(withOAuth)).rejects.toThrow( + /Failed to fetch OAuth token/, + ); + }); + + it('uses OAuth Bearer token and caches it', async () => { + // Test OAuth + caching + let callCount = 0; + worker.use( + rest.post(BITBUCKET_CLOUD_OAUTH_TOKEN_URL, (_, res, ctx) => { + callCount++; + return res( + ctx.status(200), + ctx.json({ + access_token: 'test-oauth-token', + expires_in: 3600, + }), + ); + }), + ); + + const withOAuth: BitbucketCloudIntegrationConfig = { + host: BITBUCKET_CLOUD_HOST, + apiBaseUrl: BITBUCKET_CLOUD_API_BASE_URL, + clientId: 'test-client-id', + clientSecret: 'test-client-secret', + }; + + // First call should fetch token + const result1 = await getBitbucketCloudRequestOptions(withOAuth); + expect(result1.headers.Authorization).toEqual('Bearer test-oauth-token'); + expect(callCount).toBe(1); + + // Second call should use cached token (proves caching works) + const result2 = await getBitbucketCloudRequestOptions(withOAuth); + expect(result2.headers.Authorization).toEqual('Bearer test-oauth-token'); + expect(callCount).toBe(1); // Still 1, proving cache was used + }); }); describe('getBitbucketCloudFileFetchUrl', () => { diff --git a/packages/integration/src/bitbucketCloud/core.ts b/packages/integration/src/bitbucketCloud/core.ts index a97de872de..9beb3bd748 100644 --- a/packages/integration/src/bitbucketCloud/core.ts +++ b/packages/integration/src/bitbucketCloud/core.ts @@ -17,6 +17,100 @@ import fetch from 'cross-fetch'; import parseGitUrl from 'git-url-parse'; import { BitbucketCloudIntegrationConfig } from './config'; +import { DateTime } from 'luxon'; + +type OAuthTokenData = { + token: string; + expiresAt: DateTime; +}; + +// In-memory token cache (single entry since there's only one Bitbucket Cloud integration) +let cachedToken: OAuthTokenData | undefined; + +// Track in-flight token refresh request to prevent concurrent fetches +let refreshPromise: Promise | undefined; + +/** + * Fetches an OAuth access token from Bitbucket Cloud using client credentials flow. + * Tokens are cached with a 10-minute grace period to account for clock skew. + * Implements concurrent refresh protection to prevent multiple simultaneous token requests. + * + * @param clientId - OAuth client ID + * @param clientSecret - OAuth client secret + * @public + */ +export async function getBitbucketCloudOAuthToken( + clientId: string, + clientSecret: string, +): Promise { + // Check cache + if (cachedToken && DateTime.now() < cachedToken.expiresAt) { + return cachedToken.token; + } + + // Check if there's already a refresh in progress + if (refreshPromise) { + return refreshPromise; + } + + // Start a new token fetch and track it + refreshPromise = (async () => { + try { + // Fetch new token + const credentials = Buffer.from( + `${clientId}:${clientSecret}`, + 'utf8', + ).toString('base64'); + + const response = await fetch( + 'https://bitbucket.org/site/oauth2/access_token', + { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${credentials}`, + }, + body: 'grant_type=client_credentials', + }, + ); + + if (!response.ok) { + throw new Error( + `Failed to fetch OAuth token from Bitbucket Cloud: ${response.status} ${response.statusText}`, + ); + } + + const data = await response.json(); + + if (!data.access_token) { + throw new Error('OAuth token response missing access_token field'); + } + + // Calculate expiration with 10-minute grace period + const expiresIn = data.expires_in || 3600; // Default to 1 hour + const expiresAt = DateTime.now() + .plus({ seconds: expiresIn }) + .minus({ minutes: 10 }); + + // Cache the token + cachedToken = { + token: data.access_token, + expiresAt, + }; + + return data.access_token; + } catch (error) { + throw new Error( + `Failed to fetch OAuth token for Bitbucket Cloud: ${error}`, + ); + } finally { + // Clean up the in-flight promise tracking + refreshPromise = undefined; + } + })(); + + return refreshPromise; +} /** * Given a URL pointing to a path on a provider, returns the default branch. @@ -34,7 +128,7 @@ export async function getBitbucketCloudDefaultBranch( const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`; const response = await fetch( branchUrl, - getBitbucketCloudRequestOptions(config), + await getBitbucketCloudRequestOptions(config), ); if (!response.ok) { @@ -118,18 +212,29 @@ export function getBitbucketCloudFileFetchUrl( /** * Gets the request options necessary to make requests to a given provider. * Returns headers for authenticating with Bitbucket Cloud. - * Supports both username/token and username/appPassword auth. + * Supports OAuth (clientId/clientSecret), username/token, and username/appPassword auth. * * @param config - The relevant provider config * @public */ -export function getBitbucketCloudRequestOptions( +export async function getBitbucketCloudRequestOptions( config: BitbucketCloudIntegrationConfig, -): { +): Promise<{ headers: Record; -} { +}> { const headers: Record = {}; + // OAuth authentication (clientId/clientSecret) + if (config.clientId && config.clientSecret) { + const token = await getBitbucketCloudOAuthToken( + config.clientId, + config.clientSecret, + ); + headers.Authorization = `Bearer ${token}`; + return { headers }; + } + + // Basic authentication (username + token/appPassword) // TODO: appPassword can be removed once fully // deprecated by BitBucket on 9th June 2026. if (config.username && (config.token ?? config.appPassword)) { diff --git a/packages/integration/src/bitbucketCloud/index.ts b/packages/integration/src/bitbucketCloud/index.ts index 7119d3ea90..d0c11136b3 100644 --- a/packages/integration/src/bitbucketCloud/index.ts +++ b/packages/integration/src/bitbucketCloud/index.ts @@ -24,5 +24,6 @@ export { getBitbucketCloudDefaultBranch, getBitbucketCloudDownloadUrl, getBitbucketCloudFileFetchUrl, + getBitbucketCloudOAuthToken, getBitbucketCloudRequestOptions, } from './core'; diff --git a/packages/integration/src/github/GithubIntegration.test.ts b/packages/integration/src/github/GithubIntegration.test.ts index c54d4db2ef..70f1c4a16c 100644 --- a/packages/integration/src/github/GithubIntegration.test.ts +++ b/packages/integration/src/github/GithubIntegration.test.ts @@ -134,24 +134,4 @@ describe('replaceGithubUrlType', () => { ), ).toBe('https://github.com/backstage/backstage/blob/tree/README.md'); }); - it('should replace with lowercase', () => { - expect( - replaceGithubUrlType( - 'https://githuB.com/backstage/backstage/blob/master/README.md', - 'edit', - ), - ).toBe('https://github.com/backstage/backstage/edit/master/README.md'); - expect( - replaceGithubUrlType( - 'https://github.com/Backstage/backstage/blob/master/README.md', - 'edit', - ), - ).toBe('https://github.com/backstage/backstage/edit/master/README.md'); - expect( - replaceGithubUrlType( - 'https://github.com/backstage/Backstage/blob/master/README.md', - 'edit', - ), - ).toBe('https://github.com/backstage/backstage/edit/master/README.md'); - }); }); diff --git a/packages/integration/src/github/GithubIntegration.ts b/packages/integration/src/github/GithubIntegration.ts index 79d5e7f421..880a2bed21 100644 --- a/packages/integration/src/github/GithubIntegration.ts +++ b/packages/integration/src/github/GithubIntegration.ts @@ -95,9 +95,7 @@ export function replaceGithubUrlType( return url.replace( /\/\/([^/]+)\/([^/]+)\/([^/]+)\/(blob|tree|edit)\//, (_, host, owner, repo) => { - return `//${host.toLocaleLowerCase('en-US')}/${owner.toLocaleLowerCase( - 'en-US', - )}/${repo.toLocaleLowerCase('en-US')}/${type}/`; + return `//${host}/${owner}/${repo}/${type}/`; }, ); } diff --git a/packages/integration/src/googleGcs/GoogleGcsIntegration.test.ts b/packages/integration/src/googleGcs/GoogleGcsIntegration.test.ts new file mode 100644 index 0000000000..5666a0aa5e --- /dev/null +++ b/packages/integration/src/googleGcs/GoogleGcsIntegration.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { GoogleGcsIntegration } from './GoogleGcsIntegration'; + +describe('GoogleGcsIntegration', () => { + it('has a working factory', () => { + const integrations = GoogleGcsIntegration.factory({ + config: new ConfigReader({ + integrations: { + googleGcs: { + clientEmail: 'someone@example.com', + privateKey: 'fake-key', + }, + }, + }), + }); + expect(integrations.list().length).toBe(1); + expect(integrations.list()[0].config.host).toBe('storage.cloud.google.com'); + }); + + it('returns default integration when no config', () => { + const integrations = GoogleGcsIntegration.factory({ + config: new ConfigReader({ + integrations: {}, + }), + }); + expect(integrations.list().length).toBe(1); + expect(integrations.list()[0].config.host).toBe('storage.cloud.google.com'); + }); + + it('returns the basics', () => { + const integration = new GoogleGcsIntegration({ + host: 'storage.cloud.google.com', + }); + expect(integration.type).toBe('googleGcs'); + expect(integration.title).toBe('storage.cloud.google.com'); + }); + + describe('resolveUrl', () => { + it('works for valid urls', () => { + const integration = new GoogleGcsIntegration({ + host: 'storage.cloud.google.com', + }); + + expect( + integration.resolveUrl({ + url: 'https://storage.cloud.google.com/bucket/catalog-info.yaml', + base: 'https://storage.cloud.google.com/bucket/catalog-info.yaml', + }), + ).toBe('https://storage.cloud.google.com/bucket/catalog-info.yaml'); + }); + }); + + it('resolve edit URL', () => { + const integration = new GoogleGcsIntegration({ + host: 'storage.cloud.google.com', + }); + + expect( + integration.resolveEditUrl( + 'https://storage.cloud.google.com/bucket/catalog-info.yaml', + ), + ).toBe('https://storage.cloud.google.com/bucket/catalog-info.yaml'); + }); +}); diff --git a/packages/integration/src/googleGcs/GoogleGcsIntegration.ts b/packages/integration/src/googleGcs/GoogleGcsIntegration.ts new file mode 100644 index 0000000000..11642a231c --- /dev/null +++ b/packages/integration/src/googleGcs/GoogleGcsIntegration.ts @@ -0,0 +1,71 @@ +/* + * 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 { basicIntegrations, defaultScmResolveUrl } from '../helpers'; +import { ScmIntegration, ScmIntegrationsFactory } from '../types'; +import { + GoogleGcsIntegrationConfig, + readGoogleGcsIntegrationConfig, + GOOGLE_GCS_HOST, +} from './config'; + +/** + * A Google Cloud Storage based integration. + * + * @public + */ +export class GoogleGcsIntegration implements ScmIntegration { + static factory: ScmIntegrationsFactory = ({ + config, + }) => { + const gcsConfig = config.has('integrations.googleGcs') + ? readGoogleGcsIntegrationConfig( + config.getConfig('integrations.googleGcs'), + ) + : { host: GOOGLE_GCS_HOST }; + + return basicIntegrations( + [new GoogleGcsIntegration(gcsConfig)], + i => i.config.host, + ); + }; + + get type(): string { + return 'googleGcs'; + } + + get title(): string { + return this.integrationConfig.host; + } + + get config(): GoogleGcsIntegrationConfig { + return this.integrationConfig; + } + + constructor(private readonly integrationConfig: GoogleGcsIntegrationConfig) {} + + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string { + return defaultScmResolveUrl(options); + } + + resolveEditUrl(url: string): string { + return url; + } +} diff --git a/packages/integration/src/googleGcs/config.test.ts b/packages/integration/src/googleGcs/config.test.ts index 892440c64a..d074cb7129 100644 --- a/packages/integration/src/googleGcs/config.test.ts +++ b/packages/integration/src/googleGcs/config.test.ts @@ -33,13 +33,16 @@ describe('readGoogleGcsIntegrationConfig', () => { }), ); expect(output).toEqual({ + host: 'storage.cloud.google.com', privateKey: 'fake-key', clientEmail: 'someone@example.com', }); }); - it('does not fail when config is not set', () => { + it('returns default config when config is not set', () => { const output = readGoogleGcsIntegrationConfig(buildConfig({})); - expect(output).toEqual({}); + expect(output).toEqual({ + host: 'storage.cloud.google.com', + }); }); }); diff --git a/packages/integration/src/googleGcs/config.ts b/packages/integration/src/googleGcs/config.ts index 3c03204e4c..9421b9dfba 100644 --- a/packages/integration/src/googleGcs/config.ts +++ b/packages/integration/src/googleGcs/config.ts @@ -16,12 +16,22 @@ import { Config } from '@backstage/config'; +/** + * The default Google Cloud Storage host. + * + */ +export const GOOGLE_GCS_HOST = 'storage.cloud.google.com'; + /** * The configuration parameters for a single Google Cloud Storage provider. * * @public */ export type GoogleGcsIntegrationConfig = { + /** + * The host of the target that this matches on. + */ + host: string; /** * Service account email used to authenticate requests. */ @@ -42,15 +52,19 @@ export function readGoogleGcsIntegrationConfig( config: Config, ): GoogleGcsIntegrationConfig { if (!config) { - return {}; + return { host: GOOGLE_GCS_HOST }; } if (!config.has('clientEmail') && !config.has('privateKey')) { - return {}; + return { host: GOOGLE_GCS_HOST }; } const privateKey = config.getString('privateKey').split('\\n').join('\n'); - const clientEmail = config.getString('clientEmail'); - return { clientEmail: clientEmail, privateKey: privateKey }; + + return { + host: GOOGLE_GCS_HOST, + clientEmail, + privateKey, + }; } diff --git a/packages/integration/src/googleGcs/index.ts b/packages/integration/src/googleGcs/index.ts index 3d7beae59d..c30138fc3e 100644 --- a/packages/integration/src/googleGcs/index.ts +++ b/packages/integration/src/googleGcs/index.ts @@ -16,3 +16,4 @@ export { readGoogleGcsIntegrationConfig } from './config'; export type { GoogleGcsIntegrationConfig } from './config'; +export { GoogleGcsIntegration } from './GoogleGcsIntegration'; diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index d9fe8257fe..80904e4d06 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/repo-tools +## 0.16.1 + +### Patch Changes + +- 688f070: Updated to use new utilities from `@backstage/cli-common`. +- 85895f9: Updates OpenAPI generator templates to preserve original property names (like 'group-name', 'user-id') from OpenAPI specs when propertyNaming=original is specified. Previously, these were always converted to camelCase regardless of the propertyNaming setting. + + - Updates modelGeneric.mustache templates in both client and server generators + - Updates modelTaggedUnion.mustache templates in both client and server generators + - Uses {{baseName}} when available, falls back to {{name}} for backward compatibility + - Maintains backward compatibility - no changes when propertyNaming=original is not used + +- 2bae83a: Bump `@microsoft/api-documenter` and `@microsoft/api-extractor` to latest versions. +- d1e38a7: Properly create workspace in OS temporary directory for `generate-patch` command +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-node@0.2.16 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + ## 0.16.1-next.2 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 95e29cb3f6..8cf1b48d06 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/repo-tools", - "version": "0.16.1-next.2", + "version": "0.16.1", "description": "CLI for Backstage repo tooling ", "backstage": { "role": "cli" diff --git a/packages/scaffolder-internal/CHANGELOG.md b/packages/scaffolder-internal/CHANGELOG.md index 26f3232259..870d3dbd04 100644 --- a/packages/scaffolder-internal/CHANGELOG.md +++ b/packages/scaffolder-internal/CHANGELOG.md @@ -1,5 +1,21 @@ # @internal/scaffolder +## 0.0.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.0.16 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + ## 0.0.16-next.0 ### Patch Changes diff --git a/packages/scaffolder-internal/package.json b/packages/scaffolder-internal/package.json index 94ec12f591..5ceabdd331 100644 --- a/packages/scaffolder-internal/package.json +++ b/packages/scaffolder-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/scaffolder", - "version": "0.0.16-next.0", + "version": "0.0.17-next.0", "backstage": { "role": "web-library", "inline": true diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 63fe804a80..1be62d7997 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,53 @@ # techdocs-cli-embedded-app +## 0.2.116-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.35.2-next.1 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + +## 0.2.116-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/cli@0.35.2-next.0 + - @backstage/app-defaults@1.7.3 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.3 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/test-utils@1.7.14 + - @backstage/theme@0.7.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-techdocs-react@1.3.6 + +## 0.2.115 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/cli@0.35.0 + - @backstage/ui@0.10.0 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/core-components@0.18.4 + - @backstage/test-utils@1.7.14 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/app-defaults@1.7.3 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + ## 0.2.115-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index b0018e634f..a5dfa8f9e2 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.115-next.2", + "version": "0.2.116-next.1", "backstage": { "role": "frontend" }, diff --git a/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.test.tsx b/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.test.tsx index 1a80def9e9..ec99f405ae 100644 --- a/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.test.tsx +++ b/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.test.tsx @@ -15,7 +15,7 @@ */ import { render } from '@testing-library/react'; -import { TechDocsLiveReload } from './LiveReloadAddon'; +import { TechDocsLiveReload, utils } from './LiveReloadAddon'; jest.mock('@backstage/plugin-techdocs-react', () => ({ useShadowRootElements: jest.fn(() => [ @@ -38,12 +38,11 @@ jest.mock('@backstage/plugin-techdocs-react', () => ({ describe('TechDocsLiveReload', () => { const originalXHR = global.XMLHttpRequest; - let originalLocation: Location; let openSpy: jest.Mock; let sendSpy: jest.Mock; + let reloadPageSpy: jest.SpyInstance; beforeEach(() => { - originalLocation = window.location; openSpy = jest.fn(); sendSpy = jest.fn(function (this: any) { // simulate long-poll response that does NOT trigger reload (epoch unchanged) @@ -65,9 +64,11 @@ describe('TechDocsLiveReload', () => { global.XMLHttpRequest = MockXHR as any; - // Replace window.location with a mutable object for tests - delete (window as any).location; - (window as any).location = { ...originalLocation, reload: jest.fn() }; + // Spy on the utils object's reloadPage method + reloadPageSpy = jest + .spyOn(utils, 'reloadPage') + .mockImplementation(() => {}); + jest.spyOn(window, 'addEventListener').mockImplementation(() => {}); jest.spyOn(window, 'removeEventListener').mockImplementation(() => {}); Object.defineProperty(document, 'visibilityState', { @@ -79,23 +80,17 @@ describe('TechDocsLiveReload', () => { afterEach(() => { global.XMLHttpRequest = originalXHR; jest.restoreAllMocks(); - // restore original window.location - delete (window as any).location; - (window as any).location = originalLocation; }); it('polls livereload endpoint and does not reload when epoch unchanged', async () => { - const reloadSpy = window.location.reload as unknown as jest.Mock; render(); expect(openSpy).toHaveBeenCalledWith('GET', '/.livereload/10/1'); // give microtask queue a tick await new Promise(res => setTimeout(res, 0)); - expect(reloadSpy).not.toHaveBeenCalled(); + expect(reloadPageSpy).not.toHaveBeenCalled(); }); it('reloads when server epoch increases', async () => { - const reloadSpy = window.location.reload as unknown as jest.Mock; - sendSpy.mockImplementation(function (this: any) { setTimeout(() => { (this as any).status = 200; @@ -106,6 +101,6 @@ describe('TechDocsLiveReload', () => { render(); await new Promise(res => setTimeout(res, 0)); - expect(reloadSpy).toHaveBeenCalled(); + expect(reloadPageSpy).toHaveBeenCalled(); }); }); diff --git a/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.tsx b/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.tsx index 905a339c72..393704da97 100644 --- a/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.tsx +++ b/packages/techdocs-cli-embedded-app/src/LiveReloadAddon.tsx @@ -17,6 +17,13 @@ import { useShadowRootElements } from '@backstage/plugin-techdocs-react'; import { useEffect, useRef } from 'react'; +/** @internal Exported for testing - allows spying on reloads without spying + * on window.location. + */ +export const utils = { + reloadPage: () => window.location.reload(), +}; + interface TechDocsLiveReloadProps { /** Whether to enable livereload (default: true in development) */ enabled?: boolean; @@ -69,7 +76,7 @@ export const TechDocsLiveReload = ({ reqRef.current = new XMLHttpRequest(); reqRef.current.onloadend = function handleLoadEnd(this: XMLHttpRequest) { if (parseFloat(this.responseText) > epoch) { - window.location.reload(); + utils.reloadPage(); } else { timeoutRef.current = setTimeout(poll, this.status === 200 ? 0 : 3000); } diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 32d6ad189e..3d47d9b0c5 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,35 @@ # @techdocs/cli +## 1.10.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/plugin-techdocs-node@1.13.11-next.0 + +## 1.10.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/cli-common@0.1.16 + - @backstage/config@1.3.6 + - @backstage/plugin-techdocs-node@1.13.10 + +## 1.10.3 + +### Patch Changes + +- 43629b1: Updated to use new utilities from `@backstage/cli-common`. +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-techdocs-node@1.13.10 + - @backstage/cli-common@0.1.16 + ## 1.10.3-next.2 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index fae5187156..a1cb6fa4ec 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,6 +1,6 @@ { "name": "@techdocs/cli", - "version": "1.10.3-next.2", + "version": "1.10.4-next.1", "description": "Utility CLI for managing TechDocs sites in Backstage.", "backstage": { "role": "cli" diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 0d2d782969..71c5aca50a 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/test-utils +## 1.7.14 + +### Patch Changes + +- 97cd16f: Internal update of translation imports. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + ## 1.7.14-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index e14805b620..2e12255bd0 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.7.14-next.0", + "version": "1.7.14", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.ts b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.ts index 3d02db0124..661d202379 100644 --- a/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.ts +++ b/packages/test-utils/src/testUtils/apis/FetchApi/MockFetchApi.ts @@ -127,7 +127,9 @@ function baseImplementation( ): typeof crossFetch { const implementation = options?.baseImplementation; if (!implementation) { - return crossFetch; + // Return a wrapper that evaluates global.fetch at call time, not construction time. + // This allows MSW to patch global.fetch after MockFetchApi is constructed. + return (input, init) => global.fetch(input, init); } else if (implementation === 'none') { return () => Promise.resolve(new Response()); } diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index 42a3f8e092..158499374e 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -92,17 +92,15 @@ 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', - ), - }), - expect.stringMatching(/^The above error occurred in the component:/), + expect.stringContaining( + 'Error: MockErrorApi received unexpected error, Error: NOPE', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining( + 'Error: MockErrorApi received unexpected error, Error: NOPE', + ), + expect.objectContaining({ type: 'unhandled-exception' }), + expect.stringContaining('The above error occurred in the component:'), ]); }); diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 3eb2340d47..bbe9ae3fc9 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/theme +## 0.7.1 + +### Patch Changes + +- fa06f6b: Added a `themeName` prop to `UnifiedThemeProvider`, enabling Backstage UI `data-theme-name` CSS attribute to be set based on active theme. + ## 0.7.1-next.0 ### Patch Changes diff --git a/packages/theme/package.json b/packages/theme/package.json index cc0fe2237a..645255d601 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/theme", - "version": "0.7.1-next.0", + "version": "0.7.1", "description": "material-ui theme for use with Backstage.", "backstage": { "role": "web-library" diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md index 9f867ba2ed..c692731a10 100644 --- a/packages/ui/CHANGELOG.md +++ b/packages/ui/CHANGELOG.md @@ -1,5 +1,80 @@ # @backstage/ui +## 0.11.0-next.0 + +### Minor Changes + +- 4ea1d15: **BREAKING**: Renamed CSS variable `--bui-bg` to `--bui-bg-surface-0` for consistency. + +### Patch Changes + +- 1880402: Fixes app background color on dark mode. +- 9c76682: build(deps-dev): bump `storybook` from 10.1.9 to 10.1.10 +- b4a4911: Fixed SearchField `startCollapsed` prop not working correctly in Backstage UI. The field now properly starts in a collapsed state, expands when clicked and focused, and collapses back when unfocused with no input. Also fixed CSS logic to work correctly in all layout contexts (flex row, flex column, and regular containers). + + Affected components: SearchField + +## 0.10.0 + +### Minor Changes + +- 16543fa: **Breaking change** The `Cell` component has been refactored to be a generic wrapper component that accepts `children` for custom cell content. The text-specific functionality (previously part of `Cell`) has been moved to a new `CellText` component. + + ### Migration Guide + + If you were using `Cell` with text-specific props (`title`, `description`, `leadingIcon`, `href`), you need to update your code to use `CellText` instead: + + **Before:** + + ```tsx + } + href="/path" + /> + ``` + + **After:** + + ```tsx + } + href="/path" + /> + ``` + + For custom cell content, use the new generic `Cell` component: + + ```tsx + {/* Your custom content */} + ``` + +### Patch Changes + +- 50b7927: Fixed Checkbox indicator showing checkmark color when unchecked. + + Affected components: Checkbox + +- 5bacf55: Fixed `ButtonIcon` incorrectly applying `className` to inner elements instead of only the root element. + + Affected components: ButtonIcon + +- b3ad928: Fixed Table Row component to correctly handle cases where no `href` is provided, preventing unnecessary router provider wrapping and fixing the cursor incorrectly showing as a pointer despite the element not being a link. + + Affected components: Row + +- a20d317: Added row selection support with visual state styling for hover, selected, and pressed states. Fixed checkbox rendering to only show for multi-select toggle mode. + + Affected components: Table, TableHeader, Row, Column + +- fe7c751: Fixed `useTable` hook to prioritize `providedRowCount` over data length for accurate row count in server-side pagination scenarios. +- c145031: Fixed Table column sorting indicator to show up arrow when no sort is active, correctly indicating that clicking will sort ascending. + + Affected components: Column + ## 0.10.0-next.1 ### Minor Changes diff --git a/packages/ui/css/styles.css b/packages/ui/css/styles.css index c96eda05c9..f79b954080 100644 --- a/packages/ui/css/styles.css +++ b/packages/ui/css/styles.css @@ -51,9 +51,10 @@ --bui-gray-6: #8c8c8c; --bui-gray-7: #757575; --bui-gray-8: #595959; - --bui-bg: var(--bui-gray-1); + --bui-bg-surface-0: var(--bui-gray-1); --bui-bg-surface-1: var(--bui-white); - --bui-bg-surface-2: var(--bui-gray-2); + --bui-bg-surface-2: var(--bui-gray-1); + --bui-bg-surface-3: var(--bui-gray-2); --bui-bg-solid: #1f5493; --bui-bg-solid-hover: #163a66; --bui-bg-solid-pressed: #0f2b4e; @@ -99,9 +100,10 @@ --bui-gray-6: #7b7b7b; --bui-gray-7: #9e9e9e; --bui-gray-8: #b4b4b4; - --bui-bg: #333; - --bui-bg-surface-1: #424242; + --bui-bg-surface-0: #333; + --bui-bg-surface-1: var(--bui-gray-1); --bui-bg-surface-2: var(--bui-gray-2); + --bui-bg-surface-3: var(--bui-gray-3); --bui-bg-solid: #9cc9ff; --bui-bg-solid-hover: #83b9fd; --bui-bg-solid-pressed: #83b9fd; @@ -239,7 +241,7 @@ } body { - background-color: var(--bui-bg); + background-color: var(--bui-bg-surface-0); color: var(--bui-fg-primary); font-family: var(--bui-font-regular); font-weight: var(--bui-font-weight-regular); diff --git a/packages/ui/package.json b/packages/ui/package.json index 3ac6e991c8..a5461c6726 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/ui", - "version": "0.10.0-next.1", + "version": "0.11.0-next.0", "backstage": { "role": "web-library" }, @@ -50,7 +50,7 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "chalk": "^5.4.1", - "eslint-plugin-storybook": "^9.1.7", + "eslint-plugin-storybook": "^10.1.9", "glob": "^11.0.1", "globals": "^15.11.0", "lightningcss": "^1.29.1", @@ -58,7 +58,7 @@ "react": "^18.0.2", "react-dom": "^18.0.2", "react-router-dom": "^6.3.0", - "storybook": "^9.1.7" + "storybook": "^10.1.10" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", diff --git a/packages/ui/src/components/Accordion/Accordion.stories.tsx b/packages/ui/src/components/Accordion/Accordion.stories.tsx index 6640bd5d6a..541cce5c84 100644 --- a/packages/ui/src/components/Accordion/Accordion.stories.tsx +++ b/packages/ui/src/components/Accordion/Accordion.stories.tsx @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Accordion, AccordionTrigger, @@ -36,15 +35,12 @@ const Content = () => ( ); -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Accordion', component: Accordion, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: () => ( @@ -53,9 +49,9 @@ export const Default: Story = { ), -}; +}); -export const WithSubtitle: Story = { +export const WithSubtitle = meta.story({ render: () => ( ), -}; +}); -export const CustomTrigger: Story = { +export const CustomTrigger = meta.story({ render: () => ( @@ -87,9 +83,9 @@ export const CustomTrigger: Story = { ), -}; +}); -export const DefaultExpanded: Story = { +export const DefaultExpanded = meta.story({ render: () => ( @@ -98,9 +94,9 @@ export const DefaultExpanded: Story = { ), -}; +}); -export const GroupSingleOpen: Story = { +export const GroupSingleOpen = meta.story({ render: () => ( @@ -136,9 +132,9 @@ export const GroupSingleOpen: Story = { ), -}; +}); -export const GroupMultipleOpen: Story = { +export const GroupMultipleOpen = meta.story({ render: () => ( @@ -174,4 +170,4 @@ export const GroupMultipleOpen: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Avatar/Avatar.stories.tsx b/packages/ui/src/components/Avatar/Avatar.stories.tsx index 582d82393e..75c1e68a67 100644 --- a/packages/ui/src/components/Avatar/Avatar.stories.tsx +++ b/packages/ui/src/components/Avatar/Avatar.stories.tsx @@ -13,36 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Avatar } from './index'; import { Flex, Text } from '../..'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Avatar', component: Avatar, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { src: 'https://avatars.githubusercontent.com/u/1540635?v=4', name: 'Charles de Dreuille', }, -}; +}); -export const Fallback: Story = { +export const Fallback = meta.story({ args: { - ...Default.args, + ...Default.input.args, src: 'https://avatars.githubusercontent.com/u/15406AAAAAAAAA', }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -62,11 +58,11 @@ export const Sizes: Story = { ), -}; +}); -export const Purpose: Story = { +export const Purpose = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -93,4 +89,4 @@ export const Purpose: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Box/Box.stories.tsx b/packages/ui/src/components/Box/Box.stories.tsx index 6637f45740..766a6668c7 100644 --- a/packages/ui/src/components/Box/Box.stories.tsx +++ b/packages/ui/src/components/Box/Box.stories.tsx @@ -1,3 +1,4 @@ +import preview from '../../../../../.storybook/preview'; /* * Copyright 2024 The Backstage Authors * @@ -15,11 +16,10 @@ */ import { ReactNode } from 'react'; -import type { Meta, StoryObj } from '@storybook/react-vite'; import { Box } from './Box'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Box', component: Box, argTypes: { @@ -31,10 +31,7 @@ const meta = { control: false, }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const diagonalStripePattern = (() => { const svg = ` @@ -47,7 +44,7 @@ const diagonalStripePattern = (() => { return `data:image/svg+xml,${encodeURIComponent(svg)}`; })(); -export const Default: Story = { +export const Default = meta.story({ args: { width: '64px', height: '64px', @@ -63,10 +60,10 @@ export const Default: Story = { color: '#2563eb', }, }, -}; +}); -export const Margin: Story = { - args: { ...Default.args }, +export const Margin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -89,10 +86,10 @@ export const Margin: Story = { ), -}; +}); -export const ResponsiveMargin: Story = { - args: { ...Default.args }, +export const ResponsiveMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -115,10 +112,10 @@ export const ResponsiveMargin: Story = { ), -}; +}); -export const CustomMargin: Story = { - args: { ...Default.args }, +export const CustomMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -141,10 +138,10 @@ export const CustomMargin: Story = { ), -}; +}); -export const CustomResponsiveMargin: Story = { - args: { ...Default.args }, +export const CustomResponsiveMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -167,10 +164,10 @@ export const CustomResponsiveMargin: Story = { ), -}; +}); -export const Padding: Story = { - args: { ...Default.args }, +export const Padding = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -193,10 +190,10 @@ export const Padding: Story = { ), -}; +}); -export const ResponsivePadding: Story = { - args: { ...Default.args }, +export const ResponsivePadding = meta.story({ + args: { ...Default.input.args }, render: args => ( ), -}; +}); -export const CustomPadding: Story = { - args: { ...Default.args }, +export const CustomPadding = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -263,10 +260,10 @@ export const CustomPadding: Story = { ), -}; +}); -export const CustomResponsivePadding: Story = { - args: { ...Default.args }, +export const CustomResponsivePadding = meta.story({ + args: { ...Default.input.args }, render: args => ( ), -}; +}); const CardDisplay = ({ children }: { children?: ReactNode }) => { return ( @@ -327,7 +324,7 @@ const CardDisplay = ({ children }: { children?: ReactNode }) => { ); }; -export const Display: Story = { +export const Display = meta.story({ render: args => ( @@ -346,4 +343,4 @@ export const Display: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Button/Button.stories.tsx b/packages/ui/src/components/Button/Button.stories.tsx index 4734770aa4..141db4da96 100644 --- a/packages/ui/src/components/Button/Button.stories.tsx +++ b/packages/ui/src/components/Button/Button.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Button } from './Button'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { RiArrowRightSLine, RiCloudLine } from '@remixicon/react'; import { useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Button', component: Button, argTypes: { @@ -34,18 +33,15 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Button', }, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ args: { children: 'Button', }, @@ -69,9 +65,9 @@ export const Variants: Story = { ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { children: 'Button', }, @@ -85,9 +81,9 @@ export const Sizes: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { children: 'Button', }, @@ -102,9 +98,9 @@ export const WithIcons: Story = { /> ), -}; +}); -export const FullWidth: Story = { +export const FullWidth = meta.story({ args: { children: 'Button', }, @@ -119,9 +115,9 @@ export const FullWidth: Story = { /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { children: 'Button', variant: { @@ -149,12 +145,12 @@ export const Responsive: Story = { sm: 'medium', }, }, -}; +}); const variants = ['primary', 'secondary'] as const; const sizes = ['small', 'medium'] as const; -export const Playground: Story = { +export const Playground = meta.story({ args: { children: 'Button', }, @@ -212,9 +208,9 @@ export const Playground: Story = { ))} ), -}; +}); -export const Loading: Story = { +export const Loading = meta.story({ render: () => { const [isLoading, setIsLoading] = useState(false); @@ -231,9 +227,9 @@ export const Loading: Story = { ); }, -}; +}); -export const LoadingVariants: Story = { +export const LoadingVariants = meta.story({ render: () => ( Primary @@ -289,4 +285,4 @@ export const LoadingVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx b/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx index 97072c3664..be6dad7754 100644 --- a/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx +++ b/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { ButtonIcon } from './ButtonIcon'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { RiCloudLine } from '@remixicon/react'; import { useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/ButtonIcon', component: ButtonIcon, argTypes: { @@ -34,16 +33,13 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: () => } />, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ render: () => ( } variant="primary" /> @@ -51,18 +47,18 @@ export const Variants: Story = { } variant="tertiary" /> ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ render: () => ( } size="small" /> } size="medium" /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( } variant="primary" /> @@ -70,9 +66,9 @@ export const Disabled: Story = { } variant="tertiary" /> ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { variant: { initial: 'primary', @@ -84,9 +80,9 @@ export const Responsive: Story = { }, }, render: args => } />, -}; +}); -export const Loading: Story = { +export const Loading = meta.story({ render: () => { const [isLoading, setIsLoading] = useState(false); @@ -106,9 +102,9 @@ export const Loading: Story = { /> ); }, -}; +}); -export const LoadingVariants: Story = { +export const LoadingVariants = meta.story({ render: () => ( Primary @@ -172,4 +168,4 @@ export const LoadingVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx b/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx index 7d288065a4..4b9b9b747c 100644 --- a/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx +++ b/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { ButtonLink } from './ButtonLink'; import { Flex } from '../Flex'; import { MemoryRouter } from 'react-router-dom'; import { RiArrowRightSLine, RiCloudLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/ButtonLink', component: ButtonLink, decorators: [ @@ -40,18 +41,15 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Button', }, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ render: () => ( ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { children: 'Button', }, @@ -96,9 +94,9 @@ export const Sizes: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { children: 'Button', }, @@ -113,9 +111,9 @@ export const WithIcons: Story = { /> ), -}; +}); -export const FullWidth: Story = { +export const FullWidth = meta.story({ args: { children: 'Button', }, @@ -130,9 +128,9 @@ export const FullWidth: Story = { /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( @@ -146,9 +144,9 @@ export const Disabled: Story = { ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { children: 'Button', variant: { @@ -160,4 +158,4 @@ export const Responsive: Story = { sm: 'medium', }, }, -}; +}); diff --git a/packages/ui/src/components/Card/Card.stories.tsx b/packages/ui/src/components/Card/Card.stories.tsx index 170d2b7984..f2a9c9bf07 100644 --- a/packages/ui/src/components/Card/Card.stories.tsx +++ b/packages/ui/src/components/Card/Card.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Card, CardHeader, CardBody, CardFooter } from './Card'; import { Text } from '../..'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Card', component: Card, subcomponents: { CardHeader, CardBody, CardFooter }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: args => ( Header @@ -35,19 +31,19 @@ export const Default: Story = { Footer ), -}; +}); -export const CustomSize: Story = { +export const CustomSize = meta.story({ args: { style: { width: '300px', height: '200px', }, }, - render: Default.render, -}; + render: Default.input.render, +}); -export const WithLongBody: Story = { +export const WithLongBody = meta.story({ render: () => ( @@ -77,7 +73,7 @@ export const WithLongBody: Story = { ), -}; +}); const ListRow = ({ children }: { children: React.ReactNode }) => { return ( @@ -99,7 +95,7 @@ const ListRow = ({ children }: { children: React.ReactNode }) => { ); }; -export const WithListRow: Story = { +export const WithListRow = meta.story({ render: () => ( @@ -128,4 +124,4 @@ export const WithListRow: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Checkbox/Checkbox.stories.tsx b/packages/ui/src/components/Checkbox/Checkbox.stories.tsx index a41b7f2c8d..c5318cc6fb 100644 --- a/packages/ui/src/components/Checkbox/Checkbox.stories.tsx +++ b/packages/ui/src/components/Checkbox/Checkbox.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,27 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Checkbox } from './Checkbox'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Checkbox', component: Checkbox, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Accept terms and conditions', }, -}; +}); -export const AllVariants: Story = { - ...Default, +export const AllVariants = meta.story({ + ...Default.input, render: () => ( Unchecked @@ -44,4 +40,4 @@ export const AllVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Container/Container.stories.tsx b/packages/ui/src/components/Container/Container.stories.tsx index 504cb3de87..44ff6f2d17 100644 --- a/packages/ui/src/components/Container/Container.stories.tsx +++ b/packages/ui/src/components/Container/Container.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Box } from '../Box/Box'; import { Container } from './Container'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Container', component: Container, parameters: { @@ -32,10 +31,7 @@ const meta = { control: 'text', }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const DecorativeBox = () => ( ( /> ); -export const Default: Story = { +export const Default = meta.story({ args: { children: , }, -}; +}); -export const Preview: Story = { +export const Preview = meta.story({ render: () => (
), -}; +}); -export const WithPaddingY: Story = { +export const WithPaddingY = meta.story({ args: { - ...Default.args, + ...Default.input.args, py: '4', }, -}; +}); -export const WithPaddingTop: Story = { +export const WithPaddingTop = meta.story({ args: { - ...Default.args, + ...Default.input.args, pt: '4', }, -}; +}); -export const WithPaddingBottom: Story = { +export const WithPaddingBottom = meta.story({ args: { - ...Default.args, + ...Default.input.args, pb: '4', }, -}; +}); -export const WithMarginY: Story = { +export const WithMarginY = meta.story({ args: { - ...Default.args, + ...Default.input.args, my: '4', }, -}; +}); -export const WithMarginTop: Story = { +export const WithMarginTop = meta.story({ args: { - ...Default.args, + ...Default.input.args, mt: '4', }, -}; +}); -export const WithMarginBottom: Story = { +export const WithMarginBottom = meta.story({ args: { - ...Default.args, + ...Default.input.args, mb: '4', }, -}; +}); diff --git a/packages/ui/src/components/Dialog/Dialog.stories.tsx b/packages/ui/src/components/Dialog/Dialog.stories.tsx index 98d2492913..7c7edc1801 100644 --- a/packages/ui/src/components/Dialog/Dialog.stories.tsx +++ b/packages/ui/src/components/Dialog/Dialog.stories.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; + +import preview from '../../../../../.storybook/preview'; import { Dialog, DialogTrigger, @@ -24,7 +25,7 @@ import { import { Button, Flex, Text, TextField, Select } from '@backstage/ui'; import { useArgs } from 'storybook/preview-api'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Dialog', component: Dialog, args: { @@ -35,12 +36,9 @@ const meta = { isOpen: { control: 'boolean' }, defaultOpen: { control: 'boolean' }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: args => { return ( @@ -62,17 +60,15 @@ export const Default: Story = { ); }, -}; +}); -export const Open: Story = { +export const Open = Default.extend({ args: { - ...Default.args, defaultOpen: true, }, - render: Default.render, -}; +}); -export const NoTrigger: Story = { +export const NoTrigger = meta.story({ args: { isOpen: true, }, @@ -100,9 +96,9 @@ export const NoTrigger: Story = { ); }, -}; +}); -export const FixedWidth: Story = { +export const FixedWidth = meta.story({ args: { defaultOpen: true, width: 600, @@ -145,35 +141,35 @@ export const FixedWidth: Story = { ), -}; +}); -export const FixedHeight: Story = { +export const FixedHeight = meta.story({ args: { defaultOpen: true, height: 500, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const FixedWidthAndHeight: Story = { +export const FixedWidthAndHeight = meta.story({ args: { defaultOpen: true, width: 600, height: 400, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const FullWidthAndHeight: Story = { +export const FullWidthAndHeight = meta.story({ args: { defaultOpen: true, width: '100%', height: '100%', }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const Confirmation: Story = { +export const Confirmation = meta.story({ args: { isOpen: true, }, @@ -199,9 +195,9 @@ export const Confirmation: Story = { ), -}; +}); -export const WithForm: Story = { +export const WithForm = meta.story({ args: { isOpen: true, }, @@ -235,20 +231,20 @@ export const WithForm: Story = { ), -}; +}); -export const PreviewFixedWidthAndHeight: Story = { +export const PreviewFixedWidthAndHeight = meta.story({ args: { defaultOpen: undefined, width: 600, height: 400, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const PreviewWithForm: Story = { +export const PreviewWithForm = meta.story({ args: { defaultOpen: undefined, }, - render: WithForm.render, -}; + render: WithForm.input.render, +}); diff --git a/packages/ui/src/components/FieldError/FieldError.stories.tsx b/packages/ui/src/components/FieldError/FieldError.stories.tsx index 1922e12a0d..a0b2a05b92 100644 --- a/packages/ui/src/components/FieldError/FieldError.stories.tsx +++ b/packages/ui/src/components/FieldError/FieldError.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { TextField, Input, Form } from 'react-aria-components'; import { FieldError } from './FieldError'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/FieldError', component: FieldError, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); // Show error with server validation using Form component -export const WithServerValidation: Story = { +export const WithServerValidation = meta.story({ render: () => (
), -}; +}); // Show error using children -export const WithCustomMessage: Story = { +export const WithCustomMessage = meta.story({ render: () => ( This is a custom error message. ), -}; +}); // Show error with render prop function -export const WithRenderProp: Story = { +export const WithRenderProp = meta.story({ render: () => ( ), -}; +}); diff --git a/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx b/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx index d0e8f3e4fb..178df67284 100644 --- a/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx +++ b/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { FieldLabel } from './FieldLabel'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/FieldLabel', component: FieldLabel, argTypes: { @@ -31,35 +30,32 @@ const meta = { control: 'text', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { label: 'Label', }, -}; +}); -export const WithSecondaryLabel: Story = { +export const WithSecondaryLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, secondaryLabel: 'Secondary Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...Default.args, + ...Default.input.args, description: 'Description', }, -}; +}); -export const WithAllFields: Story = { +export const WithAllFields = meta.story({ args: { - ...Default.args, + ...Default.input.args, secondaryLabel: 'Secondary Label', description: 'Description', }, -}; +}); diff --git a/packages/ui/src/components/Flex/Flex.stories.tsx b/packages/ui/src/components/Flex/Flex.stories.tsx index 87854e89c7..17ee740997 100644 --- a/packages/ui/src/components/Flex/Flex.stories.tsx +++ b/packages/ui/src/components/Flex/Flex.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Flex } from './Flex'; import { Text } from '../Text'; import { Box } from '../Box'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Flex', component: Flex, argTypes: { @@ -36,10 +35,7 @@ const meta = { options: ['row', 'column', 'row-reverse', 'column-reverse'], }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const DecorativeBox = ({ width = '48px', @@ -78,7 +74,7 @@ const DecorativeBox = ({ ); }; -export const Default: Story = { +export const Default = meta.story({ args: { children: ( <> @@ -88,23 +84,23 @@ export const Default: Story = { ), }, -}; +}); -export const ColumnDirection: Story = { +export const ColumnDirection = meta.story({ args: { - ...Default.args, + ...Default.input.args, direction: 'column', }, -}; +}); -export const RowDirection: Story = { +export const RowDirection = meta.story({ args: { - ...Default.args, + ...Default.input.args, direction: 'row', }, -}; +}); -export const AlignStartInColumn: Story = { +export const AlignStartInColumn = meta.story({ args: { align: 'start', direction: 'column', @@ -116,9 +112,9 @@ export const AlignStartInColumn: Story = { ), -}; +}); -export const AlignStartInRow: Story = { +export const AlignStartInRow = meta.story({ args: { align: 'start', direction: 'row', @@ -130,9 +126,9 @@ export const AlignStartInRow: Story = { ), -}; +}); -export const AlignCenterInColumn: Story = { +export const AlignCenterInColumn = meta.story({ args: { align: 'center', direction: 'column', @@ -144,9 +140,9 @@ export const AlignCenterInColumn: Story = { ), -}; +}); -export const AlignCenterInRow: Story = { +export const AlignCenterInRow = meta.story({ args: { align: 'center', direction: 'row', @@ -158,9 +154,9 @@ export const AlignCenterInRow: Story = { ), -}; +}); -export const AlignEndInColumn: Story = { +export const AlignEndInColumn = meta.story({ args: { align: 'end', direction: 'column', @@ -172,9 +168,9 @@ export const AlignEndInColumn: Story = { ), -}; +}); -export const AlignEndInRow: Story = { +export const AlignEndInRow = meta.story({ args: { align: 'end', direction: 'row', @@ -186,9 +182,9 @@ export const AlignEndInRow: Story = { ), -}; +}); -export const ResponsiveAlign: Story = { +export const ResponsiveAlign = meta.story({ args: { align: { xs: 'start', md: 'center', lg: 'end' }, }, @@ -199,9 +195,9 @@ export const ResponsiveAlign: Story = { ), -}; +}); -export const ResponsiveGap: Story = { +export const ResponsiveGap = meta.story({ args: { gap: { xs: '4', md: '8', lg: '12' }, }, @@ -212,9 +208,9 @@ export const ResponsiveGap: Story = { ), -}; +}); -export const LargeGap: Story = { +export const LargeGap = meta.story({ args: { gap: '8', }, @@ -225,9 +221,9 @@ export const LargeGap: Story = { ), -}; +}); -export const WithTextTruncate: Story = { +export const WithTextTruncate = meta.story({ render: () => ( @@ -246,4 +242,4 @@ export const WithTextTruncate: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Grid/Grid.stories.tsx b/packages/ui/src/components/Grid/Grid.stories.tsx index 66ea346b4f..56251b6085 100644 --- a/packages/ui/src/components/Grid/Grid.stories.tsx +++ b/packages/ui/src/components/Grid/Grid.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Grid } from './Grid'; import type { GridItemProps } from './types'; import { Box } from '../Box/Box'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Grid', component: Grid.Root, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const FakeBox = () => ( ( /> ); -export const Default: Story = { +export const Default = meta.story({ args: { children: ( <> @@ -51,16 +47,16 @@ export const Default: Story = { ), }, -}; +}); -export const LargeGap: Story = { +export const LargeGap = meta.story({ args: { - ...Default.args, + ...Default.input.args, gap: '64px', }, -}; +}); -export const ColumnSizes: Story = { +export const ColumnSizes = meta.story({ args: { columns: '12', }, @@ -78,9 +74,9 @@ export const ColumnSizes: Story = { ))} ), -}; +}); -export const RowAndColumns: Story = { +export const RowAndColumns = meta.story({ args: { columns: '12', }, @@ -106,4 +102,4 @@ export const RowAndColumns: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Header/Header.module.css b/packages/ui/src/components/Header/Header.module.css index ad50c42e0c..031cfd4d16 100644 --- a/packages/ui/src/components/Header/Header.module.css +++ b/packages/ui/src/components/Header/Header.module.css @@ -27,7 +27,7 @@ left: 0px; right: 0px; height: 16px; - background-color: var(--bui-bg); + background-color: var(--bui-bg-surface-0); z-index: 0; } diff --git a/packages/ui/src/components/Header/Header.stories.tsx b/packages/ui/src/components/Header/Header.stories.tsx index 6ccda8bb50..7d1aa3a00a 100644 --- a/packages/ui/src/components/Header/Header.stories.tsx +++ b/packages/ui/src/components/Header/Header.stories.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import type { Meta, StoryObj, StoryFn } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { Header } from './Header'; import type { HeaderTab } from './types'; import { @@ -36,16 +37,13 @@ import { } from '@remixicon/react'; import { HeaderPageBreadcrumb } from '../HeaderPage/types'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Header', component: Header, parameters: { layout: 'fullscreen', }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const withRouter = (Story: StoryFn) => ( @@ -199,19 +197,19 @@ const layoutDecorator = [ withRouter, ]; -export const Default: Story = { +export const Default = meta.story({ args: {}, decorators: [withRouter], -}; +}); -export const WithTabs: Story = { +export const WithTabs = meta.story({ args: { tabs, }, decorators: [withRouter], -}; +}); -export const WithCustomActions: Story = { +export const WithCustomActions = meta.story({ args: {}, decorators: [withRouter], render: args => ( @@ -240,20 +238,20 @@ export const WithCustomActions: Story = { } /> ), -}; +}); -export const WithAllOptionsAndTabs: Story = { +export const WithAllOptionsAndTabs = meta.story({ args: { - ...WithCustomActions.args, + ...WithCustomActions.input.args, tabs, }, decorators: [withRouter], - render: WithCustomActions.render, -}; + render: WithCustomActions.input.render, +}); -export const WithHeaderPage: Story = { +export const WithHeaderPage = meta.story({ args: { - ...WithAllOptionsAndTabs.args, + ...WithAllOptionsAndTabs.input.args, }, decorators: [withRouter], render: args => ( @@ -276,9 +274,9 @@ export const WithHeaderPage: Story = { /> ), -}; +}); -export const WithLayout: Story = { +export const WithLayout = meta.story({ decorators: layoutDecorator, render: args => ( <> @@ -291,9 +289,9 @@ export const WithLayout: Story = { /> ), -}; +}); -export const WithLayoutNoTabs: Story = { +export const WithLayoutNoTabs = meta.story({ decorators: layoutDecorator, render: args => ( <> @@ -301,9 +299,9 @@ export const WithLayoutNoTabs: Story = { ), -}; +}); -export const WithEverything: Story = { +export const WithEverything = meta.story({ args: { tabs, titleLink: '/', @@ -333,9 +331,9 @@ export const WithEverything: Story = { /> ), -}; +}); -export const WithMockedURLCampaigns: Story = { +export const WithMockedURLCampaigns = meta.story({ args: { tabs, }, @@ -353,9 +351,9 @@ export const WithMockedURLCampaigns: Story = { ), -}; +}); -export const WithMockedURLIntegrations: Story = { +export const WithMockedURLIntegrations = meta.story({ args: { tabs, }, @@ -373,9 +371,9 @@ export const WithMockedURLIntegrations: Story = { ), -}; +}); -export const WithMockedURLNoMatch: Story = { +export const WithMockedURLNoMatch = meta.story({ args: { tabs, }, @@ -397,9 +395,9 @@ export const WithMockedURLNoMatch: Story = { ), -}; +}); -export const WithTabsMatchingStrategies: Story = { +export const WithTabsMatchingStrategies = meta.story({ args: { title: 'Route Matching Demo', tabs: [ @@ -457,9 +455,9 @@ export const WithTabsMatchingStrategies: Story = { ), -}; +}); -export const WithTabsExactMatching: Story = { +export const WithTabsExactMatching = meta.story({ args: { title: 'Exact Matching Demo', tabs: [ @@ -496,9 +494,9 @@ export const WithTabsExactMatching: Story = { ), -}; +}); -export const WithTabsPrefixMatchingDeep: Story = { +export const WithTabsPrefixMatchingDeep = meta.story({ args: { title: 'Deep Nesting Demo', tabs: [ @@ -548,4 +546,4 @@ export const WithTabsPrefixMatchingDeep: Story = { ), -}; +}); diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx index ab527bcda4..0631a6111d 100644 --- a/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx +++ b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx @@ -1,3 +1,4 @@ +import preview from '../../../../../.storybook/preview'; /* * Copyright 2025 The Backstage Authors * @@ -14,7 +15,7 @@ * limitations under the License. */ -import type { Meta, StoryObj, StoryFn } from '@storybook/react-vite'; +import type { StoryFn } from '@storybook/react-vite'; import { HeaderPage } from './HeaderPage'; import type { HeaderTab } from '../Header/types'; import { MemoryRouter } from 'react-router-dom'; @@ -29,16 +30,13 @@ import { } from '../../'; import { RiMore2Line } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/HeaderPage', component: HeaderPage, parameters: { layout: 'fullscreen', }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const tabs: HeaderTab[] = [ { @@ -130,25 +128,25 @@ const layoutDecorator = [ ), ]; -export const Default: Story = { +export const Default = meta.story({ args: { title: 'Page Title', }, -}; +}); -export const WithTabs: Story = { +export const WithTabs = meta.story({ args: { - ...Default.args, + ...Default.input.args, tabs, }, decorators: [withRouter], -}; +}); -export const WithCustomActions: Story = { +export const WithCustomActions = meta.story({ decorators: [withRouter], render: () => ( @@ -174,48 +172,44 @@ export const WithCustomActions: Story = { } /> ), -}; +}); -export const WithBreadcrumbs: Story = { +export const WithBreadcrumbs = meta.story({ decorators: [withRouter], args: { - ...Default.args, + ...Default.input.args, breadcrumbs: [{ label: 'Home', href: '/' }], }, -}; +}); -export const WithLongBreadcrumbs: Story = { +export const WithLongBreadcrumbs = meta.story({ decorators: [withRouter], args: { - ...Default.args, + ...Default.input.args, breadcrumbs: [ { label: 'Home', href: '/' }, { label: 'Long Breadcrumb Name', href: '/long-breadcrumb' }, ], }, -}; +}); -export const WithEverything: Story = { +export const WithEverything = meta.story({ decorators: [withRouter], render: () => ( Custom action} breadcrumbs={[{ label: 'Home', href: '/' }]} /> ), -}; +}); -export const WithLayout: Story = { - args: { - ...WithEverything.args, - }, - decorators: [withRouter, ...layoutDecorator], - render: WithEverything.render, -}; +export const WithLayout = WithEverything.extend({ + decorators: [...layoutDecorator], +}); -export const WithTabsMatchingStrategies: Story = { +export const WithTabsMatchingStrategies = meta.story({ args: { title: 'Route Matching Demo', tabs: [ @@ -273,9 +267,9 @@ export const WithTabsMatchingStrategies: Story = { ), -}; +}); -export const WithTabsExactMatching: Story = { +export const WithTabsExactMatching = meta.story({ args: { title: 'Exact Matching Demo', tabs: [ @@ -312,9 +306,9 @@ export const WithTabsExactMatching: Story = { ), -}; +}); -export const WithTabsPrefixMatchingDeep: Story = { +export const WithTabsPrefixMatchingDeep = meta.story({ args: { title: 'Deep Nesting Demo', tabs: [ @@ -364,4 +358,4 @@ export const WithTabsPrefixMatchingDeep: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Link/Link.stories.tsx b/packages/ui/src/components/Link/Link.stories.tsx index 37f142c4dc..7d680e5616 100644 --- a/packages/ui/src/components/Link/Link.stories.tsx +++ b/packages/ui/src/components/Link/Link.stories.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { Link } from './Link'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Link', component: Link, args: { @@ -33,29 +34,26 @@ const meta = { ), ], -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { href: '/', children: 'Sign up for Backstage', }, -}; +}); -export const ExternalLink: Story = { +export const ExternalLink = meta.story({ args: { href: 'https://backstage.io', children: 'Sign up for Backstage', target: '_blank', }, -}; +}); -export const AllVariants: Story = { +export const AllVariants = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -69,9 +67,9 @@ export const AllVariants: Story = { ), -}; +}); -export const AllColors: Story = { +export const AllColors = meta.story({ render: () => ( ), -}; +}); -export const AllWeights: Story = { +export const AllWeights = meta.story({ render: () => ( @@ -225,9 +223,9 @@ export const AllWeights: Story = { ), -}; +}); -export const Truncate: Story = { +export const Truncate = meta.story({ args: { children: "A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is in the painting?", @@ -235,21 +233,21 @@ export const Truncate: Story = { truncate: true, style: { width: '480px' }, }, -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { - ...Default.args, + ...Default.input.args, variant: { xs: 'title-x-small', md: 'body-x-small', }, }, -}; +}); -export const Playground: Story = { +export const Playground = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -269,4 +267,4 @@ export const Playground: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/Menu.stories.tsx b/packages/ui/src/components/Menu/Menu.stories.tsx index 7171b3ef83..ffe184d4ae 100644 --- a/packages/ui/src/components/Menu/Menu.stories.tsx +++ b/packages/ui/src/components/Menu/Menu.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, SubmenuTrigger, @@ -38,7 +38,7 @@ import { import { MemoryRouter } from 'react-router-dom'; import { useEffect, useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Menu', component: MenuTrigger, decorators: [ @@ -48,10 +48,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -65,7 +62,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Preview: Story = { +export const Preview = meta.story({ args: { children: null, }, @@ -91,11 +88,11 @@ export const Preview: Story = { ), -}; +}); -export const PreviewSubmenu: Story = { +export const PreviewSubmenu = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -119,11 +116,11 @@ export const PreviewSubmenu: Story = { ), -}; +}); -export const PreviewIcons: Story = { +export const PreviewIcons = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -135,11 +132,11 @@ export const PreviewIcons: Story = { ), -}; +}); -export const PreviewSections: Story = { +export const PreviewSections = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -159,11 +156,11 @@ export const PreviewSections: Story = { ), -}; +}); -export const PreviewSeparators: Story = { +export const PreviewSeparators = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -180,11 +177,11 @@ export const PreviewSeparators: Story = { ), -}; +}); -export const PreviewLinks: Story = { +export const PreviewLinks = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -198,11 +195,11 @@ export const PreviewLinks: Story = { ), -}; +}); -export const Opened: Story = { +export const Opened = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -214,11 +211,11 @@ export const Opened: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -230,11 +227,11 @@ export const WithIcons: Story = { ), -}; +}); -export const WithSections: Story = { +export const WithSections = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -254,11 +251,11 @@ export const WithSections: Story = { ), -}; +}); -export const WithSeparators: Story = { +export const WithSeparators = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -275,11 +272,11 @@ export const WithSeparators: Story = { ), -}; +}); -export const WithColors: Story = { +export const WithColors = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -295,11 +292,11 @@ export const WithColors: Story = { ), -}; +}); -export const WithLinks: Story = { +export const WithLinks = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -313,11 +310,11 @@ export const WithLinks: Story = { ), -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -341,11 +338,11 @@ export const Submenu: Story = { ), -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -376,11 +373,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -411,9 +408,9 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); -export const WithScroll: Story = { +export const WithScroll = meta.story({ args: { children: null, }, @@ -446,4 +443,4 @@ export const WithScroll: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx b/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx index c0e1aca932..af68ec9415 100644 --- a/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx +++ b/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, SubmenuTrigger, @@ -26,7 +26,7 @@ import { Button } from '../..'; import { useState, useEffect } from 'react'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuAutocomplete', component: MenuTrigger, decorators: [ @@ -36,10 +36,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -53,7 +50,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -72,11 +69,11 @@ export const Default: Story = { ), -}; +}); -export const PreviewAutocompleteMenu: Story = { +export const PreviewAutocompleteMenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => ( @@ -93,11 +90,11 @@ export const PreviewAutocompleteMenu: Story = { ), -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -132,11 +129,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -172,11 +169,11 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => ( @@ -197,4 +194,4 @@ export const Submenu: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx b/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx index bf66f5f8fd..e1c22fbd9e 100644 --- a/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx +++ b/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, MenuAutocompleteListbox, @@ -28,7 +28,7 @@ import { useEffect, useState } from 'react'; import { Selection } from 'react-aria-components'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuAutocompleteListBox', component: MenuTrigger, decorators: [ @@ -38,10 +38,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -55,7 +52,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -83,11 +80,11 @@ export const Default: Story = { ); }, -}; +}); -export const PreviewListbox: Story = { +export const PreviewListbox = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -113,11 +110,11 @@ export const PreviewListbox: Story = { ); }, -}; +}); -export const PreviewListboxMultiple: Story = { +export const PreviewListboxMultiple = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -144,11 +141,11 @@ export const PreviewListboxMultiple: Story = { ); }, -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -182,11 +179,11 @@ export const Submenu: Story = { ); }, -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -221,11 +218,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -261,4 +258,4 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/Menu/MenuListBox.stories.tsx b/packages/ui/src/components/Menu/MenuListBox.stories.tsx index 72284fb6b9..2297598d0c 100644 --- a/packages/ui/src/components/Menu/MenuListBox.stories.tsx +++ b/packages/ui/src/components/Menu/MenuListBox.stories.tsx @@ -14,14 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, MenuListBox, MenuListBoxItem } from './index'; import { Button, Flex, Text } from '../..'; import { useEffect, useState } from 'react'; import { Selection } from 'react-aria-components'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuListBox', component: MenuTrigger, decorators: [ @@ -31,12 +31,9 @@ const meta = { ), ], -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -50,11 +47,11 @@ export const Default: Story = { ), -}; +}); -export const Controlled: Story = { +export const Controlled = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState(new Set(['paul'])); @@ -86,11 +83,11 @@ export const Controlled: Story = { ); }, -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -121,11 +118,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -156,4 +153,4 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/PasswordField/PasswordField.stories.tsx b/packages/ui/src/components/PasswordField/PasswordField.stories.tsx index 1867e5b7bf..5f6a74d992 100644 --- a/packages/ui/src/components/PasswordField/PasswordField.stories.tsx +++ b/packages/ui/src/components/PasswordField/PasswordField.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { PasswordField } from './PasswordField'; import { Form } from 'react-aria-components'; import { Flex } from '../Flex'; import { FieldLabel } from '../FieldLabel'; import { RiSparklingLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/PasswordField', component: PasswordField, argTypes: { @@ -32,12 +31,9 @@ const meta = { control: 'object', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { name: 'secret', placeholder: 'Enter a secret', @@ -45,11 +41,11 @@ export const Default: Story = { maxWidth: '300px', }, }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -57,79 +53,79 @@ export const Sizes: Story = { } /> ), -}; +}); -export const DefaultValue: Story = { +export const DefaultValue = meta.story({ args: { - ...Default.args, + ...Default.input.args, defaultValue: 'https://example.com', }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Description', }, -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( } /> ), -}; +}); -export const DisabledWithIcon: Story = { +export const DisabledWithIcon = meta.story({ args: { - ...WithIcon.args, + ...WithIcon.input.args, isDisabled: true, }, - render: WithIcon.render, -}; + render: WithIcon.input.render, +}); -export const ShowError: Story = { +export const ShowError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => (
), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, validate: value => (value === 'admin' ? 'Nice try!' : null), }, -}; +}); -export const CustomField: Story = { +export const CustomField = meta.story({ render: () => ( <> ), -}; +}); diff --git a/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx index df7a826c50..4f3465dade 100644 --- a/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx +++ b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,19 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { RadioGroup, Radio } from './RadioGroup'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/RadioGroup', component: RadioGroup, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { label: 'What is your favorite pokemon?', }, @@ -36,11 +32,11 @@ export const Default: Story = { Squirtle ), -}; +}); -export const Horizontal: Story = { +export const Horizontal = meta.story({ args: { - ...Default.args, + ...Default.input.args, orientation: 'horizontal', }, render: args => ( @@ -50,11 +46,11 @@ export const Horizontal: Story = { Squirtle ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, render: args => ( @@ -64,11 +60,11 @@ export const Disabled: Story = { Squirtle ), -}; +}); -export const DisabledSingle: Story = { +export const DisabledSingle = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -79,11 +75,11 @@ export const DisabledSingle: Story = { Squirtle ), -}; +}); -export const DisabledAndSelected: Story = { +export const DisabledAndSelected = meta.story({ args: { - ...Default.args, + ...Default.input.args, value: 'charmander', }, render: args => ( @@ -95,11 +91,11 @@ export const DisabledAndSelected: Story = { Squirtle ), -}; +}); -export const Invalid: Story = { +export const Invalid = meta.story({ args: { - ...Default.args, + ...Default.input.args, name: 'pokemon', isInvalid: true, }, @@ -112,11 +108,11 @@ export const Invalid: Story = { Squirtle ), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...Default.args, + ...Default.input.args, name: 'pokemon', defaultValue: 'charmander', validationBehavior: 'aria', @@ -129,11 +125,11 @@ export const Validation: Story = { Squirtle ), -}; +}); -export const ReadOnly: Story = { +export const ReadOnly = meta.story({ args: { - ...Default.args, + ...Default.input.args, isReadOnly: true, defaultValue: 'charmander', }, @@ -144,4 +140,4 @@ export const ReadOnly: Story = { Squirtle ), -}; +}); diff --git a/packages/ui/src/components/SearchField/SearchField.module.css b/packages/ui/src/components/SearchField/SearchField.module.css index e99c212b29..765527c8c3 100644 --- a/packages/ui/src/components/SearchField/SearchField.module.css +++ b/packages/ui/src/components/SearchField/SearchField.module.css @@ -40,24 +40,25 @@ } &[data-startCollapsed='true'] { - transition: flex-basis 0.3s ease-in-out; + transition: flex-basis 0.3s ease-in-out, width 0.3s ease-in-out, + max-width 0.3s ease-in-out; padding: 0; flex: 0 1 auto; &[data-collapsed='true'] { - flex-basis: 200px; - } - - &[data-collapsed='false'] { cursor: pointer; &[data-size='medium'] { flex-basis: 2.5rem; + width: 2.5rem; + max-width: 2.5rem; height: 2.5rem; } &[data-size='small'] { flex-basis: 2rem; + width: 2rem; + max-width: 2rem; height: 2rem; } @@ -79,6 +80,12 @@ } } } + + &[data-collapsed='false'] { + flex-basis: 200px; + width: 200px; + max-width: 200px; + } } } diff --git a/packages/ui/src/components/SearchField/SearchField.stories.tsx b/packages/ui/src/components/SearchField/SearchField.stories.tsx index 81bc090835..2e07e742ad 100644 --- a/packages/ui/src/components/SearchField/SearchField.stories.tsx +++ b/packages/ui/src/components/SearchField/SearchField.stories.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import { useState } from 'react'; import { SearchField } from './SearchField'; import { Form } from 'react-aria-components'; import { Flex } from '../Flex'; @@ -25,7 +26,7 @@ import { Button } from '../Button'; import { Header } from '../Header'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/SearchField', component: SearchField, argTypes: { @@ -39,12 +40,9 @@ const meta = { control: 'text', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { name: 'url', style: { @@ -52,11 +50,11 @@ export const Default: Story = { }, 'aria-label': 'Search', }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -64,46 +62,46 @@ export const Sizes: Story = { ), -}; +}); -export const DefaultValue: Story = { +export const DefaultValue = meta.story({ args: { - ...Default.args, + ...Default.input.args, defaultValue: 'https://example.com', }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Description', }, -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( } /> ), -}; +}); -export const DisabledWithIcon: Story = { +export const DisabledWithIcon = meta.story({ args: { - ...WithIcon.args, + ...WithIcon.input.args, isDisabled: true, }, -}; +}); -export const ShowError: Story = { +export const ShowError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => (
), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, validate: value => (value === 'admin' ? 'Nice try!' : null), }, -}; +}); -export const CustomField: Story = { +export const CustomField = meta.story({ render: () => ( <> ), -}; +}); -export const StartCollapsed: Story = { +export const StartCollapsed = meta.story({ args: { - ...Default.args, + ...Default.input.args, startCollapsed: true, }, render: args => ( - + + + + + - ), -}; +}); -export const InHeader: Story = { +export const StartCollapsedWithValue = meta.story({ + args: { + ...StartCollapsed.input.args, + defaultValue: 'https://example.com', + }, + + render: args => , +}); + +export const InHeader = meta.story({ decorators: [ Story => ( @@ -204,11 +214,11 @@ export const InHeader: Story = { /> ), -}; +}); -export const StartCollapsedInHeader: Story = { +export const StartCollapsedInHeader = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, decorators: [ Story => ( @@ -241,11 +251,11 @@ export const StartCollapsedInHeader: Story = { /> ), -}; +}); -export const StartCollapsedWithButtons: Story = { +export const StartCollapsedWithButtons = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: args => ( @@ -271,11 +281,11 @@ export const StartCollapsedWithButtons: Story = { ), -}; +}); -export const StartCollapsedWithOnChange: Story = { +export const StartCollapsedWithOnChange = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: args => { const handleChange = (value: string) => { @@ -292,4 +302,42 @@ export const StartCollapsedWithOnChange: Story = { ); }, -}; +}); + +export const StartCollapsedControlledEmpty = meta.story({ + args: { + ...StartCollapsed.input.args, + }, + render: function Render(args) { + const [value, setValue] = useState(''); + + return ( + + + + ); + }, +}); + +export const StartCollapsedControlledWithValue = meta.story({ + args: { + ...StartCollapsed.input.args, + }, + render: function Render(args) { + const [value, setValue] = useState('Component'); + + return ( + + + + ); + }, +}); diff --git a/packages/ui/src/components/SearchField/SearchField.tsx b/packages/ui/src/components/SearchField/SearchField.tsx index 775b7accc6..eea749e46f 100644 --- a/packages/ui/src/components/SearchField/SearchField.tsx +++ b/packages/ui/src/components/SearchField/SearchField.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { forwardRef, useEffect, useState } from 'react'; +import { forwardRef, useEffect, useState, useRef } from 'react'; import { Input, SearchField as AriaSearchField, @@ -39,9 +39,6 @@ export const SearchField = forwardRef( 'aria-labelledby': ariaLabelledBy, } = props; - const [isCollapsed, setIsCollapsed] = useState(false); - const [shouldCollapse, setShouldCollapse] = useState(true); - useEffect(() => { if (!label && !ariaLabel && !ariaLabelledBy) { console.warn( @@ -71,30 +68,29 @@ export const SearchField = forwardRef( ...rest } = cleanedProps; + const [isFocused, setIsFocused] = useState(false); + const inputRef = useRef(null); + // If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required. const secondaryLabelText = secondaryLabel || (isRequired ? 'Required' : null); - const handleClick = (isFocused: boolean) => { + const handleFocusChange = (isFocused: boolean) => { props.onFocusChange?.(isFocused); - if (shouldCollapse) { - if (isFocused) { - setIsCollapsed(true); - } else { - setIsCollapsed(false); - } - } + setIsFocused(isFocused); }; - const handleChange = (value: string) => { - props.onChange?.(value); - if (value.length > 0) { - setShouldCollapse(false); - } else { - setShouldCollapse(true); - } + const handleContainerClick = () => { + inputRef.current?.focus(); }; + const hasInputRef = !!inputRef.current; + const hasValue = !!inputRef.current?.value; + + const isCollapsed = hasInputRef + ? startCollapsed && !hasValue && !isFocused + : startCollapsed && !rest.value && !rest.defaultValue && !isFocused; + return ( ( aria-label={ariaLabel} aria-labelledby={ariaLabelledBy} data-collapsed={isCollapsed} - onFocusChange={handleClick} - onChange={handleChange} style={style} {...rest} + onFocusChange={handleFocusChange} ref={ref} > ( styles[classNames.inputWrapper], )} data-size={dataAttributes['data-size']} + onClick={handleContainerClick} > {icon !== false && (
(
)} ; - -export default meta; -type Story = StoryObj; +}); const fontOptions = [ { value: 'sans', label: 'Sans-serif' }, @@ -66,23 +64,23 @@ const skills = [ { value: 'swift', label: 'Swift' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { options: fontOptions, name: 'font', }, -}; +}); -export const Searchable: Story = { +export const Searchable = meta.story({ args: { label: 'Country', searchable: true, searchPlaceholder: 'Search countries...', options: countries, }, -}; +}); -export const MultipleSelection: Story = { +export const MultipleSelection = meta.story({ args: { label: 'Select multiple options', selectionMode: 'multiple', @@ -93,9 +91,9 @@ export const MultipleSelection: Story = { { value: 'option4', label: 'Option 4' }, ], }, -}; +}); -export const SearchableMultiple: Story = { +export const SearchableMultiple = meta.story({ args: { label: 'Skills', searchable: true, @@ -103,9 +101,9 @@ export const SearchableMultiple: Story = { searchPlaceholder: 'Filter skills...', options: skills, }, -}; +}); -export const Preview: Story = { +export const Preview = meta.story({ args: { label: 'Font Family', options: fontOptions, @@ -113,40 +111,40 @@ export const Preview: Story = { name: 'font', style: { maxWidth: 260 }, }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Font Family', }, -}; +}); -export const WithFullWidth: Story = { +export const WithFullWidth = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Font Family', style: { width: '100%' }, }, -}; +}); -export const WithLabelAndDescription: Story = { +export const WithLabelAndDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Choose a font family for your document', }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => } /> ), -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, isDisabled: true, }, -}; +}); -export const DisabledOption: Story = { +export const DisabledOption = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, disabledKeys: ['cursive', 'serif'], }, -}; +}); -export const NoOptions: Story = { +export const NoOptions = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, options: undefined, }, -}; +}); -export const WithValue: Story = { +export const WithValue = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, selectedKey: 'mono', defaultSelectedKey: 'serif', }, -}; +}); -export const WithDefaultValue: Story = { +export const WithDefaultValue = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, defaultSelectedKey: 'serif', options: fontOptions, name: 'font', }, -}; +}); const generateOptions = (count = 100) => { const firstWords = [ @@ -323,17 +321,17 @@ const generateOptions = (count = 100) => { })); }; -export const WithManyOptions: Story = { +export const WithManyOptions = meta.story({ args: { label: 'Font Family', options: generateOptions(), name: 'font', }, -}; +}); -export const WithError: Story = { +export const WithError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, name: 'font', }, render: args => ( @@ -341,9 +339,9 @@ export const WithError: Story = {
@@ -88,9 +86,9 @@ export const TableOnly: Story = {
); }, -}; +}); -export const WithPaginationUncontrolled: Story = { +export const WithPaginationUncontrolled = meta.story({ render: () => { const { data, paginationProps } = useTable({ data: data1 }); @@ -122,9 +120,9 @@ export const WithPaginationUncontrolled: Story = { ); }, -}; +}); -export const WithPaginationControlled: Story = { +export const WithPaginationControlled = meta.story({ render: () => { const [offset, setOffset] = useState(0); const [pageSize, setPageSize] = useState(5); @@ -172,9 +170,9 @@ export const WithPaginationControlled: Story = { ); }, -}; +}); -export const Sorting: Story = { +export const Sorting = meta.story({ render: () => { return ( @@ -207,9 +205,9 @@ export const Sorting: Story = {
); }, -}; +}); -export const TableRockBand: Story = { +export const TableRockBand = meta.story({ render: () => { const { data, paginationProps } = useTable({ data: data4, @@ -246,9 +244,9 @@ export const TableRockBand: Story = { ); }, -}; +}); -export const RowClick: Story = { +export const RowClick = meta.story({ render: () => { const { data, paginationProps } = useTable({ data: data4, @@ -285,9 +283,9 @@ export const RowClick: Story = { ); }, -}; +}); -export const RowLink: Story = { +export const RowLink = meta.story({ render: () => { const { data, paginationProps } = useTable({ data: data4, @@ -324,9 +322,9 @@ export const RowLink: Story = { ); }, -}; +}); -export const CellComponent: Story = { +export const CellComponent = meta.story({ name: 'Cell', render: () => { return ( @@ -354,9 +352,9 @@ export const CellComponent: Story = { ); }, -}; +}); -export const CellTextComponent: Story = { +export const CellTextComponent = meta.story({ name: 'CellText', render: () => { return ( @@ -379,9 +377,9 @@ export const CellTextComponent: Story = { ); }, -}; +}); -export const CellProfileComponent: Story = { +export const CellProfileComponent = meta.story({ name: 'CellProfile', render: () => { return ( @@ -404,9 +402,9 @@ export const CellProfileComponent: Story = { ); }, -}; +}); -export const SelectionSingleToggle: Story = { +export const SelectionSingleToggle = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -442,9 +440,9 @@ export const SelectionSingleToggle: Story = { ); }, -}; +}); -export const SelectionMultiToggle: Story = { +export const SelectionMultiToggle = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -480,9 +478,9 @@ export const SelectionMultiToggle: Story = { ); }, -}; +}); -export const SelectionSingleReplace: Story = { +export const SelectionSingleReplace = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -518,9 +516,9 @@ export const SelectionSingleReplace: Story = { ); }, -}; +}); -export const SelectionMultiReplace: Story = { +export const SelectionMultiReplace = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -556,9 +554,9 @@ export const SelectionMultiReplace: Story = { ); }, -}; +}); -export const SelectionToggleWithActions: Story = { +export const SelectionToggleWithActions = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -595,9 +593,9 @@ export const SelectionToggleWithActions: Story = { ); }, -}; +}); -export const SelectionReplaceWithActions: Story = { +export const SelectionReplaceWithActions = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -634,9 +632,9 @@ export const SelectionReplaceWithActions: Story = { ); }, -}; +}); -export const SelectionToggleWithLinks: Story = { +export const SelectionToggleWithLinks = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -672,9 +670,9 @@ export const SelectionToggleWithLinks: Story = { ); }, -}; +}); -export const SelectionReplaceWithLinks: Story = { +export const SelectionReplaceWithLinks = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -710,9 +708,9 @@ export const SelectionReplaceWithLinks: Story = { ); }, -}; +}); -export const SelectionWithDisabledRows: Story = { +export const SelectionWithDisabledRows = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -749,9 +747,9 @@ export const SelectionWithDisabledRows: Story = { ); }, -}; +}); -export const SelectionWithPagination: Story = { +export const SelectionWithPagination = meta.story({ render: () => { const [selectedKeys, setSelectedKeys] = useState(new Set([])); @@ -789,9 +787,9 @@ export const SelectionWithPagination: Story = { ); }, -}; +}); -export const SelectionModePlayground: Story = { +export const SelectionModePlayground = meta.story({ render: () => { const [selectionMode, setSelectionMode] = useState<'single' | 'multiple'>( 'multiple', @@ -849,9 +847,9 @@ export const SelectionModePlayground: Story = { ); }, -}; +}); -export const SelectionBehaviorPlayground: Story = { +export const SelectionBehaviorPlayground = meta.story({ render: () => { const [selectionBehavior, setSelectionBehavior] = useState< 'toggle' | 'replace' @@ -909,4 +907,4 @@ export const SelectionBehaviorPlayground: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/TablePagination/TablePagination.stories.tsx b/packages/ui/src/components/TablePagination/TablePagination.stories.tsx index 4550d00abb..a7d949a31d 100644 --- a/packages/ui/src/components/TablePagination/TablePagination.stories.tsx +++ b/packages/ui/src/components/TablePagination/TablePagination.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// TODO: Bring useArgs() back when we update Storybook to 9 -// import { useArgs } from 'storybook/preview-api'; -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { TablePagination } from './TablePagination'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/TablePagination', component: TablePagination, argTypes: { @@ -30,12 +27,9 @@ const meta = { setOffset: { action: 'setOffset' }, setPageSize: { action: 'setPageSize' }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { offset: 0, pageSize: 10, @@ -56,4 +50,4 @@ export const Default: Story = { /> ); }, -}; +}); diff --git a/packages/ui/src/components/Tabs/Tabs.stories.tsx b/packages/ui/src/components/Tabs/Tabs.stories.tsx index c818d0fe4b..2a02bedc8c 100644 --- a/packages/ui/src/components/Tabs/Tabs.stories.tsx +++ b/packages/ui/src/components/Tabs/Tabs.stories.tsx @@ -14,19 +14,17 @@ * limitations under the License. */ -import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { Tabs, TabList, Tab, TabPanel } from './Tabs'; import { MemoryRouter } from 'react-router-dom'; import { Box } from '../Box'; import { Text } from '../Text'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Tabs', component: Tabs, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const withRouter = (Story: StoryFn) => ( @@ -34,7 +32,7 @@ const withRouter = (Story: StoryFn) => ( ); -export const Default: Story = { +export const Default = meta.story({ args: { children: '', }, @@ -48,9 +46,9 @@ export const Default: Story = { ), -}; +}); -export const WithTabPanels: Story = { +export const WithTabPanels = meta.story({ args: { children: '', }, @@ -73,9 +71,9 @@ export const WithTabPanels: Story = { ), -}; +}); -export const WithMockedURLTab2: Story = { +export const WithMockedURLTab2 = meta.story({ args: { children: '', }, @@ -105,9 +103,9 @@ export const WithMockedURLTab2: Story = { ), -}; +}); -export const WithMockedURLTab3: Story = { +export const WithMockedURLTab3 = meta.story({ args: { children: '', }, @@ -137,9 +135,9 @@ export const WithMockedURLTab3: Story = { ), -}; +}); -export const WithMockedURLNoMatch: Story = { +export const WithMockedURLNoMatch = meta.story({ args: { children: '', }, @@ -173,11 +171,11 @@ export const WithMockedURLNoMatch: Story = { ), -}; +}); // New stories for testing match strategies -export const ExactMatchingDefault: Story = { +export const ExactMatchingDefault = meta.story({ args: { children: '', }, @@ -211,9 +209,9 @@ export const ExactMatchingDefault: Story = { ), -}; +}); -export const PrefixMatchingForNestedRoutes: Story = { +export const PrefixMatchingForNestedRoutes = meta.story({ args: { children: '', }, @@ -251,9 +249,9 @@ export const PrefixMatchingForNestedRoutes: Story = { ), -}; +}); -export const PrefixMatchingDeepNesting: Story = { +export const PrefixMatchingDeepNesting = meta.story({ args: { children: '', }, @@ -286,9 +284,9 @@ export const PrefixMatchingDeepNesting: Story = { ), -}; +}); -export const MixedMatchingStrategies: Story = { +export const MixedMatchingStrategies = meta.story({ args: { children: '', }, @@ -337,9 +335,9 @@ export const MixedMatchingStrategies: Story = { ), -}; +}); -export const PrefixMatchingEdgeCases: Story = { +export const PrefixMatchingEdgeCases = meta.story({ args: { children: '', }, @@ -379,9 +377,9 @@ export const PrefixMatchingEdgeCases: Story = { ), -}; +}); -export const PrefixMatchingWithSlash: Story = { +export const PrefixMatchingWithSlash = meta.story({ args: { children: '', }, @@ -420,9 +418,9 @@ export const PrefixMatchingWithSlash: Story = { ), -}; +}); -export const RootPathMatching: Story = { +export const RootPathMatching = meta.story({ args: { children: '', }, @@ -454,9 +452,9 @@ export const RootPathMatching: Story = { ), -}; +}); -export const AutoSelectionOfTabs: Story = { +export const AutoSelectionOfTabs = meta.story({ args: { children: '', }, @@ -511,4 +509,4 @@ export const AutoSelectionOfTabs: Story = { ), -}; +}); diff --git a/packages/ui/src/components/TagGroup/TagGroup.stories.tsx b/packages/ui/src/components/TagGroup/TagGroup.stories.tsx index 7cc8d3c824..d33eed8bf1 100644 --- a/packages/ui/src/components/TagGroup/TagGroup.stories.tsx +++ b/packages/ui/src/components/TagGroup/TagGroup.stories.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ +import preview from '../../../../../.storybook/preview'; import { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react-vite'; import { TagGroup, Tag } from '.'; import type { Selection } from 'react-aria-components'; import { Flex } from '../../'; @@ -35,7 +35,7 @@ export interface ListItem { isDisabled?: boolean; } -const meta = { +const meta = preview.meta({ title: 'Backstage UI/TagGroup', component: TagGroup, argTypes: { @@ -54,10 +54,7 @@ const meta = { ), ], -} satisfies Meta>; - -export default meta; -type Story = StoryObj; +}); const initialList: ListItem[] = [ { id: 'banana', name: 'Banana', icon: }, @@ -74,7 +71,7 @@ const initialList: ListItem[] = [ { id: 'strawberry', name: 'Strawberry', icon: }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { 'aria-label': 'Tag Group', }, @@ -85,11 +82,11 @@ export const Default: Story = { ))} ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -109,9 +106,9 @@ export const Sizes: Story = { ), -}; +}); -export const SelectionModeSingle: Story = { +export const SelectionModeSingle = meta.story({ args: { selectionMode: 'single', 'aria-label': 'Tag Group', @@ -130,9 +127,9 @@ export const SelectionModeSingle: Story = { ); }, -}; +}); -export const SelectionModeMultiple: Story = { +export const SelectionModeMultiple = meta.story({ args: { selectionMode: 'multiple', 'aria-label': 'Tag Group', @@ -153,11 +150,11 @@ export const SelectionModeMultiple: Story = { ); }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -168,9 +165,9 @@ export const WithIcon: Story = { ))} ), -}; +}); -export const WithLink: Story = { +export const WithLink = meta.story({ render: args => ( {initialList.map(item => ( @@ -180,9 +177,9 @@ export const WithLink: Story = { ))} ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: args => ( {initialList.map(item => ( @@ -192,11 +189,11 @@ export const Disabled: Story = { ))} ), -}; +}); -export const RemovingTags: Story = { +export const RemovingTags = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => { const [selected, setSelected] = useState(new Set(['travel'])); @@ -217,11 +214,11 @@ export const RemovingTags: Story = { ); }, -}; +}); -export const WithIconAndRemoveButton: Story = { +export const WithIconAndRemoveButton = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => { const [selected, setSelected] = useState(new Set(['travel'])); @@ -244,4 +241,4 @@ export const WithIconAndRemoveButton: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/Text/Text.stories.tsx b/packages/ui/src/components/Text/Text.stories.tsx index 7f95f4d5a1..09a317716a 100644 --- a/packages/ui/src/components/Text/Text.stories.tsx +++ b/packages/ui/src/components/Text/Text.stories.tsx @@ -14,31 +14,28 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Text } from './Text'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Text', component: Text, args: { children: 'Text', }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: "A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is in the painting?", }, -}; +}); -export const AllVariants: Story = { +export const AllVariants = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -52,9 +49,9 @@ export const AllVariants: Story = { ), -}; +}); -export const AllWeights: Story = { +export const AllWeights = meta.story({ render: () => ( @@ -91,11 +88,11 @@ export const AllWeights: Story = { ), -}; +}); -export const AllColors: Story = { +export const AllColors = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -106,30 +103,30 @@ export const AllColors: Story = { ), -}; +}); -export const Truncate: Story = { +export const Truncate = meta.story({ args: { - ...Default.args, + ...Default.input.args, truncate: true, as: 'p', style: { width: '480px' }, }, -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { - ...Default.args, + ...Default.input.args, variant: { xs: 'title-x-small', md: 'body-large', }, }, -}; +}); -export const WrappedInLink: Story = { +export const WrappedInLink = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, decorators: [ Story => ( @@ -138,16 +135,16 @@ export const WrappedInLink: Story = {
), ], -}; +}); -export const CustomRender: Story = { +export const CustomRender = meta.story({ args: { - ...Default.args, + ...Default.input.args, as: 'label', }, -}; +}); -export const Playground: Story = { +export const Playground = meta.story({ render: () => ( Subtitle @@ -176,4 +173,4 @@ export const Playground: Story = { ), -}; +}); diff --git a/packages/ui/src/components/TextField/TextField.stories.tsx b/packages/ui/src/components/TextField/TextField.stories.tsx index 38115996ae..54457f351b 100644 --- a/packages/ui/src/components/TextField/TextField.stories.tsx +++ b/packages/ui/src/components/TextField/TextField.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { TextField } from './TextField'; import { Form } from 'react-aria-components'; import { Flex } from '../Flex'; import { FieldLabel } from '../FieldLabel'; import { RiEyeLine, RiSparklingLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/TextField', component: TextField, argTypes: { @@ -32,12 +31,9 @@ const meta = { control: 'object', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { name: 'url', placeholder: 'Enter a URL', @@ -45,11 +41,11 @@ export const Default: Story = { maxWidth: '300px', }, }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -57,46 +53,46 @@ export const Sizes: Story = { } /> ), -}; +}); -export const DefaultValue: Story = { +export const DefaultValue = meta.story({ args: { - ...Default.args, + ...Default.input.args, defaultValue: 'https://example.com', }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Description', }, -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( } /> ), -}; +}); -export const DisabledWithIcon: Story = { +export const DisabledWithIcon = meta.story({ args: { - ...WithIcon.args, + ...WithIcon.input.args, isDisabled: true, }, - render: WithIcon.render, -}; + render: WithIcon.input.render, +}); -export const ShowError: Story = { +export const ShowError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => (
), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, validate: value => (value === 'admin' ? 'Nice try!' : null), }, -}; +}); -export const CustomField: Story = { +export const CustomField = meta.story({ render: () => ( <> ), -}; +}); diff --git a/packages/ui/src/components/Tooltip/Tooltip.stories.tsx b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx index cc6b513ed4..a636a356ef 100644 --- a/packages/ui/src/components/Tooltip/Tooltip.stories.tsx +++ b/packages/ui/src/components/Tooltip/Tooltip.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Placement } from '@react-types/overlays'; +import preview from '../../../../../.storybook/preview'; import { TooltipTrigger, Tooltip } from './Tooltip'; import { Button } from '../Button/Button'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Tooltip', component: TooltipTrigger, parameters: { layout: 'centered' }, @@ -30,10 +28,6 @@ const meta = { isDisabled: { control: { type: 'boolean' }, }, - placement: { - options: ['top', 'right', 'bottom', 'left'], - control: { type: 'inline-radio' }, - }, delay: { control: { type: 'number' }, }, @@ -41,7 +35,7 @@ const meta = { control: { type: 'number' }, }, }, - render: ({ children, isOpen, isDisabled, placement, delay, closeDelay }) => ( + render: ({ children, isOpen, isDisabled, delay, closeDelay }) => ( - {children ?? 'I am a tooltip'} + {children ?? 'I am a tooltip'} ), -} as Meta<{ - children?: string; - isOpen?: boolean; - isDisabled?: boolean; - placement?: Placement; - delay?: number; - closeDelay?: number; -}>; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'I am a tooltip', }, -}; +}); -export const IsOpen: Story = { +export const IsOpen = meta.story({ args: { - ...Default.args, + ...Default.input.args, isOpen: true, }, -}; +}); -export const IsDisabled: Story = { +export const IsDisabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const NoDelays: Story = { +export const NoDelays = meta.story({ args: { - ...Default.args, + ...Default.input.args, delay: 0, closeDelay: 0, }, -}; +}); -export const OrthogonalPlacements: Story = { +export const OrthogonalPlacements = meta.story({ parameters: { controls: { exclude: ['placement'], }, }, args: { - ...Default.args, + ...Default.input.args, isOpen: true, }, render: ({ isOpen, children }) => { @@ -113,13 +97,13 @@ export const OrthogonalPlacements: Story = { ); }, -}; +}); -export const WithLongText: Story = { +export const WithLongText = meta.story({ args: { - ...Default.args, + ...Default.input.args, isOpen: true, children: 'I am a tooltip with a very long text. orem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', }, -}; +}); diff --git a/packages/ui/src/components/VisuallyHidden/VisuallyHidden.stories.tsx b/packages/ui/src/components/VisuallyHidden/VisuallyHidden.stories.tsx index 9706edfc9b..cc75adbd5e 100644 --- a/packages/ui/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +++ b/packages/ui/src/components/VisuallyHidden/VisuallyHidden.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { VisuallyHidden } from './VisuallyHidden'; import { Text } from '../Text'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/VisuallyHidden', component: VisuallyHidden, parameters: { @@ -30,12 +29,9 @@ const meta = { }, }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: () => ( @@ -48,9 +44,9 @@ export const Default: Story = { ), -}; +}); -export const ExampleUsage: Story = { +export const ExampleUsage = meta.story({ render: () => ( @@ -70,4 +66,4 @@ export const ExampleUsage: Story = { ), -}; +}); diff --git a/packages/ui/src/css/core.css b/packages/ui/src/css/core.css index 5be23e7a1b..321ca07eff 100644 --- a/packages/ui/src/css/core.css +++ b/packages/ui/src/css/core.css @@ -27,7 +27,7 @@ } body { - background-color: var(--bui-bg); + background-color: var(--bui-bg-surface-0); /* Text defaults */ color: var(--bui-fg-primary); diff --git a/packages/ui/src/css/tokens.css b/packages/ui/src/css/tokens.css index 028c60311d..459d98d48f 100644 --- a/packages/ui/src/css/tokens.css +++ b/packages/ui/src/css/tokens.css @@ -81,9 +81,10 @@ --bui-gray-8: #595959; /* Background Colors */ - --bui-bg: var(--bui-gray-1); + --bui-bg-surface-0: var(--bui-gray-1); --bui-bg-surface-1: var(--bui-white); - --bui-bg-surface-2: var(--bui-gray-2); + --bui-bg-surface-2: var(--bui-gray-1); + --bui-bg-surface-3: var(--bui-gray-2); --bui-bg-solid: #1f5493; --bui-bg-solid-hover: #163a66; --bui-bg-solid-pressed: #0f2b4e; @@ -140,9 +141,10 @@ --bui-gray-8: #b4b4b4; /* Background Colors */ - --bui-bg: #333333; - --bui-bg-surface-1: #424242; + --bui-bg-surface-0: #333333; + --bui-bg-surface-1: var(--bui-gray-1); --bui-bg-surface-2: var(--bui-gray-2); + --bui-bg-surface-3: var(--bui-gray-3); --bui-bg-solid: #9cc9ff; --bui-bg-solid-hover: #83b9fd; --bui-bg-solid-pressed: #83b9fd; diff --git a/packages/yarn-plugin/CHANGELOG.md b/packages/yarn-plugin/CHANGELOG.md index 3c1903a019..20d37cf076 100644 --- a/packages/yarn-plugin/CHANGELOG.md +++ b/packages/yarn-plugin/CHANGELOG.md @@ -1,5 +1,12 @@ # yarn-plugin-backstage +## 0.0.8 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.16 + ## 0.0.8-next.0 ### Patch Changes diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index 5a7bec9bcc..de8b7955d3 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -1,6 +1,6 @@ { "name": "yarn-plugin-backstage", - "version": "0.0.8-next.0", + "version": "0.0.8", "description": "Yarn plugin for working with Backstage monorepos", "backstage": { "role": "node-library" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index a5b01fb068..195215f38d 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-api-docs +## 0.13.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.13.2 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/plugin-catalog@1.32.1 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + ## 0.13.2-next.1 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 225e329d36..40ca339186 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.13.2-next.1", + "version": "0.13.3-next.0", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index f4df39b170..1923dd74a3 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-app-backend +## 0.5.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-app-node@0.1.40 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + ## 0.5.9-next.1 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index d30770d3c3..9ab956713f 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.5.9-next.1", + "version": "0.5.9", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 3971b0ed54..ceab019e5a 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-app-node +## 0.1.40 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config-loader@1.10.7 + ## 0.1.40-next.1 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 1583d90e57..c41733eb04 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.40-next.1", + "version": "0.1.40", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index d04d2461ba..0dc550bb53 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-app-visualizer +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.1.26 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/ui@0.10.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.1.26-next.1 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 8b580ea17b..b736b07cd6 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.1.26-next.1", + "version": "0.1.27-next.0", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index 351479a54f..c0feabe1aa 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-app +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.3.3 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- f7bc228: Support to set `defaultLanguage` and `availableLanguages` for the app language API in the new frontend system +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + ## 0.3.3-next.1 ### Patch Changes diff --git a/plugins/app/package.json b/plugins/app/package.json index a531c5b450..3ca60fde87 100644 --- a/plugins/app/package.json +++ b/plugins/app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app", - "version": "0.3.3-next.1", + "version": "0.3.4-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "app", diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index ec89692a85..b78cce757e 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index d22ebf0b1a..28f4031eab 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.4.10-next.1", + "version": "0.4.10", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md index 7e3db38938..6e9806b643 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.2.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 6e9293d944..8b749bc420 100644 --- a/plugins/auth-backend-module-auth0-provider/package.json +++ b/plugins/auth-backend-module-auth0-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-auth0-provider", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The auth0-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index 6207a3cfbf..aff6333c3c 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index 48dee6b124..65ef39f0d5 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.4.10-next.1", + "version": "0.4.10", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 3d139b57cd..4829c70373 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.15 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.15-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index 66f7094031..ba0b80c93c 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.2.15-next.1", + "version": "0.2.15", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index 12bd0a13dc..0870c56aff 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 7f43a93502..83efe1ea70 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md index 8c0df56cb1..2f9860e317 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-server-provider/package.json b/plugins/auth-backend-module-bitbucket-server-provider/package.json index 576ca6f925..701fe9d337 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-server-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-server-provider", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The bitbucket-server-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index 7de1d06be6..06d2bf174c 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index 2d524f8741..0cea95105c 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.4.10-next.1", + "version": "0.4.10", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 155c616491..1243523582 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 69b224a9c6..e045da8fc8 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.4.10-next.1", + "version": "0.4.10", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index d81802fd50..a8458f6b1d 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.4.0 + +### Minor Changes + +- b3286d5: Added the `github.com/user-id` annotation to store GitHub's user ID (immutable) in user entities. Also includes addition of the `userIdMatchingUserEntityAnnotation` sign-in resolver that matches users by the new ID. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 1cdc217126..ce418e2b08 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.3.10-next.1", + "version": "0.4.0", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 9c3e318c71..c31ef87722 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.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 5ea1d2ccf6..81b2450555 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 77976afe3f..ef7f4a6506 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.3.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index ce142af63f..bc2523dbdb 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index ecf498d085..221b83037e 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.15 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.15-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 03bd08d7e7..726674a1ae 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.2.15-next.1", + "version": "0.2.15", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index b8d865d182..7e4b112021 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index c0b0ebc89d..10e7b2ebec 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 5804fe281b..8dadd4938e 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.4.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 2b09f84a3e..7ec85a39a0 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.4.10-next.1", + "version": "0.4.10", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index f0b86176d3..faa632f587 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.15-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 9df99d1a01..483022a70a 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.2.15-next.1", + "version": "0.2.15", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index bea755da76..591f1139e9 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.4.11-next.0 + +### Patch Changes + +- e54fcb2: Added support for custom start URL search parameters (with the new `startUrlSearchParams` config property) +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/plugin-auth-node@0.6.10 + +## 0.4.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-auth-backend@0.25.7 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/config.d.ts b/plugins/auth-backend-module-oidc-provider/config.d.ts index c11b9319ec..f25d13ae2e 100644 --- a/plugins/auth-backend-module-oidc-provider/config.d.ts +++ b/plugins/auth-backend-module-oidc-provider/config.d.ts @@ -33,6 +33,7 @@ export interface Config { additionalScopes?: string | string[]; prompt?: string; timeout?: HumanDuration | string; + startUrlSearchParams?: [string: string]; signIn?: { resolvers: Array< | { diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 288e43ed90..933182d80d 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.4.10-next.1", + "version": "0.4.11-next.0", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/report.api.md b/plugins/auth-backend-module-oidc-provider/report.api.md index 11cde22db1..ab7d2bda49 100644 --- a/plugins/auth-backend-module-oidc-provider/report.api.md +++ b/plugins/auth-backend-module-oidc-provider/report.api.md @@ -25,6 +25,7 @@ export const oidcAuthenticator: OAuthAuthenticator< client: BaseClient; strategy: Strategy; }>; + searchParams: Record; }, OidcAuthResult >; diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts index c327d4ecc5..1940a71082 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts @@ -279,6 +279,62 @@ describe('oidcAuthenticator', () => { expect(searchParams.get('response_type')).toBe('code'); }); + it('passes custom start URL search parameters', async () => { + const customImplementation = oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId123', + clientSecret: 'clientSecret', + startUrlSearchParams: { + foo: '1', + bar: '2', + }, + }), + }); + + const startResponse = await oidcAuthenticator.start( + startRequest, + customImplementation, + ); + + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('foo')).toBe('1'); + expect(searchParams.get('bar')).toBe('2'); + }); + + it('does not override the core start URL search parameters with custom ones', async () => { + const customImplementation = oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId123', + clientSecret: 'clientSecret', + startUrlSearchParams: { + foo: '1', + prompt: 'customPrompt', + scope: 'customScope', + state: 'customState', + nonce: 'customNonce', + }, + }), + }); + + const startResponse = await oidcAuthenticator.start( + startRequest, + customImplementation, + ); + + const { searchParams } = new URL(startResponse.url); + + expect(searchParams.get('foo')).toBe('1'); + expect(searchParams.get('scope')).not.toBe('customScope'); + expect(searchParams.get('state')).not.toBe('customState'); + expect(searchParams.get('nonce')).not.toBe('customNonce'); + expect(searchParams.get('prompt')).not.toBe('customPrompt'); + }); + it('passes a nonce', async () => { const startResponse = await oidcAuthenticator.start( startRequest, diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.ts index 6e7022f7cf..316ead3954 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.ts @@ -83,6 +83,9 @@ export const oidcAuthenticator = createOAuthAuthenticator({ ); const initializedPrompt = config.getOptionalString('prompt'); + const startUrlSearchParams: Record = + config.getOptional('startUrlSearchParams') || {}; + if (config.has('scope')) { throw new Error( 'The oidc provider no longer supports the "scope" configuration option. Please use the "additionalScopes" option instead.', @@ -143,17 +146,21 @@ export const oidcAuthenticator = createOAuthAuthenticator({ return { helper, client, strategy }; }); - return { initializedPrompt, promise }; + return { initializedPrompt, promise, searchParams: startUrlSearchParams }; }, async start(input, ctx) { - const { initializedPrompt, promise } = ctx; + const { initializedPrompt, promise, searchParams } = ctx; const { helper } = await promise; + + // Merge the custom start URL params, but do not override the standard params (scope, state etc) const options: Record = { + ...searchParams, scope: input.scope, state: input.state, nonce: crypto.randomBytes(16).toString('base64'), }; + const prompt = initializedPrompt || 'none'; if (prompt !== 'auto') { options.prompt = prompt; diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 9035d60a6b..47bcb2f140 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.2.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index d6320355ee..a4342efb03 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.2.10-next.1", + "version": "0.2.10", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index 8a8c58b644..9ad81ae8c4 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index f2056e8062..aadfb3f273 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-openshift-provider/CHANGELOG.md b/plugins/auth-backend-module-openshift-provider/CHANGELOG.md index 85212d8896..9cf3f67cd9 100644 --- a/plugins/auth-backend-module-openshift-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-openshift-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-openshift-provider +## 0.1.3 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.3-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-openshift-provider/package.json b/plugins/auth-backend-module-openshift-provider/package.json index e60b0cf0cd..94c21f1718 100644 --- a/plugins/auth-backend-module-openshift-provider/package.json +++ b/plugins/auth-backend-module-openshift-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-openshift-provider", - "version": "0.1.3-next.1", + "version": "0.1.3", "description": "The OpenShift backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 7dc93b5450..5da6e92225 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.3.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 4b4473fadd..ba1e04ff76 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.3.10-next.1", + "version": "0.3.10", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index fc915370ad..431d709b37 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.5.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.5.10-next.1 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 93e953897f..0445438588 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.5.10-next.1", + "version": "0.5.10", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 96f12f68d3..7eaef6e066 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend +## 0.25.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.25.7-next.1 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 3f2a86a654..9db17b1a93 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.25.7-next.1", + "version": "0.25.7", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 4168ce3284..4ad613457b 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-node +## 0.6.10 + +### Patch Changes + +- 2389358: remove leading dot in auth cookie cleanup call +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- b35f8b2: Fixed chunked cookie replacing edge case in OAuthCookieManager class where some of the old chunks would not get removed if new chunked cookie would have fewer chunks. +- e9dd634: fix flawed cookie removal logic with chunked tokens +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 0.6.10-next.1 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index d74c83e426..3e095caa91 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.6.10-next.1", + "version": "0.6.10", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-node/src/oauth/OAuthCookieManager.ts b/plugins/auth-node/src/oauth/OAuthCookieManager.ts index afbedd4dba..fc376eae67 100644 --- a/plugins/auth-node/src/oauth/OAuthCookieManager.ts +++ b/plugins/auth-node/src/oauth/OAuthCookieManager.ts @@ -145,128 +145,154 @@ export class OAuthCookieManager { maxAge: number, origin?: string, pathSuffix: string = '', - ): Response { + ): void { const options = { maxAge, ...this.getConfig(origin, pathSuffix), }; const req = res.req; - let output = res; - const chunkedFormatExists = OAuthCookieManager.chunkedCookieExists( + const newCookieShouldBeChunked = val.length > MAX_COOKIE_SIZE_CHARACTERS; + const existingChunkCount = OAuthCookieManager.countExistingCookieChunks( req, name, ); + const chunkedFormatExists = existingChunkCount > 0; // If using the default cookieConfigurer, delete old cookie with domain // explicitly set to the callbackUrl's domain (legacy behavior) if (this.cookieConfigurer === defaultCookieConfigurer) { - const { hostname: domain } = new URL(this.options.callbackUrl); - output = output.cookie(name, '', { - ...this.getRemoveCookieOptions(), - domain: domain, - }); - - if (chunkedFormatExists) { - for (let chunkNumber = 0; ; chunkNumber++) { - const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber); - const exists = !!req.cookies[key]; - if (!exists) { - break; - } - output = output.cookie(key, '', { - ...this.getRemoveCookieOptions(), - domain: domain, - }); - } - } - } - - if (val.length > MAX_COOKIE_SIZE_CHARACTERS) { - const nonChunkedFormatExists = !!req.cookies[name]; - if (nonChunkedFormatExists) { - output = output.cookie(name, '', this.getRemoveCookieOptions()); - } - - const chunked = this.splitCookieToChunks(val, MAX_COOKIE_SIZE_CHARACTERS); - chunked.forEach((value, chunkNumber) => { - output = output.cookie( - OAuthCookieManager.getCookieChunkName(name, chunkNumber), - value, - options, - ); - }); - return output; + this.removeLegacyCookieWithDomain(res, name, existingChunkCount); } if (chunkedFormatExists) { - for (let chunkNumber = 0; ; chunkNumber++) { - const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber); - const exists = !!req.cookies[key]; - if (!exists) { - break; - } - output = output.cookie(key, '', this.getRemoveCookieOptions()); - } + this.removeChunkedCookie(res, name, existingChunkCount); } - return output.cookie(name, val, options); + if (newCookieShouldBeChunked) { + this.setChunkedCookie(req, res, name, val, options); + } else { + res.cookie(name, val, options); + } + } + + private removeLegacyCookieWithDomain( + res: Response, + name: string, + chunkCount: number, + ): void { + const { hostname: domain } = new URL(this.options.callbackUrl); + res.cookie(name, '', { + ...this.getRemoveCookieOptions(), + domain: domain, + }); + + this.removeChunkedCookie(res, name, chunkCount, { domain }); + } + + private setChunkedCookie( + req: Request, + res: Response, + name: string, + val: string, + options: CookieOptions, + ): void { + const nonChunkedFormatExists = !!req.cookies[name]; + if (nonChunkedFormatExists) { + res.cookie(name, '', this.getRemoveCookieOptions()); + } + const chunkedCookieArray = this.splitCookieToChunks( + val, + MAX_COOKIE_SIZE_CHARACTERS, + ); + chunkedCookieArray.forEach((chunkValue, chunkNumber) => { + res.cookie( + OAuthCookieManager.getCookieChunkName(name, chunkNumber), + chunkValue, + options, + ); + }); } private getCookie(req: Request, name: string): string | undefined { - const isChunked = OAuthCookieManager.chunkedCookieExists(req, name); + const existingChunkCount = OAuthCookieManager.countExistingCookieChunks( + req, + name, + ); + const isChunked = existingChunkCount > 0; if (isChunked) { - const chunks: string[] = []; - let chunkNumber = 0; - let chunk = - req.cookies[OAuthCookieManager.getCookieChunkName(name, chunkNumber)]; - while (chunk) { - chunks.push(chunk); - chunkNumber++; - chunk = - req.cookies[OAuthCookieManager.getCookieChunkName(name, chunkNumber)]; - } - return chunks.join(''); + return this.getChunkedCookie(req, name, existingChunkCount); } return req.cookies[name]; } - private removeCookie(res: Response, name: string, origin?: string): Response { - const req = res.req; - const options = this.getRemoveCookieOptions(origin); - const isChunked = OAuthCookieManager.chunkedCookieExists(req, name); - if (isChunked) { - const nonChunkedFormatExists = !!req.cookies[name]; - let output: Response = nonChunkedFormatExists - ? res.cookie(name, '', options) - : res; - for (let chunkNumber = 0; ; chunkNumber++) { - const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber); - const exists = !!req.cookies[key]; - if (!exists) { - break; - } - output = output.cookie(key, '', options); - } - return output; + private getChunkedCookie( + req: Request, + name: string, + chunkCount: number, + ): string | undefined { + const chunkedCookieArray: string[] = []; + for (let chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) { + const chunk = + req.cookies[OAuthCookieManager.getCookieChunkName(name, chunkNumber)]; + chunkedCookieArray.push(chunk); + } + return chunkedCookieArray.join(''); + } + + private removeCookie(res: Response, name: string, origin?: string): void { + const req = res.req; + const existingChunkCount = OAuthCookieManager.countExistingCookieChunks( + req, + name, + ); + const chunkedFormatExists = existingChunkCount > 0; + const nonChunkedFormatExists = !!req.cookies[name]; + + if (nonChunkedFormatExists) { + res.cookie(name, '', this.getRemoveCookieOptions(origin)); + } + if (chunkedFormatExists) { + this.removeChunkedCookie(res, name, existingChunkCount, { + origin, + }); + } + } + + private removeChunkedCookie( + res: Response, + name: string, + chunkCount: number, + { domain, origin }: { domain?: string; origin?: string } = {}, + ): void { + for (let chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) { + const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber); + const baseOptions = this.getRemoveCookieOptions(origin); + const options = domain ? { ...baseOptions, domain } : baseOptions; + res.cookie(key, '', options); } - return res.cookie(name, '', options); } private splitCookieToChunks(val: string, chunkSize: number): string[] { const numChunks = Math.ceil(val.length / chunkSize); - const chunks: string[] = Array(numChunks); + const chunkedCookieArray: string[] = Array(numChunks); let offset: number = 0; for (let i = 0; i < numChunks; i++) { - chunks[i] = val.substring(offset, offset + chunkSize); + chunkedCookieArray[i] = val.substring(offset, offset + chunkSize); offset += chunkSize; } - return chunks; + return chunkedCookieArray; } - private static chunkedCookieExists(req: Request, name: string): boolean { - return !!req.cookies[OAuthCookieManager.getCookieChunkName(name, 0)]; + private static countExistingCookieChunks(req: Request, name: string): number { + for (let chunkNumber = 0; ; chunkNumber++) { + const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber); + const exists = !!req.cookies[key]; + if (!exists) { + return chunkNumber; + } + } } private static getCookieChunkName(name: string, chunkIndex: number): string { diff --git a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts index df012bcff1..f2cb27dfa9 100644 --- a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts +++ b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts @@ -19,7 +19,11 @@ import express from 'express'; import request, { SuperAgentTest } from 'supertest'; import cookieParser from 'cookie-parser'; import PromiseRouter from 'express-promise-router'; -import { AuthProviderRouteHandlers, AuthResolverContext } from '../types'; +import { + AuthProviderRouteHandlers, + AuthResolverContext, + CookieConfigurer, +} from '../types'; import { createOAuthRouteHandlers } from './createOAuthRouteHandlers'; import { OAuthAuthenticator } from './types'; import { encodeOAuthState, OAuthState } from './state'; @@ -53,6 +57,9 @@ const mockSession = { const fiveKilobyteRefreshToken = 'tylmRqYlw3LrrXATyPerWfYMXrF86h3FeI5DECH8lZ6bERd3SsSFaJZ7EVYw0Rr8HMQVqJAurcSDZBtXjry3y9hXGRmugroDiZngNw8ROSPqcWzaNWDbaVuxCGf3jdjccOio7MnbrmMGpKUF8dfx8DhBH9Vogj5qCWpDajxnGpG0HEOcAHmQbsmJ0KHKVIggAtTYIefjvO2I75Us5VI0sId1GYU0E2AsRVEGedu6oexiLV6QgyJHSyKzTTRD7DqZ4ktVLDsjOBUhAAEWbAl0vxhvjSUEt4YYEFshV5T13MhRGGma8QtVC7R1NItwtojj94QGfwnnQEviIuECONwQc6b4ObeQkPn4bgbsWG9PD5UJA9kBycBV8SqBQkKvT5nsrlsnO4E8zBJBtc2Pd14MUh6CzFng3Wee7v5uPQAnyDJT4V7COwY2F2opz2ifau6c6gUT5ybkEKbp945mo2R0mu99C7z99jhUq9RRxgrtSeNQ7o7j4NksnJThZMjxvpi978bG2P2oMWIl59LgsrYyUt2bkjEB5sQ1qwngitAQDy57flLwAyHAwTobQWjGDUumAAOHe9UqjsuPd6qf23nD0b2nn1rCtnGyJ0H6luaTT0Lqet1Eq9XRLHkL52mJN4iPLWKcDrYsK6KqKhIlVkHa4zXRKHnKONOgMqYioC155yncAirYYJQl142MWamHXqW3LsIjrPwPh9xj02TsWMG4hDt2kVb8Rp3qGJTDyDM79NKbIFFSkATIwyQmQB1THo0kAkpu3V7YYoOfDSl4N5TUbPJRSbEug6Xg3dqMjaHrL729xrGsc0iWC8DAKlTzPKnoVcjaYeru6zHIXhJJcs5BIxeA6afUcataOrzTddXdBiCehqtzjS0omXdeiHKv5d73fLeC5luUo1um6eVEidr5fXEApGpSHKsEo7mv1a9xOTCZPCE1lHntIkaG2vTgEc14QmGTXAjnaxuThGROxmm2gX8xM3JD6HYAfTxQpD5Y6fcMyF5joffBjLdFvHyYC66BghXIb4M7oZ0QQNqzMKzNuJ06JYLK4e0Pi2FQHt1XcO38sknlFnQh5S0GPMiGHXStIyDTfZNwPnI7iKH0GtsRZBUPmoG2cgJWSJPTMZOnIaC5AzZ8AClMT58GAa3MiyIhVLAs1hBv4BMu5mbY1QVSZ8UETZTDnXEn6rGIES41zkr1A3FThUhUTzJAwYLaG2nYn5Dtpge5C1B4LGElcVQDLJKKV3e6foYQMHcIzlwySKWSylI2bRjGJtE9594rlB9Yz1eno7KTtxy9IrMoAd13KnOCnrKjL40kGEWwbDScT0zob04qw1uuIcldUiLYLhPD0MtdxqtZTgvKeVTCeFNo23kWRnBvwhLlguGqvPCMfwXFjLldJsei9MElZgRrPgubBb7ZjSSdGT6CKey6TaFPx5jOT7V9v88jfQJMyEoX9jMCvCQZMFZyCMQdGKU40dOaozRqsymNMhPOgvheIhlXfN0MhU6RLJGhUen0QLuRBy2MiK82z1nkKSnlhMB3REmFmAIXrVhXiOalPLDVB9kR3csn5f6bddAcTzDLrv2YH6ZGhmXwILKJ0osKm8e9aIKVWHitr0LXl5zvkDj7U9CIVtktLLRodLTVxlKRS048LmbRBpGafoxXgOlcVfDmQO8LdKbKHWJOEN4oEhxF3zEgPf9rRMWEI0oE9KoOau7R5DVJMB6Bbf6tOxbHlVwPmnXGsEIJFDt7Wb79knZihK1mfLqaOumcAznQZiFdNt5NbBSestUCytXDDJn1fm8IGxXsBQSsEEtklg9phenjmMG38ABmyLhZCDiDEQ4M6VRPseVXpPhNYuija8YePhrB1y1aW1Cab7wglIIbeGj1Z06sJ6i4HGkAXtn2M1HolRLc6oPohihPaYtrKOFCtJarwbCHMtQjaR9GnzVfGoLFKemhY0kOZvAdLmB0g1QUKsmcKtNdpQwVYwciJE9vvIlgMIpeWBrU6cDkdIbQDOM6dvLicO3BZQqBXbSNgLcXsF1JqlD5YgUzdARjxv7tagxjXVJ4DVB31UgXcBWlEmI1gGrbVZUTQ4Kaj609StfQw2XNNdal8eES46C4rqHtTGCtdUjW7QINXaqt1efjNk4WYFS9OTGKL0GcgvF5ERlHuAQh0R2R0rSQLl72ayOZDeausNRBDYyI24pie4gFb2LI1hJjRwVTJej0xllYoPtMgLxmkCnUpPhbpPjIwPYIZfSYE6CoV7oxy4BDSyK6ueE6dUak6hlEZwOnDh3aOTSVioq53vuqk6ofC2kT2ar1PfgH5SGxpXB6RpI5bYiF4NYoDX9zEOKHD7hwVHoLK4UusPJWSNdbIDuIBmGb6p83vnEZukNaY5ocPZTZyM1Ex8dDOFiOiZs4bOgOY0NsJKv8pb4I1lDzSeBqPbytFkSAQrU5pUgK45bSIFlyEG3ef59nPHblCA8GstcMSm3zZETd5yVq1NAmQvAnabHyc10T3Arp8cm9Xe1SPVGMzEP6QjXMkZMRbwn8k9nXXcFNfRe6XjE4EhifwRuAYoUJ5jQEF5yrF1nYwwbsx6nlKtxlkxWljavjxH1aP8w8t50T3THX1hx39aktWddjRSjQJtu1rZcCxBCBx1FxictyrP9y5dhVVMGIup6mJ8vHws8nudLqHaiEEQlGlRGKi6hMcF31S8l1RWG6KJRsbm8x6jvJchk5ekr9Cj2fmCkpVdE2yCianjU7pCLibtfR7HV36uGK2d0DXwbrv0sXPr9M7KGgTLmSjlUJrohDBHshfHPdT5DgIq1boeBBZjxlxNoUxN7veZ80VjFSuNbCxTg9rcZeAT35qgt06oHboySGL1ZwGPs4Ip73tN1AYRlfo3PZBHWCT4V8mF0R9DDyFEdhkZtvjJLTNqroJsUuUAQzggheYufFunJ8lrwJyche4XaJqnKkv2JktuSbLXol2NoNX31493O2F2nnwWbzgff1jh2gDvPiG9o8wvNrXY06Ar47WDF62YipcLuAY50RnPWaVOgC2vV0OmDGMxnu3niKM0rSiyOtwWzc8SbRPkdRzGwqmtmSFfJSLzNdDLFAbGyDel7WzMUtWuXfvqEZwLVco49zrlcnLPAT4OKNvSl6AcZaTulU9sA2xbEK7gKMv7r8HNJLdEze2cgHG6rXUiayefWE3o2V8YjSHyUwV4PmrW8neAv0v5zKnKBsE6QwlYX23NoaPBvSokjStkNbLxLec0ip6Rgy7vJv5AEA7nxbDM53WUz44898OKHrVjN9vqvoKPBQUXf5BHihloJQCnpk03yzcc2h6y3e9rMFPyMyLFI6Hd4jCOuwtOqTJjAJAvcJzP7gKkeAe9N5ObwtjNqkkWPOd1AJccZukWnT1Lu390xfY3eyRjdMutc5OkTo4di2u0AjVH3LtRIRfa0AHVEly3ZvBCCYo9jCZ0CV8s6PlNOJ6SkyZyZzO3VyOUYxfj09D0P8kCaQ8YcyyoeSKPKVlFvxEqALW8nXASnKCv5mvsAyZMGpYRHtoyu4mVyCIrdOjmyGIK462aO6KaGC6lfWkKisQhLmSK2PmrPeimdS5ViOHllBfwexF5AsmNi6LYrjS00uPTki9K06h6yuppMVV8ykV6HIZoLABicTm5NofudhYrqV5hWstXxunHAk2cNq5Is1mFSNU4eedYbqu2c3y8iD3QzLWO6FmxwWFu3XUK8upSJ2cK34uUl8kX1uRsWSNEMIMOils8HZwHtxZ9fZ09sT2fRJKAIKxx57h0leLsjciNT5iTrMHgsNTlpa5I1QDSbEqtlFhDvh3TYmAYBYUENhcVBZmVK62XhTPpzgmEIQX4dlZJbz9g6I85jjfJILKLsEpmErtbzglmQpyQNw2EQFzYIWu25tv2dTDoDRP7uDV4KDKl5pXKRwu5z4UQI4sXLPACK78x6EoEyVUFnBktvnT7mQe5bqAlJ7dhqUEbzC3AJIgVosnRplZqXInSlNdpTFOasW3YyQmQtDB4183vKzCe4UMdKnHkRAoA127iSIUvKe5w66Cv8cQU38AFyWp5eedMNu9NlbqepUEaYSTmas5odjQUJ23D35QCuO67zFILoDKqWYv7jVKXMIVZUnyvspAWbtUFYDij5SmP2QQCgCpExeDtmoVPdjusL1QqQjukGVc9nXHwjhZ7KwrtrC5XMeKgl9EBvNjRum0sn4B7MLhuqJPqreoTLE2unGcI34mKbWRbyHjSq5xi8uZy72MuDCXyUU4GmZrXNqMG7QAw4wAvMKI31G0uHJEaOSV5II9XGAuYSGTuUuO4y31NTQBPpa2O0JFfnFJgYveVoWL3cCcjJivvEWezutrJ3eObOFbV4ACiZ1uXwJFlI484ILeWSNkS3jaSgfIYvBK9SMVZwg6IuFtjX6D855I4U4XHMqKWla3IcaKvIKwYFlrOWPq81lflKMPLQvJnrEiUi67jZJZYF0rMKtrv2ayFEfFBDtG58hA9uIkCbvHAQOBeWpzuTNUdtZoNdAuLqxddjpxZr4moFtk1CjdQihJNQLPeZR0ZrQYVBUPMyFIV639RykPOPyhxFMSKQNo9xjNCuxnoZWBbtqHHXtFZdUBq7qkb0GzfiADZ7LaRtj9MNOLLej35Wy0L0xPu5Hy5v9N0Jslj65YZJvC7N8uMYuIR6rMuh2MhuthHOlxLLbzcBy7gicP5aFofdt4fkOBgitm8CCRdm0f9DQpETZ5hEGmkI4V59HRs2Up4CG2ajOFIZwRmbvs3B8M5NZmwf1mmek0j7qfjkOhpsp7RHMqUztEYGd1RX3S6vaHDSFEouqPiU07CjNFDV1f8x94tUq8ldicDtQN1DbR5oBTvdmQZsgG8K6oU70IKNhwX4idMFNaTcQ0ZsfJk1rQLh6cIoksmrbm6tYu97HQhVsDmavCs5CnkN2mZDEEj9HfK6O53ck273X3jRo01lFfT65KcUSH71zr3KkLPzxBbhhCRmdpXQSfyHwbN7QbKWi6NkU8G7xb8oRFFsR'; +const eightAndAHalfKilobyteRefreshToken = + 'Ad62a2Bfa5cdCdE489CaF47BDBaF9fbd8CCB6b866Bfc04bB2f8ec7D19ddc7d3189e5249e231cAd567745d4Dc83Be5ADd5BdDdC3cdDa8Cbfe2B2f2Cb01876eadF0A444eA420FEfb5EaFD918A9BbfabD8eaa512FdE7F3fC03bA134d99ebb43fe58eE8C7DaA587a563eac5B75E4bc03E31BcD9dB5DABa0a24e7A6B44C0C585Fc2dAA1dCc5ba110BBeeF7404dE5a0e416A86e23aFADd9efA19faabC74DfdbeCe70E396E054fe2dA1dcCddf5f6f36d1dEF8371FD31BbCA9D1e23a6deCfC43Db00750a2feE0fc7ff6dBdeBaC1557ccA546E8B0B2E6860cfdDC96bBf2356Adff7CFCB1AACC183Fc3DE8bEb0dcFb22D19f44B9f4a6fC0AbE9BCa64e31baaD85aEdE42C1E3b4Cd7F8FEEDDda1dC25C50E93353Df12dCACCA85cD7E6Fb99cbAB4Fb59EDAc3De414ffdC1AbBa3AA06Cd11e9c6eAA1Eb6B1dACa1BE7afd34234Ae6B1Fd2e2Aeb7e0C74cbB3F6fFc39ec6Dd805ddA1433cDfD4bCBB8b19Aa6eB2d19eDE0e57E668302b9E700a4f170967E38F0C8c664AcFbAE6f98eAB5e3EC96AcFcf862Ae90843ffdeEBB89DE2933e55a4bCEB45E07aB1AeB2e8dE4e70e7d4aDB8B3020fC48d0FD4A2A03c6Cd97cbc6A169e13b7AE73A37F25082B4aBe19EB050F0768e2Db7D3514BCA067B79687d03260bd0A4bfFe02cF38Fd31bC09D52fccFAD1D73E51BE55f11BECfFBA6F988fEE16004Be54AD6CC87741DaA40Db1f600fEffC0fa17b77F85e883E6F9BE8e92dA6C862C28DBf128de0A8d307Ad6b1ddd4a9493ee1F8731aBd8Da2f0e85Af89DEC18678bd7ffAA75FA5a79f4cF5A0AAb4f3aD1Df7E2BBDD24Dd3BB12f26cA5f0359a9462f5f5e32EBCA7346BF171ba4F1E2af7f3Ee8B3C8C776B4f0D0622EeBDdBa9Cf9314a85c9F2952aaf25bB2B79A2418ACa6f3bbA76eFB99FA0eC8e30F4e7b5853dfB8f6cdAeEb337dbeD2392e95BECF0Aef66fDbeb0803Bc950EEfed4Ff9b865C80bBBdb074facCE5614E8CC6DF0033cF223c2D5dC60Bd6Bc30141dc5120B8D5D429D4e07cAdfBD67BfdAEFEce8D32C15BA9CaDC1dCCDbf2D59CB370B57cDCa083cC9fEabc8B607c74E167cc1AAE121c6265Fee7b39eDFE10d31E8d59ad4e266a176010AC505BEd8ca057Eb224cf57DA4dfb98fd10A3Ee64F6950Ac54dbD3ffcbB35EfC84BEA9cbCa49872eEc9dAb29161d7b80475C42226914B5FaFCecC023c1AecEa9F89Da95bA4EF2Df2c3Daf14cBdBb9533E07E2E6141e76d1558dF33aeFbfe572fcAd33d3cFCC055bDDd8D8d8f1dCAe6Cff2aCCAfe653b7e845ae459563D0da4E995D35559200EF6FaDbDA59a6BBD323cE8E370fC3996Ed9ebcef1dCeABb067c2c9E96adFC22F058bDEb00bc037549CBCEAF3e6D3b0bB914Aa8CB00a4a97D34cc6D15Eecb295B0a26bD83109EF2af3C82AF55f146ffB26Ebe727eD86dDEB1BF7b714Bb0a58Ad152daAaDC7F5dAEDfAA109d6fCe2847D3b32B41E8c29DAC6499bDA10F8A7a5c3E0b2a1d0f2DE2c3e88de4DFDF85B4AD4Ddae8e8D6dF5bF2affd8dFc2185A92E81E9CEFB0cd71Bf5Ac4C09AEe012eFC79B5dFf447b9AAAFadA871AEac9be09cDa26E1c56F54DD8b8Afac765Fc452c0e11B45daC6ec766B80002C544E4e6342b0B445CE1AfEC0FE8E9d7DE5EF5Ec4921515Ddb8Ee7BEbd68d7065154252E75d922A4b8E4d0AaEcc6Dc3db498E9CfF41bb121B69Ebb774B3cf998316C80Fe73F7d688bcDec894BD3adf5c5AA6A36044C5B01D2dCCcc23BF21F91cd95E55ca1aDaA770AE0b65fE67aA95d44D0BBD3FFDa20bc6EdFcC7e2ef5B46225EFF5c767BdCE8C666Cdcae2aCf9ADb7CD3C10b59be627AbE5B0FDEA16dD9C4727FbECF6bEcAb1b8E1f5716eDEbEaf4E550B8c7CAfDd0C0BE15b6D4bBE3261f9c657aB885B8862C74ED9af0FD725CBCBd7ded2B0d6fb8eEdc802BB1EC2c7609399844a2DCaDC0DF2a0ada1fa91E7a4FFeee6C7AEB3A42DCb85eCc3fe6b31B8D857225a43C49CDBAcB9E855CF9C3ecC05cc41FCCdc9c6b10aa201D0471658aaDBB2077abc0516ee7911F8e1A435eEDBf50e0C12b5AB3e40A4DC2aD61Cdefd6CDd2d16dC9c0d5eE5C2573A6AfceB43d9E6f9e3C7BdAa5CbD2FFcB1AcFAdf52B6EC5cc5B0AC36c2c932124dc8C43cd6867fBfAc1F4DFF957E0f8F09Ea0e4C60faccc4D4E84bC0F0163aD1e2E6977ff83FAaebDd2cc1Fa8BCa821B29f34F242E3FdAb05Bde16a0C46af8CeeAC2EaC00Cf81C112e6Ee0b79b9f5Af9eD0acCc330794aeDf8aa3551C35063BF2D108E4a190cDE9055a3eFB08CFCCe7750eCec6eD4BF2dFDbec7b3A9Bb6cDa71eAb0De2CCA3F6bACFF4ce9304b7B5EAd78a5DfDef6cDbd2df49f0F806ECd85Dab8B1B9B76C2AA0d50baBCAd9db11761f572feF3D50CEFAb6Bf3e38Af8EED4cafe43E47BD68dB67fEfaDC7b3FF2eF5C285DF0850bE8b17B2AfDCDa0923b4BF1f0E02a279B0bc87c5d2Ca60ADc1ccccE07f58BeDC8a31bC9F25bF3D7C6fA4be472cfA4B1F0Ffd37d0EcACAa1Cf1dA07Ee8aE5AB9f88E54db4b6be0cEb3aBcb0DdEf5394a40d25e5138aeBBE1f3b191eCcBFcCC949AAd584BFe2Fb932797E6ABBCaB8BEBB96daBD097fedA5fE1dfce3F0E4BEc518aB25FfCBBb0aA007ffafb04d3BbCC5e0347AcBbc3006C05C41CBeeBae17A149b15Bc1533aeB44017cc5BCDfc6c5d2AcCEc4c17A44e53D42dc68C6f93eFa7D1d2f9f2D4e4Dddd90dCa0f15dD1aa40D7eBff9b0Cb7d7Da33FD2cb0d5Af8DbcbaE47Fb86Abf8bE20A7FeBBD4a390abB6abfD8C8D5E41e2BEd8E3eBFD2d1B8d41d605AdEF2BE63E22C09A55fBbAbfbeb8fed339119bf34a8d0BA3e912702b9c0DF7b476FC538eD06571EF2dE208beCDA8134BeEcb1F794BeaaDCd5619fd05EABAA82d58cB0cC9Cc3adA0D5fcF915b6E9dA9517caB500aDEAc8aAB6ad26b3E2F8Bf7cd2004f7cF74cA4b2a495CDed2a7a5CE42b6DC8e95326a7637f21EbFCbEcE8860EfDb31Df9aaF6F133674723f716a600B1c01DC98c7aA4fBe9cb81E7C50F3Bdc966D8BDa1AFcd4EBfB922f2eba045B3726d3Cec02Bdd606ae43aaeaa0EA945D4ec95d9E5E1AcF92aa75F4db4AC453Ccc51ceAdBD7b0614BfeCC303AADc40bCfDDfC76bfafFdbcD47D4B729EEF1CCED07C3dF85EEfC2eCcbbB45F8D5f1D09e9A1964fEF402E29AE024dEEeAeDEfF377E7b2ee2F621165dEB3CE9f4471DEeb396Dc3B508Bb0C2A51c4CC4Ba5Ca1aa9ca7b401D6C0421EDB83CF03EA16bA24ceE3FC4e7Ad4BFc7dAbe16e4C2A51F4e2cAeb7bC7287684268ea7FAae360A1A8aF5BFED450db3D66363284eD57B2f9D25A5c4FE424a7feE764eaA0e47F96b77Af2bd725c1c8DbE5A7FF2e0c7cE7F9eE0FCf7bdF00543a9ED1C485CDC2e82386F440D04FEa6380B9bbE48C605bF0fbDe0dc2cEAe35C2BFB84dF62185B8e6BABBE89DcCF1b1Cedf5aDadeBdd3Bd66cc76aC6badb2F1ec27C411ccd3cCD823feE8A8F9aE8C0e1cc0fE6484fBd2c58C77Fbcbdc662C7EEeb684dAaeE0489C40d8A91d6DCec15A3e506783C35acBD0Dad364AeeC295d7eD1BecdB2d1d9d1352dE4F7f52B50e272ab9E57e8AFbCC54fEEbB640F5FD37b18f6a46D70f0cBCB98aBAdd6EfcF06f5f5Aa6D61b3FD4c1aeB46Be0Da0Dfcaf5c45e2FDF46C43aFcCb952Be929adaFcFeECbCDB6Edc61472DBC37Eeeff5a5B64Bd1Fee6B5e6861EcBfff3d6103a7E3e361EC08Ecb4d81c0FdefAdA9d861c12e7aD85678a23E5E94F3dC9677d4B82Dee5A24dDbebF20B880c25C6955dCCC276ff9C3505a85bBE6aB08E6EFb3C35DC1fcFDC8F86E4bE7C1F0fBF8b1B8594F122fFAd7c6CDe8fba97af1697Ae3e5cFc485B8E0Ae66dbD485afceBAAe550cdc9E4B4CbEbC51c85D6BeCb83BF51f41DDeCAbe4bB75209eA0EaeEe6010Da909b5CBd1D1CBaE7b579F48cd5Af0d2F81c1E8ADcaA4DaCA01Ea206fee4ECBc8fddaa505b41c114EABF753F5aD02B25Be96bEa1dfF5e04EddEcEbA8881EfCe9AB957e0366DdCD9E32ecBdFC1B0Ab6f1effdcb0b1A3d2f7eFEf59EB2bddC130305d4bAe6f627e1087B3Ef5Cdd1f2A75Eadc6B4d79A5b6d55fEA7ea30d3cDd74D74F3bD2aa99b5ab3FC83Acbb9ee0fBa05D4d23DACeBb16cda8A2bF7Ca4D85eee1BAc9D06Cd899861bB5e2e4B9c30E1C887d19DbF81cFe8Ae9b777249f542faAFE3b3bd49Ba5295afbd927A475C0C3B81C1ee6eEB8c00451CFBcCFfF7Fc8aD0b7251c00D507cEfe86BeEeFe5FBded0FBe30CC447DFaB930c04c4460e9f9cbf1BBF2eBFdF06D3AAed2af2BEDBA0f296AEfAf90571F9B63e0876fFADfDf61408B6dedeBfE2dE7a8ee750Ef78B1289b6fCdfdaC58393e373a5dA35d2b149c9FF5a1fA9DFeCc37c678Ce657A172D5d990BbbFDa089288dCa5F89f6CeF7cf6b1EB2609BBD65e6fFfa815Cc59abcE387ead000Af1B1C1cC87faB990D1b9AfcEfDc3D68cCCb9b7475803829dDebA48e92df26AC70027CcEfB6F6FDd1DA25DFB9dA0aE50398998E7EbEEaE11BB68a2E03c5f8306eaca1aF15CeBCB05a6FDb8E3BdAAeFfeC21Db12762dDBABd3eDf12A438B3C37B51cCaCD1Eda73dFCCeF06BCFbECE21F95e2Ae1d0F161dEec60a17D01d1Dc425b85aCD0adeCCBdddd310581aa0eF48FfF8a6A727E95BADefF6Cd011Df1c993DB5aE2ec8c3dD42cD704a5e0AC8bCbae34F245e7ABfba828efa3adFFefb33fCa32ad0b2Bd7C4Ae56C3d932E7A1a24bE87Bd235067A73CcBC5A8Cd44B0Fa5131dacCDEA7454aAb7c0Dfb006B6EbFAd3dD1EAEee79c9Da23FA02D88CD8333BE964E7D2eBbd1AAAE06E67463CCb6eceA604Cdd2A16d834599c86914Ea9b063243C4Ebe8E6aa677fdE2b67A6eE4Cfe1801273137ec777DEfc84D4B3d0e96dFF1f7CCaB0CFD307Ba1fC16b9C4f4d1fee0ee0f05BB1102eEeA5E49e7f339BE6d9335Bf2F28d57f194D9facA9c5af5B08B08D7530c7DDe99D0Ae0D8dD5d0c13B77fDf1E3Bc0aA8e71C32EAD5AaD7Bed538F26d4deaA3A67C667201C5Fd62A5FaeDde62E6DC78E62bEeaBFaa030cFDa4E86f5B3C48bBE7bB4Be5528D3D0fd69BCCE1D8B6d04Ee6B9a1B5c49572B21FFFf1bDf06cd98fa9ED5fd9Dc3B04bD4530B8CBD5d0106799E4CBCE64c65EFcfb4f84Ba0ced14BECdcd4bb33CA38B4eea4bF7e665Eda4a8ADfBfae5C45b2B91e2C1eCD0CcBC85275d4Ca8318638eB77Eab97845c40Ccd34f7ef99385Ce275B30013f7BfC2c088a2F332DAF6Ca2CFB21d5f8EAF177B519cAF56ca42a9DAfadBAECb5E16Bf671BDB2BBb15c8eb1F4Cb9dfDbfbcFcFAEABAD3aeeCF8e84BbEECf3dDf0f7FdBCF44aa1A4ac7bFac026B8Ab6C0004a1dCc6bc2b5eb8fA7cEEe9cEeAce5d287BCE0E5f3bBffdFaED134286794D704b32DD36cF2FF80dd39FB09cAbCF1FaF07a2aFB0EA7FeA464b90f77090B846Fad58Ca0fB83eA3d6C4dDBCFd17b8c5EFCc7a6e1efDaaE8B4Ecae65C89BC80Df9bC844cE9aDCcFdaE2be0f0Bc6AdBDB6E814d2050febEB3BaFCfBCCADF749BC2Cde2BeC0e7E6e14afa92Fe5fd51A8Ef62aC53FAE304B0f4317Ab5db11fD13ecAcd8995E6F87Fe4Ff5FF89e4B7b44A754f52a7E4fDDCdfDDefEE4aD7AcAacDCa17fd3a2b43D4bc74B3Cad0aeee8eDBa25D56e3Ba0C5cd8B8E2a2c0B8f951Fd7AFC75edEAee0c28bf3cEBc3af7C60ca147fC9cF0886B066e263f36CA5B5BB36aB82f0f0A58FE3d67f1a9fc24270e6170ac34E6eE5c1bc64B1B5f416afbb8E8edD2cFA9fdcAF7Be904EBaA1abF8b0c2D5cc176C5866fcbCECa5342d7439Cc5E859dBe6a18e9c58EC2e9a5bc20a79D3E3CF073aD4c4F12409E787fFA0Dd1C6d3f01b3CeaDC7F5Cc9be3415f0DFFD5F2E2Fb0dBA6843CCB1aECbF1480E8fCFc16e2cEDB8B8e292dFFeF1bBc6F9C7DD4b873DBbbD528d0fB1E4D02ba3EDe9f1c13b4DEE0FC8BAAdc5cAB40AF2EC4eFDAAfD31104bC04CEFFCbEAae6aA1C91FAccAEed7B3dE6FF226Db01f62E239fba8BD5aE9B7C9a4DeeF746ec2F9580368FB1DDcF785e410aec4a70005a609CBBebf42f714b3c59a76cB06c3c86Ca3dfbB5EcAC'; + const baseConfig = { authenticator: mockAuthenticator, appUrl: 'http://127.0.0.1', @@ -116,6 +123,30 @@ function getRefreshTokenCookie(test: SuperAgentTest, chunkNumber?: number) { }); } +function confirmRefreshTokenCookieDeletion( + res: request.Response, + { + domain = false, + path = '/my-provider', + chunkNumber, + }: { domain?: string | false; path?: string; chunkNumber?: number } = {}, +): boolean { + const setCookieHeaders = [res.get('Set-Cookie') ?? []].flat(); + const cookieName = + chunkNumber !== undefined + ? `my-provider-refresh-token-${chunkNumber}` + : 'my-provider-refresh-token'; + return setCookieHeaders.some( + cookie => + cookie.includes(`${cookieName}=;`) && + cookie.includes('Max-Age=0') && + (domain + ? cookie.includes(`Domain=${domain}`) + : !cookie.includes('Domain=')) && + (path ? cookie.includes(`Path=${path}`) : true), + ); +} + function getGrantedScopesCookie(test: SuperAgentTest) { return test.jar.getCookie('my-provider-granted-scope', { domain: '127.0.0.1', @@ -125,6 +156,12 @@ function getGrantedScopesCookie(test: SuperAgentTest) { }); } +function extractTokenStringSlice(tokenString: string, index: number): string { + const chunkSize = 4000; + const start = index * chunkSize; + return tokenString.slice(start, start + chunkSize); +} + describe('createOAuthRouteHandlers', () => { afterEach(() => jest.clearAllMocks()); @@ -329,14 +366,137 @@ describe('createOAuthRouteHandlers', () => { }); expect(getRefreshTokenCookie(agent, 0).value).toBe( - fiveKilobyteRefreshToken.slice(0, 4000), + extractTokenStringSlice(fiveKilobyteRefreshToken, 0), ); expect(getRefreshTokenCookie(agent, 1).value).toBe( - fiveKilobyteRefreshToken.slice(4000), + extractTokenStringSlice(fiveKilobyteRefreshToken, 1), ); expect(getGrantedScopesCookie(agent)).toBeUndefined(); }); + it('should replace and clean up chunked token bigger than 4KB', async () => { + // Create and use a custom cookie configurer to make sure to circumvent legacy cookie removal mechanism logic + const customCookieConfigurer: CookieConfigurer = ({ + callbackUrl, + providerId, + }) => { + const { pathname } = new URL(callbackUrl); + const path = pathname.endsWith(`${providerId}/handler/frame`) + ? pathname.slice(0, -'/handler/frame'.length) + : `${pathname}/${providerId}`; + return { + path: path, + secure: false, + sameSite: 'lax', + }; + }; + const agent = request.agent( + wrapInApp( + createOAuthRouteHandlers({ + ...baseConfig, + cookieConfigurer: customCookieConfigurer, + }), + ), + ); + + agent.jar.setCookie( + 'my-provider-nonce=123', + '127.0.0.1', + '/my-provider/handler', + ); + + mockAuthenticator.authenticate.mockResolvedValue({ + fullProfile: { id: 'id' } as PassportProfile, + session: { + ...mockSession, + refreshToken: fiveKilobyteRefreshToken, + }, + }); + + // Simulate 8.5KB token (3-chunks) that should be replaced with 5KB token (2-chunks) + agent.jar.setCookie( + `my-provider-refresh-token-0=${extractTokenStringSlice( + eightAndAHalfKilobyteRefreshToken, + 0, + )}`, + '127.0.0.1', + '/my-provider', + ); + agent.jar.setCookie( + `my-provider-refresh-token-1=${extractTokenStringSlice( + eightAndAHalfKilobyteRefreshToken, + 1, + )}`, + '127.0.0.1', + '/my-provider', + ); + agent.jar.setCookie( + `my-provider-refresh-token-2=${extractTokenStringSlice( + eightAndAHalfKilobyteRefreshToken, + 2, + )}`, + '127.0.0.1', + '/my-provider', + ); + + const res = await agent.get('/my-provider/handler/frame').query({ + state: encodeOAuthState({ + env: 'development', + nonce: '123', + } as OAuthState), + }); + + expect(mockAuthenticator.authenticate).toHaveBeenCalledWith( + { req: expect.anything() }, + { ctx: 'authenticator' }, + ); + + expect(res.status).toBe(200); + expect(parseWebMessageResponse(res.text).response).toEqual({ + type: 'authorization_response', + response: { + profile: {}, + providerInfo: { + accessToken: 'access-token', + expiresInSeconds: 3, + idToken: 'id-token', + scope: 'my-scope', + }, + }, + }); + + expect(getRefreshTokenCookie(agent, 0).value).toBe( + extractTokenStringSlice(fiveKilobyteRefreshToken, 0), + ); + expect(getRefreshTokenCookie(agent, 1).value).toBe( + extractTokenStringSlice(fiveKilobyteRefreshToken, 1), + ); + // verify that the old chunked cookie 2 is cleaned up + expect(getRefreshTokenCookie(agent, 2)).toBeUndefined(); + + // verify that deletion was ordered for old chunked cookies + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 0, + domain: false, + }), + ).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 1, + domain: false, + }), + ).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 2, + domain: false, + }), + ).toBe(true); + + expect(getGrantedScopesCookie(agent)).toBeUndefined(); + }); + it('should clean up old cookies (non-chunked) with domain attribute during migration', async () => { const agent = request.agent( wrapInApp(createOAuthRouteHandlers(baseConfig)), @@ -367,15 +527,9 @@ describe('createOAuthRouteHandlers', () => { }); expect(res.status).toBe(200); - - const setCookieHeaders = [res.get('Set-Cookie') ?? []].flat(); - const hasDeleteWithDomain = setCookieHeaders.some( - cookie => - cookie.includes('my-provider-refresh-token=;') && - cookie.includes('Max-Age=0') && - cookie.includes('Domain=127.0.0.1'), - ); - expect(hasDeleteWithDomain).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { domain: '127.0.0.1' }), + ).toBe(true); expect(getRefreshTokenCookie(agent).value).toBe('refresh-token'); }); @@ -393,16 +547,19 @@ describe('createOAuthRouteHandlers', () => { // Simulate old chunked cookies with domain attribute (legacy format) agent.jar.setCookie( - `my-provider-refresh-token-0=${fiveKilobyteRefreshToken.slice( + `my-provider-refresh-token-0=${extractTokenStringSlice( + fiveKilobyteRefreshToken, 0, - 4000, - )}; Domain=127.0.0.1`, + )}`, + '127.0.0.1', '/my-provider', ); agent.jar.setCookie( - `my-provider-refresh-token-1=${fiveKilobyteRefreshToken.slice( - 4000, - )}; Domain=127.0.0.1`, + `my-provider-refresh-token-1=${extractTokenStringSlice( + fiveKilobyteRefreshToken, + 1, + )}`, + '127.0.0.1', '/my-provider', ); @@ -423,28 +580,24 @@ describe('createOAuthRouteHandlers', () => { expect(res.status).toBe(200); - const setCookieHeaders = [res.get('Set-Cookie') ?? []].flat(); - const hasChunk0DeleteWithDomain = setCookieHeaders.some( - cookie => - cookie.includes('my-provider-refresh-token-0=') && - cookie.includes('Max-Age=0') && - cookie.includes('Domain=127.0.0.1'), - ); - const hasChunk1DeleteWithDomain = setCookieHeaders.some( - cookie => - cookie.includes('my-provider-refresh-token-1=') && - cookie.includes('Max-Age=0') && - cookie.includes('Domain=127.0.0.1'), - ); - - expect(hasChunk0DeleteWithDomain).toBe(true); - expect(hasChunk1DeleteWithDomain).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 0, + domain: '127.0.0.1', + }), + ).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 1, + domain: '127.0.0.1', + }), + ).toBe(true); expect(getRefreshTokenCookie(agent, 0).value).toBe( - fiveKilobyteRefreshToken.slice(0, 4000), + extractTokenStringSlice(fiveKilobyteRefreshToken, 0), ); expect(getRefreshTokenCookie(agent, 1).value).toBe( - fiveKilobyteRefreshToken.slice(4000), + extractTokenStringSlice(fiveKilobyteRefreshToken, 1), ); }); @@ -460,16 +613,19 @@ describe('createOAuthRouteHandlers', () => { ); agent.jar.setCookie( - `my-provider-refresh-token-0=${fiveKilobyteRefreshToken.slice( + `my-provider-refresh-token-0=${extractTokenStringSlice( + fiveKilobyteRefreshToken, 0, - 4000, )}; Domain=127.0.0.1`, + '127.0.0.1', '/my-provider', ); agent.jar.setCookie( - `my-provider-refresh-token-1=${fiveKilobyteRefreshToken.slice( - 4000, + `my-provider-refresh-token-1=${extractTokenStringSlice( + fiveKilobyteRefreshToken, + 1, )}; Domain=127.0.0.1`, + '127.0.0.1', '/my-provider', ); @@ -487,22 +643,18 @@ describe('createOAuthRouteHandlers', () => { expect(res.status).toBe(200); - const setCookieHeaders = [res.get('Set-Cookie') ?? []].flat(); - const hasChunk0DeleteWithDomain = setCookieHeaders.some( - cookie => - cookie.includes('my-provider-refresh-token-0=;') && - cookie.includes('Max-Age=0') && - cookie.includes('Domain=127.0.0.1'), - ); - const hasChunk1DeleteWithDomain = setCookieHeaders.some( - cookie => - cookie.includes('my-provider-refresh-token-1=;') && - cookie.includes('Max-Age=0') && - cookie.includes('Domain=127.0.0.1'), - ); - - expect(hasChunk0DeleteWithDomain).toBe(true); - expect(hasChunk1DeleteWithDomain).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 0, + domain: false, + }), + ).toBe(true); + expect( + confirmRefreshTokenCookieDeletion(res, { + chunkNumber: 1, + domain: false, + }), + ).toBe(true); expect(getRefreshTokenCookie(agent).value).toBe('refresh-token'); expect(getRefreshTokenCookie(agent, 0)).toBeUndefined(); @@ -804,15 +956,18 @@ describe('createOAuthRouteHandlers', () => { ); agent.jar.setCookie( - `my-provider-refresh-token-0=${fiveKilobyteRefreshToken.slice( + `my-provider-refresh-token-0=${extractTokenStringSlice( + fiveKilobyteRefreshToken, 0, - 4000, )}`, '127.0.0.1', '/my-provider', ); agent.jar.setCookie( - `my-provider-refresh-token-1=${fiveKilobyteRefreshToken.slice(4000)}`, + `my-provider-refresh-token-1=${extractTokenStringSlice( + fiveKilobyteRefreshToken, + 1, + )}`, '127.0.0.1', '/my-provider', ); diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 6a92a82a99..8d5ee31f64 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-react +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 7348245f87..3a11292642 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.22-next.0", + "version": "0.1.22", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/auth/CHANGELOG.md b/plugins/auth/CHANGELOG.md index 7c66e1b692..f402cffbd3 100644 --- a/plugins/auth/CHANGELOG.md +++ b/plugins/auth/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/theme@0.7.1 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/auth/package.json b/plugins/auth/package.json index 77412a3c05..629d00efa9 100644 --- a/plugins/auth/package.json +++ b/plugins/auth/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth", - "version": "0.1.3-next.0", + "version": "0.1.3", "backstage": { "role": "frontend-plugin", "pluginId": "auth", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 0f6425b00b..a1a06e7318 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.3.5 + +### Patch Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +- Updated dependencies + - @backstage/integration@1.19.0 + ## 0.3.5-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 354b2ad31c..536ae53f9f 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.3.5-next.0", + "version": "0.3.6-next.0", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts index adbf08cf40..eb40b51b5b 100644 --- a/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts +++ b/plugins/bitbucket-cloud-common/src/BitbucketCloudClient.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { BitbucketCloudIntegrationConfig } from '@backstage/integration'; +import { + BitbucketCloudIntegrationConfig, + getBitbucketCloudOAuthToken, +} from '@backstage/integration'; import fetch, { Request } from 'cross-fetch'; import { Models } from './models'; import { WithPagination } from './pagination'; @@ -139,22 +142,32 @@ export class BitbucketCloudClient { } private async request(req: Request): Promise { - return fetch(req, { headers: this.getAuthHeaders() }).then( - (response: Response) => { - if (!response.ok) { - throw new Error( - `Unexpected response for ${req.method} ${req.url}. Expected 200 but got ${response.status} - ${response.statusText}`, - ); - } + const headers = await this.getAuthHeaders(); + return fetch(req, { headers }).then((response: Response) => { + if (!response.ok) { + throw new Error( + `Unexpected response for ${req.method} ${req.url}. Expected 200 but got ${response.status} - ${response.statusText}`, + ); + } - return response; - }, - ); + return response; + }); } - private getAuthHeaders(): Record { + private async getAuthHeaders(): Promise> { const headers: Record = {}; + // OAuth authentication (clientId/clientSecret) + if (this.config.clientId && this.config.clientSecret) { + const token = await getBitbucketCloudOAuthToken( + this.config.clientId, + this.config.clientSecret, + ); + headers.Authorization = `Bearer ${token}`; + return headers; + } + + // Basic authentication (username/token or username/appPassword) if ( this.config.username && (this.config.token ?? this.config.appPassword) diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index d42c4e06b6..03ec97083a 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + +## 0.4.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/integration-aws-node@0.1.19 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-kubernetes-common@0.9.9 + +## 0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.4.18-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index c73960b473..acdec6390e 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.4.18-next.2", + "version": "0.4.19-next.1", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index c5956021fe..aeeff02acd 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.3.12-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 23ad359d21..6e6497e1db 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.3.12-next.1", + "version": "0.3.13-next.0", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index 3bf19b22da..718dde0ce6 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-node@1.20.1 + +## 0.5.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.5.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 3dfa270e86..9eb50da0bf 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.5.9-next.1", + "version": "0.5.10-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 951cd48ace..62149e2b19 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + +## 0.5.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.5.6-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index d91f41cb8f..011b6bf909 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.5.6-next.1", + "version": "0.5.7-next.0", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 7aba4e8a30..1c73573c76 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.5.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.5.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.5.6-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index f94d7c87d7..c0feb69a9e 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.5.6-next.1", + "version": "0.5.7-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index f5b00f9d06..5102f3266f 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.3.15-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index bb7c0a200e..620c35c84f 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.3.15-next.2", + "version": "0.3.15", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap b/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap index c903bcd192..18fd9b58ce 100644 --- a/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap +++ b/plugins/catalog-backend-module-gcp/src/providers/__snapshots__/GkeEntityProvider.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`GkeEntityProvider should return clusters as Resources 1`] = ` [MockFunction] { diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index dc2c9d7a4d..ecc3cf831b 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.3.9 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.3.9-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 6a49d35277..5cfccbffd4 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.3.9-next.1", + "version": "0.3.10-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gitea/CHANGELOG.md b/plugins/catalog-backend-module-gitea/CHANGELOG.md index 11f4ff7cc3..eec7ee8b10 100644 --- a/plugins/catalog-backend-module-gitea/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gitea +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.1.7-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitea/package.json b/plugins/catalog-backend-module-gitea/package.json index d80ddb806f..5992c56171 100644 --- a/plugins/catalog-backend-module-gitea/package.json +++ b/plugins/catalog-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitea", - "version": "0.1.7-next.1", + "version": "0.1.8-next.0", "license": "Apache-2.0", "description": "The gitea backend module for the catalog plugin.", "main": "src/index.ts", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 2c7acb8b3e..1529c9a49b 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.12.1-next.0 + +## 0.3.17 + +### Patch Changes + +- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances. + + When it’s set to true, suspended users won’t be returned when querying the organization users for GitHub Enterprise instances. + Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail. + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-catalog-backend-module-github@0.12.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.3.17-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 0d871749ea..b5614e5ab0 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.3.17-next.2", + "version": "0.3.18-next.0", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 2247087317..de1a33fc6d 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-backend-module-github +## 0.12.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.12.0 + +### Minor Changes + +- b3286d5: Added the `github.com/user-id` annotation to store GitHub's user ID (immutable) in user entities. Also includes addition of the `userIdMatchingUserEntityAnnotation` sign-in resolver that matches users by the new ID. + +### Patch Changes + +- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances. + + When it’s set to true, suspended users won’t be returned when querying the organization users for GitHub Enterprise instances. + Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail. + +- a413977: Added configurable `pageSizes` option to `GithubOrgEntityProvider` for GitHub GraphQL API queries to prevent `RESOURCE_LIMITS_EXCEEDED` errors with organizations with large number of teams and members. This aligns the configuration options with `GithubMultiOrgEntityProvider`. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.11.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index cbd57f1568..cb61e06e9e 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.11.3-next.2", + "version": "0.12.1-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index 1f9bc5035d..e781626038 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.7-next.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.7.6 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 12d6b52425..3587dd5e5e 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 9736abe90b..ffda3d9f15 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.7.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + +## 0.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/integration@1.19.0 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + +## 0.7.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.7.6-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 37edb7bb1a..5b4e9a0a16 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.7.6-next.1", + "version": "0.7.7-next.1", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index d2cd96a4b1..f1e8c36d89 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.7.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + +## 0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- fb029b6: Updated luxon types +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.7.7-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 875d3c3d9e..133cae849e 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.7.7-next.1", + "version": "0.7.8-next.0", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 9e4cca6cc4..6bcb9ea561 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.12.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.12.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index abf0717679..52bce2aae7 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.12.1-next.1", + "version": "0.12.1", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index ffcf0a98ba..633be5a127 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-backend@3.3.1-next.0 + - @backstage/plugin-events-node@0.4.18 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.3.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 2b4fd92c73..12224abd8a 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.1.17-next.1", + "version": "0.1.18-next.0", "description": "A module that subscribes to catalog related events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 7354d45c76..6577c69166 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.8.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.8.3-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 9b87318300..0dddba19f7 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.8.3-next.1", + "version": "0.8.3", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index af02b2a7dc..59ad2533d7 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.2.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 47ea21295f..ac32292848 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.2.17-next.1", + "version": "0.2.18-next.0", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index 01df77b6e7..c270f87cb5 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.2.17-next.1 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index baaa9b1adb..f2cd6115d1 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.2.17-next.1", + "version": "0.2.17", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 490700d5f4..c17e5817e7 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + +## 0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-common@1.7.4 + ## 0.2.15-next.1 ### 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 c01c22cad6..015bc7a63a 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.2.15-next.1", + "version": "0.2.16-next.0", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index fb3d3f57a4..32dde9548a 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.6.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.12 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.6.7-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index d0185c8a6d..b735e7a13a 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.6.7-next.2", + "version": "0.6.7", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index fee155e596..3d86c0fe35 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend +## 3.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 3.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.7 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + +## 3.3.0 + +### Minor Changes + +- dce1824: Added `ActionsRegistry` actions for `register-entity` and `unregister-entity` + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 8101ec1: Fixed default refresh service to go through the whole ancestry of the entity. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 3.2.1-next.1 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 04676121a8..fccc6aa57c 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "3.2.1-next.1", + "version": "3.3.1-next.1", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.test.ts b/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.test.ts new file mode 100644 index 0000000000..31a89a31f3 --- /dev/null +++ b/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.test.ts @@ -0,0 +1,105 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createRegisterCatalogEntitiesAction } from './createRegisterCatalogEntitiesAction'; +import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; +import { ForwardedError } from '@backstage/errors'; + +describe('createRegisterCatalogEntitiesAction', () => { + it('should successfully register a catalog location with a valid URL', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const mockLocationId = 'test-location-id-1234'; + mockCatalog.addLocation = jest.fn().mockResolvedValue({ + location: { + id: mockLocationId, + type: 'url', + target: 'https://github.com/example/repo/blob/main/catalog-info.yaml', + }, + entities: [], + exists: false, + }); + + createRegisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + const result = await mockActionsRegistry.invoke({ + id: 'test:register-entity', + input: { + locationUrl: + 'https://github.com/example/repo/blob/main/catalog-info.yaml', + }, + }); + + expect(result.output).toEqual({ + locationId: mockLocationId, + }); + expect(mockCatalog.addLocation).toHaveBeenCalledWith( + { + type: 'url', + target: 'https://github.com/example/repo/blob/main/catalog-info.yaml', + }, + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + }); + + it('should throw an error if locationUrl is not a valid URL', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + createRegisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:register-entity', + input: { locationUrl: 'not-a-valid-url' }, + }), + ).rejects.toThrow('not-a-valid-url is an invalid URL'); + }); + + it('should throw a ForwardedError if catalog.addLocation throws an error', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const errorMessage = 'Failed to add location'; + mockCatalog.addLocation = jest + .fn() + .mockRejectedValue(new Error(errorMessage)); + + createRegisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:register-entity', + input: { + locationUrl: + 'https://github.com/example/repo/blob/main/catalog-info.yaml', + }, + }), + ).rejects.toThrow(ForwardedError); + }); +}); diff --git a/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.ts b/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.ts new file mode 100644 index 0000000000..c521672ae1 --- /dev/null +++ b/plugins/catalog-backend/src/actions/createRegisterCatalogEntitiesAction.ts @@ -0,0 +1,89 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; +import { InputError } from '@backstage/errors'; +import { CatalogService } from '@backstage/plugin-catalog-node'; + +const isValidUrl = (url: string) => { + try { + // eslint-disable-next-line no-new + new URL(url); + return true; + } catch (error) { + return false; + } +}; + +export const createRegisterCatalogEntitiesAction = ({ + catalog, + actionsRegistry, +}: { + catalog: CatalogService; + actionsRegistry: ActionsRegistryService; +}) => { + actionsRegistry.register({ + name: 'register-entity', + title: 'Register entity in the Catalog', + attributes: { + destructive: false, + readOnly: false, + idempotent: false, + }, + description: `Registers one or more entities in the Backstage catalog by creating a Location entity that points to a remote catalog-info.yaml file. + +This action is similar to the "Register existing component" flow in the Backstage UI, where you provide a URL to a catalog-info.yaml file describing catalog entities such as Components, Systems, Resources, APIs, Users, and Groups. The action will create a new Location entity that references the provided file; all entities defined within that file will be imported into the catalog. + +A unique identifier (locationId) will be returned for the newly created Location. You can use this identifier in the future to unregister or delete the Location and all entities it owns. +`, + schema: { + input: z => + z.object({ + locationUrl: z + .string() + .describe( + `URL reference to the catalog-info.yaml file that describes the entity to register. For example: https://github.com/backstage/demo/blob/master/catalog-info.yaml`, + ), + }), + output: z => + z.object({ + locationId: z + .string() + .describe('The ID of the entity that was registered'), + }), + }, + action: async ({ input, credentials }) => { + if (!isValidUrl(input.locationUrl)) { + throw new InputError(`${input.locationUrl} is an invalid URL`); + } + + const result = await catalog.addLocation( + { + type: 'url', + target: input.locationUrl, + }, + { + credentials, + }, + ); + + return { + output: { + locationId: result.location.id, + }, + }; + }, + }); +}; diff --git a/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.test.ts b/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.test.ts new file mode 100644 index 0000000000..492a427630 --- /dev/null +++ b/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.test.ts @@ -0,0 +1,274 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createUnregisterCatalogEntitiesAction } from './createUnregisterCatalogEntitiesAction'; +import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; + +describe('createUnregisterCatalogEntitiesAction', () => { + describe('with locationId', () => { + it('should successfully unregister a catalog location with a valid locationId', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + mockCatalog.removeLocationById = jest.fn().mockResolvedValue(undefined); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + const result = await mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { type: { locationId: 'test-location-id-1234' } }, + }); + + expect(result.output).toEqual({}); + expect(mockCatalog.removeLocationById).toHaveBeenCalledWith( + 'test-location-id-1234', + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + }); + + it('should throw an error if catalog.removeLocationById throws an error', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const errorMessage = 'Failed to remove location'; + mockCatalog.removeLocationById = jest + .fn() + .mockRejectedValue(new Error(errorMessage)); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { type: { locationId: 'test-location-id-1234' } }, + }), + ).rejects.toThrow(errorMessage); + }); + }); + + describe('with locationUrl', () => { + it('should successfully unregister a catalog location with a valid locationUrl', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const locationUrl = + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml'; + + mockCatalog.getLocations = jest.fn().mockResolvedValue({ + items: [ + { id: 'location-id-1', target: locationUrl }, + { id: 'location-id-2', target: 'https://other-url.com/catalog.yaml' }, + ], + }); + mockCatalog.removeLocationById = jest.fn().mockResolvedValue(undefined); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + const result = await mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { type: { locationUrl } }, + }); + + expect(result.output).toEqual({}); + expect(mockCatalog.getLocations).toHaveBeenCalledWith( + {}, + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + expect(mockCatalog.removeLocationById).toHaveBeenCalledTimes(1); + expect(mockCatalog.removeLocationById).toHaveBeenCalledWith( + 'location-id-1', + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + }); + + it('should match locationUrl case-insensitively', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + mockCatalog.getLocations = jest.fn().mockResolvedValue({ + items: [ + { + id: 'location-id-1', + target: + 'https://github.com/Backstage/Demo/blob/master/catalog-info.yaml', + }, + ], + }); + mockCatalog.removeLocationById = jest.fn().mockResolvedValue(undefined); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + const result = await mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { + type: { + locationUrl: + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml', + }, + }, + }); + + expect(result.output).toEqual({}); + expect(mockCatalog.removeLocationById).toHaveBeenCalledTimes(1); + expect(mockCatalog.removeLocationById).toHaveBeenCalledWith( + 'location-id-1', + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + }); + + it('should unregister multiple locations with the same URL', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const locationUrl = + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml'; + + mockCatalog.getLocations = jest.fn().mockResolvedValue({ + items: [ + { id: 'location-id-1', target: locationUrl }, + { id: 'location-id-2', target: locationUrl }, + ], + }); + mockCatalog.removeLocationById = jest.fn().mockResolvedValue(undefined); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + const result = await mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { type: { locationUrl } }, + }); + + expect(result.output).toEqual({}); + expect(mockCatalog.removeLocationById).toHaveBeenCalledTimes(2); + expect(mockCatalog.removeLocationById).toHaveBeenNthCalledWith( + 1, + 'location-id-1', + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + expect(mockCatalog.removeLocationById).toHaveBeenNthCalledWith( + 2, + 'location-id-2', + expect.objectContaining({ + credentials: expect.any(Object), + }), + ); + }); + + it('should throw NotFoundError if no location matches the URL', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + mockCatalog.getLocations = jest.fn().mockResolvedValue({ + items: [ + { id: 'location-id-1', target: 'https://other-url.com/catalog.yaml' }, + ], + }); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { + type: { + locationUrl: + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml', + }, + }, + }), + ).rejects.toThrow(/NotFoundError/); + }); + + it('should throw NotFoundError with descriptive message when location not found', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const locationUrl = + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml'; + + mockCatalog.getLocations = jest.fn().mockResolvedValue({ + items: [], + }); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { type: { locationUrl } }, + }), + ).rejects.toThrow(`Location with URL ${locationUrl} not found`); + }); + + it('should throw an error if catalog.getLocations throws an error', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const mockCatalog = catalogServiceMock(); + + const errorMessage = 'Failed to get locations'; + mockCatalog.getLocations = jest + .fn() + .mockRejectedValue(new Error(errorMessage)); + + createUnregisterCatalogEntitiesAction({ + catalog: mockCatalog, + actionsRegistry: mockActionsRegistry, + }); + + await expect( + mockActionsRegistry.invoke({ + id: 'test:unregister-entity', + input: { + type: { + locationUrl: + 'https://github.com/backstage/demo/blob/master/catalog-info.yaml', + }, + }, + }), + ).rejects.toThrow(errorMessage); + }); + }); +}); diff --git a/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.ts b/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.ts new file mode 100644 index 0000000000..542fc79ac5 --- /dev/null +++ b/plugins/catalog-backend/src/actions/createUnregisterCatalogEntitiesAction.ts @@ -0,0 +1,102 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; +import { NotFoundError } from '@backstage/errors'; +import { CatalogService } from '@backstage/plugin-catalog-node'; + +export const createUnregisterCatalogEntitiesAction = ({ + catalog, + actionsRegistry, +}: { + catalog: CatalogService; + actionsRegistry: ActionsRegistryService; +}) => { + actionsRegistry.register({ + name: 'unregister-entity', + title: 'Unregister entity from the Catalog', + attributes: { + destructive: true, + readOnly: false, + idempotent: true, + }, + description: `Unregisters a Location entity and all entities it owns from the Backstage catalog. + +This action is similar to the "Unregister location" function in the Backstage UI, where you provide the unique identifier (locationId) of a Location entity. Alternatively, you can provide the URL used to register the location. The action will remove the specified Location from the catalog as well as all entities that were created when the Location was imported. + +Once completed, all entities associated with the Location will be deleted from the catalog. +`, + schema: { + input: z => + z + .object({ + type: z.union([ + z.object({ + locationId: z + .string() + .describe(`Location ID of the Entity to unregister`), + }), + z.object({ + locationUrl: z + .string() + .describe( + `URL of the catalog-info.yaml file to unregister for example: https://github.com/backstage/demo/blob/master/catalog-info.yaml`, + ), + }), + ]), + }) + .describe( + 'The type to the unregister-entity action. Either locationId or locationUrl must be provided.', + ), + output: z => z.object({}), + }, + action: async ({ input: { type }, credentials }) => { + if ('locationId' in type) { + await catalog.removeLocationById(type.locationId, { + credentials, + }); + } else { + const locations = await catalog + .getLocations( + {}, + { + credentials, + }, + ) + .then(response => + response.items.filter( + location => + location.target.toLowerCase() === + type.locationUrl.toLowerCase(), + ), + ); + + if (locations.length === 0) { + throw new NotFoundError( + `Location with URL ${type.locationUrl} not found`, + ); + } + + for (const location of locations) { + await catalog.removeLocationById(location.id, { + credentials, + }); + } + } + + return { output: {} }; + }, + }); +}; diff --git a/plugins/catalog-backend/src/actions/index.ts b/plugins/catalog-backend/src/actions/index.ts index c53f956f62..5940bc32f1 100644 --- a/plugins/catalog-backend/src/actions/index.ts +++ b/plugins/catalog-backend/src/actions/index.ts @@ -17,6 +17,8 @@ import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; import { CatalogService } from '@backstage/plugin-catalog-node'; import { createGetCatalogEntityAction } from './createGetCatalogEntityAction.ts'; import { createValidateEntityAction } from './createValidateEntityAction.ts'; +import { createRegisterCatalogEntitiesAction } from './createRegisterCatalogEntitiesAction.ts'; +import { createUnregisterCatalogEntitiesAction } from './createUnregisterCatalogEntitiesAction.ts'; export const createCatalogActions = (options: { actionsRegistry: ActionsRegistryService; @@ -24,4 +26,6 @@ export const createCatalogActions = (options: { }) => { createGetCatalogEntityAction(options); createValidateEntityAction(options); + createRegisterCatalogEntitiesAction(options); + createUnregisterCatalogEntitiesAction(options); }; diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index e9d00f3451..7012c2e505 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -1577,10 +1577,11 @@ describe('DefaultEntitiesCatalog', () => { totalItems: 0, items: { type: 'raw', - entities: expect.objectContaining({ length: 10 }), + entities: expect.any(Array), }, pageInfo: { nextCursor: expect.anything() }, }); + expect(response.items.entities).toHaveLength(10); response = await catalog.queryEntities({ ...request, cursor: response.pageInfo.nextCursor!, @@ -1589,10 +1590,11 @@ describe('DefaultEntitiesCatalog', () => { totalItems: 0, items: { type: 'raw', - entities: expect.objectContaining({ length: 5 }), + entities: expect.any(Array), }, pageInfo: { prevCursor: expect.anything() }, }); + expect(response.items.entities).toHaveLength(5); }, ); diff --git a/plugins/catalog-backend/src/service/DefaultRefreshService.ts b/plugins/catalog-backend/src/service/DefaultRefreshService.ts index 99b78f900b..45a8f27c6e 100644 --- a/plugins/catalog-backend/src/service/DefaultRefreshService.ts +++ b/plugins/catalog-backend/src/service/DefaultRefreshService.ts @@ -29,20 +29,17 @@ export class DefaultRefreshService implements RefreshService { const { entityRefs } = await this.database.listAncestors(tx, { entityRef: options.entityRef, }); - const locationAncestor = entityRefs.find(ref => + + const locationAncestors = entityRefs.filter(ref => ref.startsWith('location:'), ); // TODO: Refreshes are currently scheduled(as soon as possible) for execution and will therefore happen in the future. // There's room for improvements here where the refresh could potentially hang or return an ID so that the user can check progress. - if (locationAncestor) { - await this.database.refresh(tx, { - entityRef: locationAncestor, - }); + for (const locationAncestor of locationAncestors) { + await this.database.refresh(tx, { entityRef: locationAncestor }); } - await this.database.refresh(tx, { - entityRef: options.entityRef, - }); + await this.database.refresh(tx, { entityRef: options.entityRef }); }); } } diff --git a/plugins/catalog-backend/src/service/response/write.test.ts b/plugins/catalog-backend/src/service/response/write.test.ts index d60d1c3526..25aaa33aa1 100644 --- a/plugins/catalog-backend/src/service/response/write.test.ts +++ b/plugins/catalog-backend/src/service/response/write.test.ts @@ -327,9 +327,10 @@ describe('writeEntitiesResponse', () => { expect(res.header['content-length']).not.toBeDefined(); expect(res.body).toEqual({ page: 1, - items: expect.objectContaining({ length: 300 }), + items: expect.any(Array), totalItems: 1337, }); + expect(res.body.items).toHaveLength(300); }); }); @@ -438,9 +439,10 @@ describe('writeEntitiesResponse', () => { expect(res.header['content-length']).toBeDefined(); expect(res.body).toEqual({ page: 1, - items: expect.objectContaining({ length: 300 }), + items: expect.any(Array), totalItems: 1337, }); + expect(res.body.items).toHaveLength(300); }); }); }); diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 7cb4eb28b4..0aae66c2f6 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-graph +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.5.4 + +### Patch Changes + +- a67c144: Fixed zoom out description (replace `&` with &) +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.5.4-next.1 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index ff97c60d76..4b0f18e73c 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.5.4-next.1", + "version": "0.5.5-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index b549bb0b85..f0d60f857e 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-import +## 0.13.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.13.8 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + ## 0.13.8-next.0 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index f18c00afa2..7a511c5939 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.13.8-next.0", + "version": "0.13.9-next.0", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 018b9e4cee..112e1cfca2 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-catalog-node +## 1.20.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + ## 1.20.1-next.1 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 28ee49c7a0..befa4e9b7f 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.20.1-next.1", + "version": "1.20.1", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 6a033f0865..1d328e42d5 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-react +## 1.21.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-test-utils@0.4.3-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 1.21.4 + +### Patch Changes + +- 6d39141: Fixed an issue where `EntityOwnerPicker` failed to filter options when the input text contained uppercase characters. +- b3c0594: Use a versioned context for `useEntityList`, to better work with mixed `@backstage/plugin-catalog-react` versions. +- c51c901: $contains may have string value in an entity filter. Typescript type and Zod parser were not the same. +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/core-compat-api@0.5.5 + - @backstage/frontend-test-utils@0.4.2 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + ## 1.21.4-next.2 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index ee8e8757f6..98a824068f 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.21.4-next.2", + "version": "1.21.5-next.0", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-react/report-alpha.api.md b/plugins/catalog-react/report-alpha.api.md index 3f2ed575b4..22ac105eeb 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -549,7 +549,7 @@ export type EntityPredicateValue = $in: EntityPredicatePrimitive[]; } | { - $contains: EntityPredicateExpression; + $contains: EntityPredicate; }; // @alpha (undocumented) diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityCardBlueprint.test.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityCardBlueprint.test.tsx index 3c9a020c93..af04673ad1 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityCardBlueprint.test.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityCardBlueprint.test.tsx @@ -60,20 +60,75 @@ describe('EntityCardBlueprint', () => { { "anyOf": [ { - "type": [ - "string", - "number", - "boolean", - ], + "additionalProperties": { + "anyOf": [ + { + "type": [ + "string", + "number", + "boolean", + ], + }, + { + "additionalProperties": false, + "properties": { + "$exists": { + "type": "boolean", + }, + }, + "required": [ + "$exists", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$in": { + "items": { + "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, + "type": "array", + }, + }, + "required": [ + "$in", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$contains": { + "$ref": "#/properties/filter/anyOf/1", + }, + }, + "required": [ + "$contains", + ], + "type": "object", + }, + ], + }, + "propertyNames": { + "pattern": "^(?!\\$).*$", + }, + "type": "object", }, { - "items": { - "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0", + "additionalProperties": { + "not": {}, }, - "type": "array", + "propertyNames": { + "pattern": "^\\$", + }, + "type": "object", }, ], }, + { + "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, { "additionalProperties": false, "properties": { @@ -116,58 +171,6 @@ describe('EntityCardBlueprint', () => { ], "type": "object", }, - { - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/properties/filter/anyOf/1/anyOf/0", - }, - { - "additionalProperties": false, - "properties": { - "$exists": { - "type": "boolean", - }, - }, - "required": [ - "$exists", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$in": { - "items": { - "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0", - }, - "type": "array", - }, - }, - "required": [ - "$in", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$contains": { - "$ref": "#/properties/filter/anyOf/1", - }, - }, - "required": [ - "$contains", - ], - "type": "object", - }, - ], - }, - "propertyNames": { - "pattern": "^(?!\\$).*$", - }, - "type": "object", - }, ], }, ], diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.test.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.test.tsx index 729f15079f..e80834be92 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.test.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityContentBlueprint.test.tsx @@ -62,20 +62,75 @@ describe('EntityContentBlueprint', () => { { "anyOf": [ { - "type": [ - "string", - "number", - "boolean", - ], + "additionalProperties": { + "anyOf": [ + { + "type": [ + "string", + "number", + "boolean", + ], + }, + { + "additionalProperties": false, + "properties": { + "$exists": { + "type": "boolean", + }, + }, + "required": [ + "$exists", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$in": { + "items": { + "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, + "type": "array", + }, + }, + "required": [ + "$in", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$contains": { + "$ref": "#/properties/filter/anyOf/1", + }, + }, + "required": [ + "$contains", + ], + "type": "object", + }, + ], + }, + "propertyNames": { + "pattern": "^(?!\\$).*$", + }, + "type": "object", }, { - "items": { - "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0", + "additionalProperties": { + "not": {}, }, - "type": "array", + "propertyNames": { + "pattern": "^\\$", + }, + "type": "object", }, ], }, + { + "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, { "additionalProperties": false, "properties": { @@ -118,58 +173,6 @@ describe('EntityContentBlueprint', () => { ], "type": "object", }, - { - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/properties/filter/anyOf/1/anyOf/0", - }, - { - "additionalProperties": false, - "properties": { - "$exists": { - "type": "boolean", - }, - }, - "required": [ - "$exists", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$in": { - "items": { - "$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0", - }, - "type": "array", - }, - }, - "required": [ - "$in", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$contains": { - "$ref": "#/properties/filter/anyOf/1", - }, - }, - "required": [ - "$contains", - ], - "type": "object", - }, - ], - }, - "propertyNames": { - "pattern": "^(?!\\$).*$", - }, - "type": "object", - }, ], }, ], diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.test.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.test.tsx index 55598f5de1..d92fcc1863 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.test.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityContextMenuItemBlueprint.test.tsx @@ -73,20 +73,75 @@ describe('EntityContextMenuItemBlueprint', () => { { "anyOf": [ { - "type": [ - "string", - "number", - "boolean", - ], + "additionalProperties": { + "anyOf": [ + { + "type": [ + "string", + "number", + "boolean", + ], + }, + { + "additionalProperties": false, + "properties": { + "$exists": { + "type": "boolean", + }, + }, + "required": [ + "$exists", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$in": { + "items": { + "$ref": "#/properties/filter/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, + "type": "array", + }, + }, + "required": [ + "$in", + ], + "type": "object", + }, + { + "additionalProperties": false, + "properties": { + "$contains": { + "$ref": "#/properties/filter", + }, + }, + "required": [ + "$contains", + ], + "type": "object", + }, + ], + }, + "propertyNames": { + "pattern": "^(?!\\$).*$", + }, + "type": "object", }, { - "items": { - "$ref": "#/properties/filter/anyOf/0/anyOf/0", + "additionalProperties": { + "not": {}, }, - "type": "array", + "propertyNames": { + "pattern": "^\\$", + }, + "type": "object", }, ], }, + { + "$ref": "#/properties/filter/anyOf/0/anyOf/0/additionalProperties/anyOf/0", + }, { "additionalProperties": false, "properties": { @@ -129,58 +184,6 @@ describe('EntityContextMenuItemBlueprint', () => { ], "type": "object", }, - { - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/properties/filter/anyOf/0", - }, - { - "additionalProperties": false, - "properties": { - "$exists": { - "type": "boolean", - }, - }, - "required": [ - "$exists", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$in": { - "items": { - "$ref": "#/properties/filter/anyOf/0/anyOf/0", - }, - "type": "array", - }, - }, - "required": [ - "$in", - ], - "type": "object", - }, - { - "additionalProperties": false, - "properties": { - "$contains": { - "$ref": "#/properties/filter", - }, - }, - "required": [ - "$contains", - ], - "type": "object", - }, - ], - }, - "propertyNames": { - "pattern": "^(?!\\$).*$", - }, - "type": "object", - }, ], }, }, diff --git a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.test.ts b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.test.ts index 4fdf921c1a..3553fa932b 100644 --- a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.test.ts +++ b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.test.ts @@ -16,84 +16,100 @@ import { z } from 'zod'; import { createEntityPredicateSchema } from './createEntityPredicateSchema'; +import { EntityPredicate } from './types'; describe('createEntityPredicateSchema', () => { const schema = createEntityPredicateSchema(z); - it.each([ - 'string', - '', - [], - 1, - { kind: 'component', 'spec.type': 'service' }, - { 'metadata.tags': { $in: ['java'] } }, - { - $all: [ - { 'metadata.tags': { $contains: 'java' } }, - { 'metadata.tags': { $contains: 'spring' } }, - ], - }, - { 'metadata.tags': ['java', 'spring'] }, - { 'metadata.tags': { $in: ['go'] } }, - { 'metadata.tags.0': 'java' }, - { $not: { 'metadata.tags': { $in: ['java'] } } }, - { - $any: [{ kind: 'component', 'spec.type': 'service' }, { kind: 'group' }], - }, - { - relations: { - $contains: { type: 'ownedBy', targetRef: 'group:default/g' }, + describe('valid predicates', () => { + const predicates: EntityPredicate[] = [ + 'string', + '', + 1, + { kind: 'component', 'spec.type': 'service' }, + { 'metadata.tags': { $in: ['java'] } }, + { 'metadata.tags': { $contains: 'java' } }, + { + $all: [ + { 'metadata.tags': { $contains: 'java' } }, + { 'metadata.tags': { $contains: 'spring' } }, + ], }, - }, - { - metadata: { $contains: { name: 'a' } }, - }, - { kind: 'component', 'spec.type': { $in: ['service', 'website'] } }, - { - $any: [ - { - $all: [ - { - kind: 'component', - 'spec.type': { $in: ['service', 'website'] }, - }, - ], + { 'metadata.tags': { $in: ['go'] } }, + { 'metadata.tags.0': 'java' }, + { $not: { 'metadata.tags': { $in: ['java'] } } }, + { + $any: [ + { kind: 'component', 'spec.type': 'service' }, + { kind: 'group' }, + ], + }, + { + relations: { + $contains: { type: 'ownedBy', targetRef: 'group:default/g' }, }, - { $all: [{ kind: 'api', 'spec.type': 'grpc' }] }, - ], - }, - { kind: 'component', 'spec.type': { $in: ['service'] } }, - { 'spec.owner': { $exists: true } }, - { 'spec.owner': { $exists: false } }, - { 'spec.type': 'service' }, - { $not: { 'spec.type': 'service' } }, - { - kind: 'component', - 'metadata.annotations.github.com/repo': { $exists: true }, - }, - { $all: [{ x: { $exists: true } }] }, - { $any: [{ x: { $exists: true } }] }, - { $not: { x: { $exists: true } } }, - { $not: { $all: [{ x: { $exists: true } }] } }, - ])('should accept valid predicate %j', predicate => { - expect(schema.parse(predicate)).toEqual(predicate); + }, + { + metadata: { $contains: { name: 'a' } }, + }, + { kind: 'component', 'spec.type': { $in: ['service', 'website'] } }, + { + $any: [ + { + $all: [ + { + kind: 'component', + 'spec.type': { $in: ['service', 'website'] }, + }, + ], + }, + { $all: [{ kind: 'api', 'spec.type': 'grpc' }] }, + ], + }, + { kind: 'component', 'spec.type': { $in: ['service'] } }, + { 'spec.owner': { $exists: true } }, + { 'spec.owner': { $exists: false } }, + { 'spec.type': 'service' }, + { $not: { 'spec.type': 'service' } }, + { + kind: 'component', + 'metadata.annotations.github.com/repo': { $exists: true }, + }, + { $all: [{ x: { $exists: true } }] }, + { $any: [{ x: { $exists: true } }] }, + { $not: { x: { $exists: true } } }, + { $not: { $all: [{ x: { $exists: true } }] } }, + ]; + + it.each(predicates)('should accept valid predicate %j', predicate => { + expect(schema.parse(predicate)).toEqual(predicate); + }); }); - it.each([ - { kind: { 1: 'foo' } }, - { kind: { foo: 'bar' } }, - { kind: { $unknown: 'foo' } }, - { kind: { $in: 'foo' } }, - { kind: { $in: [{ x: 'foo' }] } }, - { kind: { $in: [{ x: 'foo' }] } }, - { 'spec.type': null }, - { $all: [{ x: { $unknown: true } }] }, - { $any: [{ x: { $unknown: true } }] }, - { $not: { x: { $unknown: true } } }, - { $not: { $all: [{ x: { $unknown: true } }] } }, - { $unknown: 'foo' }, - ])('should reject invalid predicate %j', predicate => { - const result = schema.safeParse(predicate); - expect(result.success).toBe(false); + describe('invalid predicates', () => { + const predicates: Array< + Exclude + > = [ + [], + ['foo', 'bar'], + { kind: { 1: 'foo' } }, + { kind: { foo: 'bar' } }, + { kind: { $unknown: 'foo' } }, + { kind: { $in: 'foo' } }, + { kind: { $in: [{ x: 'foo' }] } }, + { kind: { $in: [{ x: 'foo' }] } }, + { 'spec.type': null }, + { $all: [{ x: { $unknown: true } }] }, + { $any: [{ x: { $unknown: true } }] }, + { $not: { x: { $unknown: true } } }, + { $not: { $all: [{ x: { $unknown: true } }] } }, + { $unknown: 'foo' }, + { 'metadata.tags': ['foo', 'bar'] }, + ]; + + it.each(predicates)('should reject invalid predicate %j', predicate => { + const result = schema.safeParse(predicate); + expect(result.success).toBe(false); + }); }); }); diff --git a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts index cfd2e451df..3e31ec4d35 100644 --- a/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts +++ b/plugins/catalog-react/src/alpha/predicates/createEntityPredicateSchema.ts @@ -14,33 +14,44 @@ * limitations under the License. */ -import { EntityPredicate, EntityPredicateValue } from './types'; +import { + EntityPredicate, + EntityPredicateExpression, + EntityPredicatePrimitive, + EntityPredicateValue, +} from './types'; import type { z as zImpl, ZodType } from 'zod'; /** @internal */ export function createEntityPredicateSchema(z: typeof zImpl) { - const primitiveSchema = z.union([z.string(), z.number(), z.boolean()]); - - const comparableValueSchema = z.union([ - primitiveSchema, - z.array(primitiveSchema), - ]); + const primitiveSchema = z.union([ + z.string(), + z.number(), + z.boolean(), + ]) as ZodType; // eslint-disable-next-line prefer-const let valuePredicateSchema: ZodType; + const expressionSchema = z.lazy(() => + z.union([ + z.record(z.string().regex(/^(?!\$).*$/), valuePredicateSchema), + z.record(z.string().regex(/^\$/), z.never()), + ]), + ) as ZodType; + const predicateSchema = z.lazy(() => z.union([ - comparableValueSchema, + expressionSchema, + primitiveSchema, z.object({ $all: z.array(predicateSchema) }), z.object({ $any: z.array(predicateSchema) }), z.object({ $not: predicateSchema }), - z.record(z.string().regex(/^(?!\$).*$/), valuePredicateSchema), ]), ) as ZodType; valuePredicateSchema = z.union([ - comparableValueSchema, + primitiveSchema, z.object({ $exists: z.boolean() }), z.object({ $in: z.array(primitiveSchema) }), z.object({ $contains: predicateSchema }), diff --git a/plugins/catalog-react/src/alpha/predicates/types.ts b/plugins/catalog-react/src/alpha/predicates/types.ts index a4a2e9199f..f19026c01b 100644 --- a/plugins/catalog-react/src/alpha/predicates/types.ts +++ b/plugins/catalog-react/src/alpha/predicates/types.ts @@ -34,7 +34,7 @@ export type EntityPredicateValue = | EntityPredicatePrimitive | { $exists: boolean } | { $in: EntityPredicatePrimitive[] } - | { $contains: EntityPredicateExpression }; + | { $contains: EntityPredicate }; /** @alpha */ export type EntityPredicatePrimitive = string | number | boolean; diff --git a/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.test.tsx b/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.test.tsx index 0ba231b72a..07eaa479fd 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.test.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.test.tsx @@ -68,15 +68,15 @@ describe('useAllEntitiesCount', () => { ), }); - await waitFor(() => + await waitFor(() => { expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ filter: { 'relations.ownedBy': ['user:default/owner'], }, limit: 0, - }), - ); - expect(result.current).toEqual({ count: 10, loading: false }); + }); + expect(result.current).toEqual({ count: 10, loading: false }); + }); }); it(`shouldn't invoke the endpoint at startup, when filters are missing`, async () => { diff --git a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md index 67dfa74dae..2a9cca8511 100644 --- a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-unprocessed-entities-common +## 0.0.12 + +### Patch Changes + +- df4d646: Moved types, API and client to the common package, allowing both frontend and + backend plugins to use the `CatalogUnprocessedEntitiesClient`. + + The following types, clients and interfaces have been deprecated and should be + imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead: + `CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`, + `UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`. + + All those types, clients and interfaces are re-exported temporarily in the + `@backstage/plugin-catalog-unprocessed-entities` package until cleaned up. + ## 0.0.12-next.0 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities-common/package.json b/plugins/catalog-unprocessed-entities-common/package.json index c20e1c142a..58423cad91 100644 --- a/plugins/catalog-unprocessed-entities-common/package.json +++ b/plugins/catalog-unprocessed-entities-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities-common", - "version": "0.0.12-next.0", + "version": "0.0.12", "description": "Common functionalities for the catalog-unprocessed-entities plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index b48f12b4dd..47be6beb8b 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.24 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- df4d646: Moved types, API and client to the common package, allowing both frontend and + backend plugins to use the `CatalogUnprocessedEntitiesClient`. + + The following types, clients and interfaces have been deprecated and should be + imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead: + `CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`, + `UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`. + + All those types, clients and interfaces are re-exported temporarily in the + `@backstage/plugin-catalog-unprocessed-entities` package until cleaned up. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.12 + ## 0.2.24-next.1 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 2b6d876226..016018b93f 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.2.24-next.1", + "version": "0.2.24", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 9215ba537c..cd9e492610 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-catalog +## 1.32.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## 1.32.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 91f5ed8: Fixed `catalogAboutEntityCard` to filter icon links before calling useProps(), preventing side effects from hooks in filtered-out links +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/core-compat-api@0.5.5 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-techdocs-react@1.3.6 + ## 1.32.1-next.1 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index c0c851469a..9016bf83a1 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.32.1-next.1", + "version": "1.32.2-next.0", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog/src/alpha/pages.test.tsx b/plugins/catalog/src/alpha/pages.test.tsx index cc83b9168b..0b35e63979 100644 --- a/plugins/catalog/src/alpha/pages.test.tsx +++ b/plugins/catalog/src/alpha/pages.test.tsx @@ -721,18 +721,27 @@ describe('Entity page', () => { ); const { disabled } = params.useProps(); - await waitFor(async () => { - await userEvent.click(screen.getByTestId('menu-button')); - expect(screen.getByText('Test Title')).toBeInTheDocument(); - expect(screen.getByText('Test Icon')).toBeInTheDocument(); - const listItem = screen.getByText('Test Title').closest('li'); - expect(listItem).toHaveAttribute('aria-disabled', disabled.toString()); - if (!disabled) { - await userEvent.click(screen.getByText('Test Title')); - } - expect(onClickMock).toHaveBeenCalledTimes(disabled ? 0 : 1); - }); + // Wait for entity to load first + await waitFor(() => + expect(screen.getByText(/artist-lookup/)).toBeInTheDocument(), + ); + + await userEvent.click(screen.getByTestId('menu-button')); + + // Wait for menu to open + await waitFor(() => + expect(screen.getByText('Test Title')).toBeInTheDocument(), + ); + + expect(screen.getByText('Test Icon')).toBeInTheDocument(); + const listItem = screen.getByText('Test Title').closest('li'); + expect(listItem).toHaveAttribute('aria-disabled', disabled.toString()); + if (!disabled) { + await userEvent.click(screen.getByText('Test Title')); + } + + expect(onClickMock).toHaveBeenCalledTimes(disabled ? 0 : 1); }); it.each([ diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 2dba805a25..1329d91732 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-config-schema +## 0.1.75 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.1.75-next.0 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 1018d9baab..46b051aca6 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.75-next.0", + "version": "0.1.75", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 8c3d629ba4..0dc5503884 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-devtools-backend +## 0.5.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config@1.3.6 + - @backstage/config-loader@1.10.7 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-devtools-common@0.1.20 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + +## 0.5.12 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/cli-common@0.1.16 + - @backstage/config-loader@1.10.7 + - @backstage/plugin-devtools-common@0.1.20 + ## 0.5.12-next.1 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 0102e18257..23c41c6d9d 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.5.12-next.1", + "version": "0.5.13-next.0", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 6eeced0711..baa07b0bb7 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-devtools-common +## 0.1.20 + +### Patch Changes + +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin + ## 0.1.19 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index cc03b91103..21d99333c2 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-common", - "version": "0.1.19", + "version": "0.1.20", "description": "Common functionalities for the devtools plugin", "backstage": { "role": "common-library", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 4bc547cbbe..acaf74091e 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-devtools +## 0.1.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.5.6-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.1.34 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 291bf9d: Added scheduled tasks UI feature for the DevTools plugin +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-devtools-common@0.1.20 + - @backstage/core-compat-api@0.5.5 + - @backstage/plugin-permission-react@0.4.39 + ## 0.1.34-next.0 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index d79a4a4bff..2a057e800b 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.34-next.0", + "version": "0.1.35-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index a59e6f1e02..23eeee8fcd 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.4.18 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.18-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 1c508d16ff..dbcca544dd 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.4.18-next.1", + "version": "0.4.18", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 37f58155ab..07db604cc3 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.27-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 867e125f2c..e0af5fda5c 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.2.27-next.1", + "version": "0.2.27", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 3a4f98290f..4acd9bf71d 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.27-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 99e9b66935..cca7630e0d 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.2.27-next.1", + "version": "0.2.27", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md index a268c0c0f1..3d602aebb2 100644 --- a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-server +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-server/package.json b/plugins/events-backend-module-bitbucket-server/package.json index 30bc81d2a7..452b3262a0 100644 --- a/plugins/events-backend-module-bitbucket-server/package.json +++ b/plugins/events-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-server", - "version": "0.1.8-next.1", + "version": "0.1.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 892ddfe843..4c0750ad67 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.27-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index c4e83055c6..3d79d8805c 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.2.27-next.1", + "version": "0.2.27", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 987cea1db4..8980120bab 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-events-backend-module-github +## 0.4.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.7-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index 34300e178f..02d50f8e0d 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.4.7-next.1", + "version": "0.4.8-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index e63ac21b11..b97a60c140 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.3.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.8-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index b328f09bb8..e0d509fa3b 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.3.8-next.1", + "version": "0.3.8", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-google-pubsub/CHANGELOG.md b/plugins/events-backend-module-google-pubsub/CHANGELOG.md index 624d76c284..d07530ac08 100644 --- a/plugins/events-backend-module-google-pubsub/CHANGELOG.md +++ b/plugins/events-backend-module-google-pubsub/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-google-pubsub +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.7-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-google-pubsub/package.json b/plugins/events-backend-module-google-pubsub/package.json index 9f06b4db63..d5a97f3223 100644 --- a/plugins/events-backend-module-google-pubsub/package.json +++ b/plugins/events-backend-module-google-pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-google-pubsub", - "version": "0.1.7-next.1", + "version": "0.1.7", "description": "The google-pubsub backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-module-kafka/CHANGELOG.md b/plugins/events-backend-module-kafka/CHANGELOG.md index a74c0aa187..3edfcf9487 100644 --- a/plugins/events-backend-module-kafka/CHANGELOG.md +++ b/plugins/events-backend-module-kafka/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-events-backend-module-kafka +## 0.2.0 + +### Minor Changes + +- 2c74ea9: Added support for multiple named instances in `kafkaConsumingEventPublisher` configuration. The previous single configuration format is still supported for backward compatibility. +- 2c74ea9: Added `KafkaPublishingEventConsumer` to support sending Backstage events to Kafka topics. + + This addition enables Backstage to publish events to external Kafka systems, complementing the existing ability to receive events from Kafka. This allows for better integration with external systems that rely on Kafka for event streaming. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.6-next.1 ### Patch Changes diff --git a/plugins/events-backend-module-kafka/package.json b/plugins/events-backend-module-kafka/package.json index 48ba679986..d6e7b1ac0e 100644 --- a/plugins/events-backend-module-kafka/package.json +++ b/plugins/events-backend-module-kafka/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-kafka", - "version": "0.1.6-next.1", + "version": "0.2.0", "description": "The kafka backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 91ac1aa27e..a9233cc14a 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.51 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + ## 0.1.51-next.0 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 64c0ee9925..814fb23241 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.51-next.0", + "version": "0.1.51", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 6023351a5d..d504f3fdaf 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-events-backend +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.18 + +## 0.5.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.5.9-next.1 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index fce8d33ddf..5089655b6e 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.5.9-next.1", + "version": "0.5.10-next.0", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 02eb3b07ba..d748102a2b 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-node +## 0.4.18 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 0.4.18-next.1 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 9e4ad5889f..c8dc226198 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.4.18-next.1", + "version": "0.4.18", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", @@ -65,7 +65,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "msw": "^1.0.0" + "msw": "^2.0.0" }, "configSchema": "config.d.ts" } diff --git a/plugins/events-node/src/api/DefaultEventsService.test.ts b/plugins/events-node/src/api/DefaultEventsService.test.ts index 13a6a68fa4..a62cc24f14 100644 --- a/plugins/events-node/src/api/DefaultEventsService.test.ts +++ b/plugins/events-node/src/api/DefaultEventsService.test.ts @@ -17,7 +17,7 @@ import { DefaultEventsService } from './DefaultEventsService'; import { EventParams } from './EventParams'; import { EVENTS_NOTIFY_TIMEOUT_HEADER } from './EventsService'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { mockServices, @@ -129,18 +129,18 @@ describe('DefaultEventsService', () => { }); mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => res(ctx.status(200)), + () => new HttpResponse(null, { status: 200 }), ), - rest.get( + http.get( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester/events', - (_req, res, ctx) => - res( - ctx.status(200), - ctx.json({ + () => + HttpResponse.json( + { events: [{ topic: 'test', payload: { foo: 'bar' } }], - }), + }, + { status: 200 }, ), ), ); @@ -180,38 +180,36 @@ describe('DefaultEventsService', () => { }); mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => res(ctx.status(200)), + () => new HttpResponse(null, { status: 200 }), ), // The first and third calls result in a blocking 202 that is resolved after 100ms // The second and fourth calls result in a 200 with an event // The fifth call blocks until the end of the test // No more than 5 calls should be made - rest.get( + http.get( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester/events', - (_req, res, ctx) => { + () => { callCount += 1; if (callCount === 1 || callCount === 3) { - return res( - ctx.status(202), - ctx.body( - new ReadableStream({ - start(controller) { - setTimeout(() => controller.close(), 100); - }, - }), - ), + return new HttpResponse( + new ReadableStream({ + start(controller) { + setTimeout(() => controller.close(), 100); + }, + }), + { status: 202 }, ); } else if (callCount === 2 || callCount === 4) { - return res( - ctx.status(200), - ctx.json({ + return HttpResponse.json( + { events: [{ topic: 'test', payload: { callCount } }], - }), + }, + { status: 200 }, ); } else if (callCount === 5) { - return res(ctx.status(202), ctx.body(blockingStream)); + return new HttpResponse(blockingStream, { status: 202 }); } throw new Error(`events endpoint called too many times`); }, @@ -268,45 +266,42 @@ describe('DefaultEventsService', () => { }); mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => res(ctx.status(200)), + () => new HttpResponse(null, { status: 200 }), ), // The first and third calls result in a blocking 202 that is resolved after 100ms // The second and fourth calls result in a 200 with an event // The fifth call blocks until the end of the test // No more than 5 calls should be made - rest.get( + http.get( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester/events', - (_req, res, ctx) => { + () => { callCount += 1; if (callCount === 1 || callCount === 3) { - return res( - ctx.status(202), - ctx.body( - new ReadableStream({ - start(controller) { - setTimeout(() => controller.close(), 100); - }, - }), - ), + return new HttpResponse( + new ReadableStream({ + start(controller) { + setTimeout(() => controller.close(), 100); + }, + }), + { status: 202 }, ); } else if (callCount === 2 || callCount === 4) { - return res( - ctx.status(200), - ctx.json({ + return HttpResponse.json( + { events: [{ topic: 'test', payload: { callCount } }], - }), + }, + { status: 200 }, ); } else if (callCount === 5) { // 5th call has a timeout header so polling should proceed to the next call - return res( - ctx.set(EVENTS_NOTIFY_TIMEOUT_HEADER, '100'), - ctx.status(202), - ctx.body(blockingStream), - ); + return new HttpResponse(blockingStream, { + status: 202, + headers: { [EVENTS_NOTIFY_TIMEOUT_HEADER]: '100' }, + }); } else if (callCount === 6) { - return res(ctx.status(202), ctx.body(blockingStream)); + return new HttpResponse(blockingStream, { status: 202 }); } throw new Error(`events endpoint called too many times`); }, @@ -358,11 +353,11 @@ describe('DefaultEventsService', () => { let calledApi = false; mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => { + () => { calledApi = true; - res(ctx.status(200)); + return new HttpResponse(null, { status: 200 }); }, ), ); @@ -393,9 +388,9 @@ describe('DefaultEventsService', () => { }); mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -432,9 +427,9 @@ describe('DefaultEventsService', () => { }); mswServer.use( - rest.put( + http.put( 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', - (_req, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index c73992d349..4d7a89509f 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-backend +## 1.0.46 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 1.0.46-next.1 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index b5dabde1e7..108655947a 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.46-next.1", + "version": "1.0.46", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index d2db721b76..798fa8df02 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.46 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 1.0.46-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 7867750b3a..ad138b4713 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.46-next.0", + "version": "1.0.46", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/gateway-backend/CHANGELOG.md b/plugins/gateway-backend/CHANGELOG.md index cdda4ba64f..5e6c6254d9 100644 --- a/plugins/gateway-backend/CHANGELOG.md +++ b/plugins/gateway-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gateway-backend +## 1.1.1 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 7e860dd: Updated dependency `eventsource` to `^4.0.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 1.1.1-next.1 ### Patch Changes diff --git a/plugins/gateway-backend/package.json b/plugins/gateway-backend/package.json index c70ad78a09..4cc39faf7b 100644 --- a/plugins/gateway-backend/package.json +++ b/plugins/gateway-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gateway-backend", - "version": "1.1.1-next.1", + "version": "1.1.1", "backstage": { "role": "backend-plugin", "pluginId": "gateway", @@ -46,7 +46,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/express": "^4.17.6", - "eventsource": "^3.0.6", + "eventsource": "^4.0.0", "wait-for-expect": "^3.0.2" } } diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 48857f74d4..81c9fbc1be 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-home-react +## 0.1.33 + +### Patch Changes + +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.1.33-next.1 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 7eec7e630c..8f69f7eab7 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.33-next.1", + "version": "0.1.33", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index e5f243bf4a..c4e531ee28 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-home +## 0.8.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.8.15 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-home-react@0.1.33 + - @backstage/theme@0.7.1 + ## 0.8.15-next.1 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 36ff21769a..7b9a891644 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.8.15-next.1", + "version": "0.8.16-next.0", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 1f54767a13..a8ebfa6f8f 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.21.0 + +### Minor Changes + +- 7f9846f: Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- fb029b6: Updated luxon types +- e9589d9: Replace `@aws-sdk/signature-v4` with `@smithy/signature-v4`, + as stated in the [package documentation](https://www.npmjs.com/package/@aws-sdk/signature-v4?activeTab=readme) +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas +- Updated dependencies + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-node@0.4.0 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.21.0-next.2 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 79ef93c0a2..2aac84c616 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.21.0-next.2", + "version": "0.21.0", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-backend/src/cluster-locator/__snapshots__/CatalogClusterLocator.test.ts.snap b/plugins/kubernetes-backend/src/cluster-locator/__snapshots__/CatalogClusterLocator.test.ts.snap index f8b3e71515..64526faacb 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/__snapshots__/CatalogClusterLocator.test.ts.snap +++ b/plugins/kubernetes-backend/src/cluster-locator/__snapshots__/CatalogClusterLocator.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CatalogClusterLocator returns the aws cluster details provided by annotations 1`] = ` { diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 7136e5d3e1..a12471753e 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## 0.0.32 + +### Patch Changes + +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.14 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + ## 0.0.32-next.2 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 18897c6ba1..a190f01da5 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.32-next.2", + "version": "0.0.33-next.0", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 902a7e1f1d..de8f93897c 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-kubernetes-common +## 0.9.9 + +### Patch Changes + +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas + ## 0.9.9-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 512ed1f7eb..db2d9c2837 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-common", - "version": "0.9.9-next.0", + "version": "0.9.9", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 79f922532f..a0fad104d8 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-node +## 0.4.0 + +### Minor Changes + +- 7f9846f: Add possibility to extends Kubernetes REST API. Add fetcher to parameters for custom objects provider + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-kubernetes-common@0.9.9 + ## 0.4.0-next.2 ### Minor Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 5dfc49b66c..8778449eaa 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.4.0-next.2", + "version": "0.4.0", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index b260e25475..d1bb328016 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-react +## 0.5.14 + +### Patch Changes + +- f966a85: Enabled a pod terminal at GKE +- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas +- f15d5f1: add missing i18n support for kubernetes and kubernetes-react +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + ## 0.5.14-next.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index da1b5f6e3e..a634594e60 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.5.14-next.1", + "version": "0.5.14", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", @@ -84,7 +84,7 @@ "@testing-library/react": "^16.0.0", "@types/react": "^18.0.0", "jest-websocket-mock": "^2.5.0", - "msw": "^1.3.1", + "msw": "^2.0.0", "react": "^18.0.2", "react-dom": "^18.0.2", "react-router-dom": "^6.3.0" diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index 4698f01dfe..3e8b7aa437 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -16,7 +16,7 @@ import { KubernetesAuthProvidersApi } from '../kubernetes-auth-provider'; import { KubernetesBackendClient } from './KubernetesBackendClient'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { UrlPatternDiscovery } from '@backstage/core-app-api'; import { setupServer } from 'msw/node'; import { MockFetchApi, registerMswTestHooks } from '@backstage/test-utils'; @@ -89,23 +89,24 @@ describe('KubernetesBackendClient', () => { it('hits the /clusters API', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.get('http://localhost:1234/api/kubernetes/clusters', (_, res, ctx) => - res(ctx.json({ items: [{ name: 'cluster-a', authProvider: 'aws' }] })), + http.get('http://localhost:1234/api/kubernetes/clusters', () => + HttpResponse.json({ + items: [{ name: 'cluster-a', authProvider: 'aws' }], + }), ), ); const clusters = await backendClient.getClusters(); - expect(clusters).toStrictEqual([ - { name: 'cluster-a', authProvider: 'aws' }, - ]); + expect(clusters).toEqual([{ name: 'cluster-a', authProvider: 'aws' }]); }); it('/clusters API throws a 404 Error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.get('http://localhost:1234/api/kubernetes/clusters', (_, res, ctx) => - res(ctx.status(404)), + http.get( + 'http://localhost:1234/api/kubernetes/clusters', + () => new HttpResponse(null, { status: 404 }), ), ); @@ -117,8 +118,9 @@ describe('KubernetesBackendClient', () => { it('/clusters API throws a 500 Error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.get('http://localhost:1234/api/kubernetes/clusters', (_, res, ctx) => - res(ctx.status(500)), + http.get( + 'http://localhost:1234/api/kubernetes/clusters', + () => new HttpResponse(null, { status: 500 }), ), ); @@ -130,9 +132,9 @@ describe('KubernetesBackendClient', () => { it('hits the /resources/custom/query API', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/custom/query', - (_, res, ctx) => res(ctx.json(mockResponse)), + () => HttpResponse.json(mockResponse), ), ); @@ -157,15 +159,15 @@ describe('KubernetesBackendClient', () => { const customObject: ObjectsByEntityResponse = await backendClient.getCustomObjectsByEntity(request); - expect(customObject).toStrictEqual(mockResponse); + expect(customObject).toEqual(mockResponse); }); it('/resources/custom/query API throws a 404 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/custom/query', - (_, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -197,9 +199,9 @@ describe('KubernetesBackendClient', () => { it('/resources/custom/query API throws a 500 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/custom/query', - (_, res, ctx) => res(ctx.status(500)), + () => new HttpResponse(null, { status: 500 }), ), ); @@ -231,9 +233,8 @@ describe('KubernetesBackendClient', () => { it('hits the /services/{entityName} API', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( - 'http://localhost:1234/api/kubernetes/services/test-name', - (_, res, ctx) => res(ctx.json(mockResponse)), + http.post('http://localhost:1234/api/kubernetes/services/test-name', () => + HttpResponse.json(mockResponse), ), ); @@ -250,15 +251,15 @@ describe('KubernetesBackendClient', () => { const entityObject: ObjectsByEntityResponse = await backendClient.getObjectsByEntity(request); - expect(entityObject).toStrictEqual(mockResponse); + expect(entityObject).toEqual(mockResponse); }); it('services/{entityName} API throws a 404 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/services/test-name', - (_, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -282,9 +283,9 @@ describe('KubernetesBackendClient', () => { it('services/{entityName} API throws a 500 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/services/test-name', - (_, res, ctx) => res(ctx.status(500)), + () => new HttpResponse(null, { status: 500 }), ), ); @@ -308,9 +309,9 @@ describe('KubernetesBackendClient', () => { it('hits the /resources/workloads/query API', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/workloads/query', - (_, res, ctx) => res(ctx.json(mockResponse)), + () => HttpResponse.json(mockResponse), ), ); @@ -328,15 +329,15 @@ describe('KubernetesBackendClient', () => { const response: ObjectsByEntityResponse = await backendClient.getWorkloadsByEntity(request); - expect(response).toStrictEqual(mockResponse); + expect(response).toEqual(mockResponse); }); it('/resources/workloads/query API throws a 404 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/workloads/query', - (_, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -361,9 +362,9 @@ describe('KubernetesBackendClient', () => { it('/resources/workloads/query API throws a 500 error', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.post( + http.post( 'http://localhost:1234/api/kubernetes/resources/workloads/query', - (_, res, ctx) => res(ctx.status(500)), + () => new HttpResponse(null, { status: 500 }), ), ); @@ -388,12 +389,10 @@ describe('KubernetesBackendClient', () => { describe('proxy', () => { beforeEach(() => { worker.use( - rest.get( - 'http://localhost:1234/api/kubernetes/clusters', - (_, res, ctx) => - res( - ctx.json({ items: [{ name: 'cluster-a', authProvider: 'aws' }] }), - ), + http.get('http://localhost:1234/api/kubernetes/clusters', () => + HttpResponse.json({ + items: [{ name: 'cluster-a', authProvider: 'aws' }], + }), ), ); identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); @@ -401,20 +400,16 @@ describe('KubernetesBackendClient', () => { it('hits the /proxy API with oidc as protocol and okta as auth provider', async () => { worker.use( - rest.get( - 'http://localhost:1234/api/kubernetes/clusters', - (_, res, ctx) => - res( - ctx.json({ - items: [ - { - name: 'cluster-a', - authProvider: 'oidc', - oidcTokenProvider: 'okta', - }, - ], - }), - ), + http.get('http://localhost:1234/api/kubernetes/clusters', () => + HttpResponse.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'oidc', + oidcTokenProvider: 'okta', + }, + ], + }), ), ); kubernetesAuthProvidersApi.getCredentials.mockResolvedValue({ @@ -428,16 +423,14 @@ describe('KubernetesBackendClient', () => { }, }; worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (req, res, ctx) => - res( - req.headers.get( - 'Backstage-Kubernetes-Authorization-oidc-okta', - ) === 'k8-token3' - ? ctx.json(nsResponse) - : ctx.status(403), - ), + ({ request }) => + request.headers.get( + 'Backstage-Kubernetes-Authorization-oidc-okta', + ) === 'k8-token3' + ? HttpResponse.json(nsResponse) + : new HttpResponse(null, { status: 403 }), ), ); @@ -448,7 +441,7 @@ describe('KubernetesBackendClient', () => { const response = await backendClient.proxy(request); - await expect(response.json()).resolves.toStrictEqual(nsResponse); + await expect(response.json()).resolves.toEqual(nsResponse); expect(kubernetesAuthProvidersApi.getCredentials).toHaveBeenCalledWith( 'oidc.okta', ); @@ -457,19 +450,15 @@ describe('KubernetesBackendClient', () => { it('hits the /proxy API with serviceAccount as auth provider', async () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); worker.use( - rest.get( - 'http://localhost:1234/api/kubernetes/clusters', - (_, res, ctx) => - res( - ctx.json({ - items: [ - { - name: 'cluster-a', - authProvider: 'serviceAccount', - }, - ], - }), - ), + http.get('http://localhost:1234/api/kubernetes/clusters', () => + HttpResponse.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'serviceAccount', + }, + ], + }), ), ); @@ -481,14 +470,12 @@ describe('KubernetesBackendClient', () => { }, }; worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (req, res, ctx) => - res( - req.headers.get('Authorization') === 'Bearer idToken' - ? ctx.json(nsResponse) - : ctx.status(403), - ), + ({ request }) => + request.headers.get('Authorization') === 'Bearer idToken' + ? HttpResponse.json(nsResponse) + : new HttpResponse(null, { status: 403 }), ), ); @@ -499,7 +486,7 @@ describe('KubernetesBackendClient', () => { const response = await backendClient.proxy(request); - await expect(response.json()).resolves.toStrictEqual(nsResponse); + await expect(response.json()).resolves.toEqual(nsResponse); expect(kubernetesAuthProvidersApi.getCredentials).toHaveBeenCalledWith( 'serviceAccount', ); @@ -507,24 +494,20 @@ describe('KubernetesBackendClient', () => { it('ignores oidcTokenProvider for non-oidc auth provider', async () => { worker.use( - rest.get( - 'http://localhost:1234/api/kubernetes/clusters', - (_, res, ctx) => - res( - ctx.json({ - items: [ - { - name: 'cluster-a', - authProvider: 'not oidc', - oidcTokenProvider: 'should be ignored', - }, - ], - }), - ), + http.get('http://localhost:1234/api/kubernetes/clusters', () => + HttpResponse.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'not oidc', + oidcTokenProvider: 'should be ignored', + }, + ], + }), ), - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (_, res, ctx) => res(ctx.json([])), + () => HttpResponse.json([]), ), ); @@ -552,15 +535,13 @@ describe('KubernetesBackendClient', () => { }, }; worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (req, res, ctx) => - res( - req.headers.get('Backstage-Kubernetes-Authorization-aws') === - 'k8-token' - ? ctx.json(nsResponse) - : ctx.status(403), - ), + ({ request }) => + request.headers.get('Backstage-Kubernetes-Authorization-aws') === + 'k8-token' + ? HttpResponse.json(nsResponse) + : new HttpResponse(null, { status: 403 }), ), ); @@ -570,7 +551,7 @@ describe('KubernetesBackendClient', () => { }; const response = await backendClient.proxy(request); - await expect(response.json()).resolves.toStrictEqual(nsResponse); + await expect(response.json()).resolves.toEqual(nsResponse); }); it('/proxy API throws a 404 error', async () => { @@ -578,9 +559,9 @@ describe('KubernetesBackendClient', () => { token: 'k8-token', }); worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (_, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -616,15 +597,13 @@ describe('KubernetesBackendClient', () => { }, }; worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', - (req, res, ctx) => - res( - req.headers.get('Backstage-Kubernetes-Authorization') === - 'Bearer k8-token' - ? ctx.json(nsResponse) - : ctx.status(403), - ), + ({ request }) => + request.headers.get('Backstage-Kubernetes-Authorization') === + 'Bearer k8-token' + ? HttpResponse.json(nsResponse) + : new HttpResponse(null, { status: 403 }), ), ); @@ -646,14 +625,12 @@ describe('KubernetesBackendClient', () => { }, }; worker.use( - rest.get( + http.get( 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces/new-ns', - (req, res, ctx) => - res( - req.headers.get('Backstage-Kubernetes-Authorization') - ? ctx.status(403) - : ctx.json(nsResponse), - ), + ({ request }) => + request.headers.get('Backstage-Kubernetes-Authorization') + ? new HttpResponse(null, { status: 403 }) + : HttpResponse.json(nsResponse), ), ); kubernetesAuthProvidersApi.getCredentials.mockResolvedValue({}); @@ -663,7 +640,7 @@ describe('KubernetesBackendClient', () => { path: '/api/v1/namespaces/new-ns', }); - await expect(response.json()).resolves.toStrictEqual(nsResponse); + await expect(response.json()).resolves.toEqual(nsResponse); }); }); }); diff --git a/plugins/kubernetes-react/src/api/formatters/HeadlampClusterLinksFormatter.test.ts b/plugins/kubernetes-react/src/api/formatters/HeadlampClusterLinksFormatter.test.ts index 533e966137..12de678718 100644 --- a/plugins/kubernetes-react/src/api/formatters/HeadlampClusterLinksFormatter.test.ts +++ b/plugins/kubernetes-react/src/api/formatters/HeadlampClusterLinksFormatter.test.ts @@ -21,11 +21,6 @@ describe('HeadlampClusterLinksFormatter', () => { beforeEach(() => { formatter = new HeadlampClusterLinksFormatter(); - // Mock window.location.origin - Object.defineProperty(window, 'location', { - value: { origin: 'http://localhost:3000' }, - writable: true, - }); }); it('formats internal dashboard link correctly', async () => { @@ -41,7 +36,7 @@ describe('HeadlampClusterLinksFormatter', () => { const result = await formatter.formatClusterLink(options); expect(result.toString()).toBe( - 'http://localhost:3000/headlamp?to=%2Fc%2Ftest-cluster%2Fpods%2Fdefault%2Ftest-pod', + 'http://localhost/headlamp?to=%2Fc%2Ftest-cluster%2Fpods%2Fdefault%2Ftest-pod', ); }); diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 3780dee9c6..6fb347f44f 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-kubernetes +## 0.12.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.12.14 + +### Patch Changes + +- f15d5f1: add missing i18n support for kubernetes and kubernetes-react +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-kubernetes-react@0.5.14 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-kubernetes-common@0.9.9 + - @backstage/core-plugin-api@1.12.1 + - @backstage/plugin-permission-react@0.4.39 + ## 0.12.14-next.1 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index a455747640..f16f4c6b90 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.12.14-next.1", + "version": "0.12.15-next.0", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/mcp-actions-backend/CHANGELOG.md b/plugins/mcp-actions-backend/CHANGELOG.md index f5a0738405..c91b47584c 100644 --- a/plugins/mcp-actions-backend/CHANGELOG.md +++ b/plugins/mcp-actions-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-mcp-actions-backend +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-node@1.20.1 + +## 0.1.6 + +### Patch Changes + +- e83e038: Added `@cfworker/json-schema` as a dependency to this package part of the `@modelcontextprotocol/sdk` bump as it's required in the types +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 79ef471: Clarify error handling in readme and update handleError.ts to include all backstage/errors +- Updated dependencies + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 0.1.6-next.1 ### Patch Changes diff --git a/plugins/mcp-actions-backend/package.json b/plugins/mcp-actions-backend/package.json index 5a19fe1c46..b99cb48afe 100644 --- a/plugins/mcp-actions-backend/package.json +++ b/plugins/mcp-actions-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-mcp-actions-backend", - "version": "0.1.6-next.1", + "version": "0.1.7-next.0", "backstage": { "role": "backend-plugin", "pluginId": "mcp-actions", diff --git a/plugins/mui-to-bui/CHANGELOG.md b/plugins/mui-to-bui/CHANGELOG.md index 81ccaeb013..7f4a45c885 100644 --- a/plugins/mui-to-bui/CHANGELOG.md +++ b/plugins/mui-to-bui/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-mui-to-bui +## 0.2.3-next.0 + +### Patch Changes + +- e4a1180: Updated tokens from `--bui-bg` to `--bui-bg-surface-0` +- Updated dependencies + - @backstage/ui@0.11.0-next.0 + - @backstage/core-plugin-api@1.12.1 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/theme@0.7.1 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.10.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + ## 0.2.2-next.1 ### Patch Changes diff --git a/plugins/mui-to-bui/package.json b/plugins/mui-to-bui/package.json index f5f014a9ed..2305eec5a3 100644 --- a/plugins/mui-to-bui/package.json +++ b/plugins/mui-to-bui/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-mui-to-bui", - "version": "0.2.2-next.1", + "version": "0.2.3-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "mui-to-bui", diff --git a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts index 6ba3f7d2d9..48bb318a71 100644 --- a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts +++ b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts @@ -59,7 +59,7 @@ describe('convertMuiToBuiTheme', () => { // Border radius tokens are only generated when radius is 0 expect(result.css).not.toContain('--bui-radius-3:'); // Background default maps to surface-2 - expect(result.css).toContain('--bui-bg: #f5f5f5;'); + expect(result.css).toContain('--bui-bg-surface-0: #f5f5f5;'); expect(result.css).toContain('--bui-bg-surface-2: #f5f5f5;'); expect(result.css).toContain('--bui-bg-surface-1: #ffffff;'); expect(result.css).toContain('--bui-fg-primary: #000000;'); @@ -98,7 +98,7 @@ describe('convertMuiToBuiTheme', () => { expect(result.css).toContain("[data-theme-mode='dark'] {"); // Background default maps to surface-2 in dark mode as well - expect(result.css).toContain('--bui-bg: #121212;'); + expect(result.css).toContain('--bui-bg-surface-0: #121212;'); expect(result.css).toContain('--bui-bg-surface-2: #121212;'); expect(result.css).toContain('--bui-bg-surface-1: #1e1e1e;'); expect(result.css).toContain('--bui-fg-primary: #ffffff;'); diff --git a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts index 1b8528922b..029d70cec7 100644 --- a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts +++ b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts @@ -110,9 +110,10 @@ function generateBuiVariables(theme: Mui5Theme): Record { // Generate surface colors Object.entries({ - '': palette.background.default, + 'surface-0': palette.background.default, 'surface-1': palette.background.paper, 'surface-2': palette.background.default, + 'surface-3': palette.background.default, solid: palette.primary.main, 'solid-hover': blend(palette.primary.main, palette.primary.dark, 0.5), 'solid-pressed': palette.primary.dark, @@ -125,7 +126,7 @@ function generateBuiVariables(theme: Mui5Theme): Record { warning: palette.warning.light, success: palette.success.light, }).forEach(([key, value]) => { - styleObject[`--bui-bg${key ? `-${key}` : ''}`] = value; + styleObject[`--bui-bg-${key}`] = value; }); // Border colors diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 9a479822c1..21cb61c4c4 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.17 + +### Patch Changes + +- a5d5b3a: SES config for the notification email processor now supports utilizing an ARN for the SES identity when sending an email after the SES SDK V2 update. + + The `sesConfig.fromArn` will set the `fromEmailAddressIdentityArn` option for the SES `SendEmailCommand`. The `sesConfig.sourceArn` field is removed since no equivalent option is available in the send email command options. Setting `sesConfig.sourceArn` will have no effect and log a warning. Example changes: + + ```diff + notifications: + processors: + email: + transportConfig: + transport: "ses" + region: "us-west-2" + sender: "sender@mycompany.com" + replyTo: "no-reply@mycompany.com" + sesConfig: + - sourceArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" + fromArn: "arn:aws:ses:us-west-2:123456789012:identity/example.com" + ``` + +- b267aea: Updated dependency `@types/nodemailer` to `^7.0.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index a4e0957c23..b1f2831758 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.3.17-next.1", + "version": "0.3.17", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-slack/CHANGELOG.md b/plugins/notifications-backend-module-slack/CHANGELOG.md index 38c740cb4b..4d9c711297 100644 --- a/plugins/notifications-backend-module-slack/CHANGELOG.md +++ b/plugins/notifications-backend-module-slack/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-backend-module-slack +## 0.3.0 + +### Minor Changes + +- f95a516: Enables optional routes to Slack channels for broadcast notifications based on origin and/or topics. + +### Patch Changes + +- b80857a: Slack notification handler throttling can now be configured with the `concurrencyLimit` and `throttleInterval` options. +- f8230e4: Updated dependency `@faker-js/faker` to `^10.0.0`. +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + ## 0.2.2-next.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-slack/config.d.ts b/plugins/notifications-backend-module-slack/config.d.ts index e5971ec3ff..17a4e25e0d 100644 --- a/plugins/notifications-backend-module-slack/config.d.ts +++ b/plugins/notifications-backend-module-slack/config.d.ts @@ -28,8 +28,32 @@ export interface Config { * Broadcast notification receivers when receiver is set to config * These can be Slack User IDs, Slack User Email addresses, Slack Channel * Names, or Slack Channel IDs. Any valid identifier that chat.postMessage can accept. + * @deprecated Use broadcastRoutes instead for more granular control */ broadcastChannels?: string[]; + /** + * Optional username to display as the sender of the notification + */ + username?: string; + /** + * Routes for broadcast notifications based on origin and/or topic. + * Routes are evaluated in order, first match wins. + * Origin+topic matches take precedence over origin-only matches. + */ + broadcastRoutes?: Array<{ + /** + * The origin to match (e.g., 'plugin:catalog', 'external:my-service') + */ + origin?: string; + /** + * The topic to match (e.g., 'entity-updated', 'alerts') + */ + topic?: string; + /** + * The Slack channel(s) to send to. Can be channel IDs, channel names, or user IDs. + */ + channel: string | string[]; + }>; /** * Concurrency limit for Slack notifications per backend instance of the notifications plugin, defaults to 10. */ diff --git a/plugins/notifications-backend-module-slack/package.json b/plugins/notifications-backend-module-slack/package.json index 86a60c88bf..0e35577006 100644 --- a/plugins/notifications-backend-module-slack/package.json +++ b/plugins/notifications-backend-module-slack/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-slack", - "version": "0.2.2-next.1", + "version": "0.3.0", "description": "The slack backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", @@ -54,7 +54,7 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/test-utils": "workspace:^", - "@faker-js/faker": "^8.4.1", + "@faker-js/faker": "^10.0.0", "msw": "^2.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.test.ts b/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.test.ts index 2963d2c0e6..9490ff7dde 100644 --- a/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.test.ts +++ b/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.test.ts @@ -411,6 +411,462 @@ describe('SlackNotificationProcessor', () => { }); }); + describe('when broadcast routes are configured', () => { + it('should route by origin and topic (highest priority)', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastChannels: ['default-channel'], + broadcastRoutes: [ + { origin: 'plugin:catalog', channel: 'catalog-channel' }, + { topic: 'alerts', channel: 'alerts-channel' }, + { + origin: 'plugin:catalog', + topic: 'alerts', + channel: 'catalog-alerts-channel', + }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:catalog', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'alerts', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'alerts' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'catalog-alerts-channel' }), + ); + }); + + it('should route by origin only when no origin+topic match', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + { origin: 'plugin:catalog', channel: 'catalog-channel' }, + { topic: 'alerts', channel: 'alerts-channel' }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:catalog', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'updates', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'updates' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'catalog-channel' }), + ); + }); + + it('should route by topic only when no origin match', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + { origin: 'plugin:catalog', channel: 'catalog-channel' }, + { topic: 'alerts', channel: 'alerts-channel' }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:unknown', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'alerts', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'alerts' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'alerts-channel' }), + ); + }); + + it('should fall back to broadcastChannels when no route matches', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastChannels: ['default-channel'], + broadcastRoutes: [ + { origin: 'plugin:catalog', channel: 'catalog-channel' }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:unknown', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'default-channel' }), + ); + }); + + it('should support multiple channels in a route', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + { + origin: 'plugin:catalog', + channel: ['channel1', 'channel2', 'channel3'], + }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:catalog', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(3); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'channel1' }), + ); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'channel2' }), + ); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'channel3' }), + ); + }); + + it('should support single channel as string in a route', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + { topic: 'alerts', channel: 'single-alerts-channel' }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:any', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'alerts', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'alerts' }, + }, + ); + + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'single-alerts-channel' }), + ); + }); + + it('should not send when no route matches and no broadcastChannels configured', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + { origin: 'plugin:catalog', channel: 'catalog-channel' }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:unknown', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'unknown-topic', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'unknown-topic' }, + }, + ); + + expect(slack.chat.postMessage).not.toHaveBeenCalled(); + }); + + it('should match origin+topic route over origin-only route', async () => { + const slack = new WebClient(); + const routesConfig = mockServices.rootConfig({ + data: { + app: { + baseUrl: 'https://example.org', + }, + notifications: { + processors: { + slack: [ + { + token: 'mock-token', + broadcastRoutes: [ + // Origin-only route defined first + { origin: 'plugin:catalog', channel: 'general-catalog' }, + // More specific origin+topic route defined second + { + origin: 'plugin:catalog', + topic: 'entity-deleted', + channel: 'catalog-deletions', + }, + ], + }, + ], + }, + }, + }, + }); + + const processor = SlackNotificationProcessor.fromConfig(routesConfig, { + auth, + logger, + catalog: catalogServiceMock({ + entities: DEFAULT_ENTITIES_RESPONSE.items, + }), + slack, + })[0]; + + await processor.postProcess( + { + origin: 'plugin:catalog', + id: '1234', + user: null, + created: new Date(), + payload: { + title: 'notification', + topic: 'entity-deleted', + }, + }, + { + recipients: { type: 'broadcast' }, + payload: { title: 'notification', topic: 'entity-deleted' }, + }, + ); + + // Should use the origin+topic match, not the origin-only match + expect(slack.chat.postMessage).toHaveBeenCalledTimes(1); + expect(slack.chat.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ channel: 'catalog-deletions' }), + ); + }); + }); + describe('when slack.com/bot-notify annotation is missing', () => { it('should not send notification to a group without annotation', async () => { const slack = new WebClient(); diff --git a/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.ts b/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.ts index 14bc169573..e8f8d9eda4 100644 --- a/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.ts +++ b/plugins/notifications-backend-module-slack/src/lib/SlackNotificationProcessor.ts @@ -34,6 +34,7 @@ import { ChatPostMessageArguments, WebClient } from '@slack/web-api'; import DataLoader from 'dataloader'; import pThrottle from 'p-throttle'; import { ANNOTATION_SLACK_BOT_NOTIFY } from './constants'; +import { BroadcastRoute } from './types'; import { ExpiryMap, toChatPostMessageArgs } from './util'; import { CatalogService } from '@backstage/plugin-catalog-node'; @@ -48,6 +49,7 @@ export class SlackNotificationProcessor implements NotificationProcessor { private readonly messagesSent: Counter; private readonly messagesFailed: Counter; private readonly broadcastChannels?: string[]; + private readonly broadcastRoutes?: BroadcastRoute[]; private readonly entityLoader: DataLoader; private readonly username?: string; private readonly concurrencyLimit: number; @@ -70,6 +72,10 @@ export class SlackNotificationProcessor implements NotificationProcessor { const slack = options.slack ?? new WebClient(token); const broadcastChannels = c.getOptionalStringArray('broadcastChannels'); const username = c.getOptionalString('username'); + const broadcastRoutesConfig = c.getOptionalConfigArray('broadcastRoutes'); + const broadcastRoutes = broadcastRoutesConfig?.map(route => + this.parseBroadcastRoute(route), + ); const concurrencyLimit = c.getOptionalNumber('concurrencyLimit') ?? 10; const throttleInterval = c.has('throttleInterval') ? durationToMilliseconds( @@ -79,6 +85,7 @@ export class SlackNotificationProcessor implements NotificationProcessor { return new SlackNotificationProcessor({ slack, broadcastChannels, + broadcastRoutes, username, concurrencyLimit, throttleInterval, @@ -93,6 +100,7 @@ export class SlackNotificationProcessor implements NotificationProcessor { logger: LoggerService; catalog: CatalogService; broadcastChannels?: string[]; + broadcastRoutes?: BroadcastRoute[]; username?: string; concurrencyLimit?: number; throttleInterval?: number; @@ -103,6 +111,7 @@ export class SlackNotificationProcessor implements NotificationProcessor { logger, slack, broadcastChannels, + broadcastRoutes, username, concurrencyLimit, throttleInterval, @@ -112,6 +121,7 @@ export class SlackNotificationProcessor implements NotificationProcessor { this.auth = auth; this.slack = slack; this.broadcastChannels = broadcastChannels; + this.broadcastRoutes = broadcastRoutes; this.username = username; this.concurrencyLimit = concurrencyLimit ?? 10; this.throttleInterval = @@ -258,7 +268,8 @@ export class SlackNotificationProcessor implements NotificationProcessor { // Handle broadcast case if (notification.user === null) { - destinations.push(...(this.broadcastChannels ?? [])); + const routedChannels = this.getBroadcastDestinations(notification); + destinations.push(...routedChannels); } else if (options.recipients.type === 'entity') { // Handle user-specific notification const entityRefs = [options.recipients.entityRef].flat(); @@ -407,4 +418,88 @@ export class SlackNotificationProcessor implements NotificationProcessor { throw new Error(`Failed to send notification: ${response.error}`); } } + + private static parseBroadcastRoute(route: Config): BroadcastRoute { + const channelValue = route.getOptional('channel'); + let channels: string[]; + + if (typeof channelValue === 'string') { + channels = [channelValue]; + } else if (Array.isArray(channelValue)) { + channels = channelValue as string[]; + } else { + throw new Error( + 'broadcastRoutes entry must have a channel property (string or string[])', + ); + } + + return { + origin: route.getOptionalString('origin'), + topic: route.getOptionalString('topic'), + channels, + }; + } + + /** + * Gets the destination channels for a broadcast notification based on + * configured routes. Routes are matched by origin and/or topic. + * + * Matching precedence: + * 1. Routes with both origin AND topic matching (most specific) + * 2. Routes with only origin matching + * 3. Routes with only topic matching + * 4. Default broadcastChannels (least specific fallback) + * + * The first matching route wins within each precedence level. + */ + private getBroadcastDestinations(notification: Notification): string[] { + const { origin } = notification; + const { topic } = notification.payload; + + if (!this.broadcastRoutes || this.broadcastRoutes.length === 0) { + // Fall back to legacy broadcastChannels config + return this.broadcastChannels ?? []; + } + + // Find most specific match + // Priority 1: origin AND topic match + const originAndTopicMatch = this.broadcastRoutes.find( + route => + route.origin !== undefined && + route.topic !== undefined && + route.origin === origin && + route.topic === topic, + ); + + if (originAndTopicMatch) { + return originAndTopicMatch.channels; + } + + // Priority 2: origin-only match (no topic specified in route) + const originOnlyMatch = this.broadcastRoutes.find( + route => + route.origin !== undefined && + route.topic === undefined && + route.origin === origin, + ); + + if (originOnlyMatch) { + return originOnlyMatch.channels; + } + + // Priority 3: topic-only match (no origin specified in route) + const topicOnlyMatch = this.broadcastRoutes.find( + route => + route.topic !== undefined && + route.origin === undefined && + route.topic === topic, + ); + + if (topicOnlyMatch) { + return topicOnlyMatch.channels; + } + + // No match found, fall back to legacy broadcastChannels + return this.broadcastChannels ?? []; + } } diff --git a/plugins/notifications-backend-module-slack/src/lib/types.ts b/plugins/notifications-backend-module-slack/src/lib/types.ts index bd87e9656c..316df03462 100644 --- a/plugins/notifications-backend-module-slack/src/lib/types.ts +++ b/plugins/notifications-backend-module-slack/src/lib/types.ts @@ -18,3 +18,16 @@ export interface SlackNotificationOptions { url: string; payload: string; } + +/** + * Configuration for routing broadcast notifications to specific Slack channels + * based on origin and/or topic. + */ +export type BroadcastRoute = { + /** The origin to match (e.g., 'plugin:catalog', 'external:my-service') */ + origin?: string; + /** The topic to match (e.g., 'entity-updated', 'alerts') */ + topic?: string; + /** The Slack channel(s) to send to */ + channels: string[]; +}; diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index e52d81afc0..91da5468ca 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-notifications-backend +## 0.6.1 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-notifications-node@0.2.22 + ## 0.6.1-next.1 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index d2df0faf9b..7262b65d38 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.6.1-next.1", + "version": "0.6.1", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index bd74b53be2..98d1b3c84c 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-notifications-node +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.22-next.1 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index 529e7904a4..8007852dd5 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.22-next.1", + "version": "0.2.22", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index b40d8540bf..50bd9b35a3 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-notifications +## 0.5.12 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 53347cc: Move long notification descriptions behind `Show more/less` button. + + This improves readability of the notifications list by preventing long descriptions from taking up too much space + or rendering very small scrollable areas. + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + ## 0.5.12-next.0 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 5f2c652425..1a6b544da3 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.5.12-next.0", + "version": "0.5.12", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index 5cfb6f1a18..1a7f5a0c8a 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-org-react +## 0.1.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + +## 0.1.45 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.1.45-next.0 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index a077894bc7..ea019289bb 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.45-next.0", + "version": "0.1.46-next.0", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index bbf64740b8..ddea784dcb 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-org +## 0.6.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.6.47 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + ## 0.6.47-next.1 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 340f6a3773..a2a3739acf 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.47-next.1", + "version": "0.6.48-next.0", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 3296f8b846..a9709fd88b 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + ## 0.2.15-next.1 ### 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 65d806f37e..5cddb60c98 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.2.15-next.1", + "version": "0.2.15", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 3df4344b18..196de3238b 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-backend +## 0.7.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + ## 0.7.7-next.1 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index da36d835a9..f3c840b693 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.7.7-next.1", + "version": "0.7.7", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index ece99f08c7..822d10b858 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -148,9 +148,7 @@ describe('PermissionIntegrationClient', () => { ], ); - expect(response).toEqual( - expect.objectContaining([{ id: '123', result: AuthorizeResult.ALLOW }]), - ); + expect(response).toEqual([{ id: '123', result: AuthorizeResult.ALLOW }]); }); it('should not include authorization headers if no token is supplied', async () => { diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 213b9f24f3..6c9fe8a91b 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-node +## 0.10.7 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-plugin-api@1.6.0 + ## 0.10.7-next.1 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index b222eb63cd..1ae3935b4c 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.10.7-next.1", + "version": "0.10.7", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index cf0248c840..9a377d5dc8 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-permission-react +## 0.4.39 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + ## 0.4.39-next.0 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 098959f342..17b4d65b51 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.39-next.0", + "version": "0.4.39", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 04cdca7611..7541c8faf1 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.6.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-proxy-node@0.1.11 + ## 0.6.9-next.1 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index c408692f3d..c75e9a42e7 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.6.9-next.1", + "version": "0.6.9", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/proxy-node/CHANGELOG.md b/plugins/proxy-node/CHANGELOG.md index 6388858064..e2bf6a15cf 100644 --- a/plugins/proxy-node/CHANGELOG.md +++ b/plugins/proxy-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-proxy-node +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.11-next.1 ### Patch Changes diff --git a/plugins/proxy-node/package.json b/plugins/proxy-node/package.json index 3e786060b5..9134a6c2b5 100644 --- a/plugins/proxy-node/package.json +++ b/plugins/proxy-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-node", - "version": "0.1.11-next.1", + "version": "0.1.11", "description": "The plugin-proxy-node module for @backstage/plugin-proxy-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index 96198a8eb7..0c39a865fe 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index a854181873..fc87c17b6a 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index f8c8771f7d..cd4fc60f4c 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.3.0 + +### Minor Changes + +- 37fba1d: Added support for Bitbucket Cloud OAuth. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues. + + **BREAKING CHANGES** + + - **@backstage/integration** (`src/bitbucketCloud/core.ts`) + + - `getBitbucketCloudRequestOptions` now returns a `Promise` and **must** be awaited. + + - **@backstage/plugin-scaffolder-backend-module-bitbucket-cloud** (`src/actions/helpers.ts`) + - `getBitbucketClient` now returns a `Promise` and **must** be awaited. + - `getAuthorizationHeader` now returns a `Promise` and **must** be awaited. + + **OAuth usage example** + + ```yaml + integrations: + bitbucketCloud: + - clientId: client-id + clientSecret: client-secret + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index dc0a41490b..76f5397fcb 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.2.16-next.1", + "version": "0.3.1-next.0", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts index 722bf01303..a278410639 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts @@ -25,6 +25,7 @@ import { import { Config } from '@backstage/config'; import { getAuthorizationHeader } from './helpers'; +import { getBitbucketCloudOAuthToken } from '@backstage/integration'; import { examples } from './bitbucketCloud.examples'; const createRepository = async (opts: { @@ -216,7 +217,7 @@ export function createPublishBitbucketCloudAction(options: { ); } - const authorization = getAuthorizationHeader( + const authorization = await getAuthorizationHeader( ctx.input.token ? { token: ctx.input.token } : integrationConfig.config, ); @@ -249,6 +250,18 @@ export function createPublishBitbucketCloudAction(options: { username: 'x-token-auth', password: ctx.input.token, }; + } else if ( + integrationConfig.config.clientId && + integrationConfig.config.clientSecret + ) { + const token = await getBitbucketCloudOAuthToken( + integrationConfig.config.clientId, + integrationConfig.config.clientSecret, + ); + auth = { + username: 'x-token-auth', + password: token, + }; } else { if ( !integrationConfig.config.username || diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.test.ts index 55ee430091..2ac54894d5 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.test.ts @@ -22,11 +22,11 @@ jest.mock('bitbucket', () => ({ })); describe('bitbucketCloud:branchRestriction:create', () => { - it('getBitbucketClient should return the correct headers with username and password', () => { + it('getBitbucketClient should return the correct headers with username and password', async () => { expect.assertions(1); const username = 'username'; const password = 'password'; - getBitbucketClient({ username: username, appPassword: password }); + await getBitbucketClient({ username: username, appPassword: password }); expect(Bitbucket).toHaveBeenCalledWith({ auth: { username: username, @@ -35,12 +35,14 @@ describe('bitbucketCloud:branchRestriction:create', () => { }); }); - it('getBitbucketClient should throw if only one of username or password is provided', () => { + it('getBitbucketClient should throw if only one of username or password is provided', async () => { expect.assertions(2); const username = 'username'; const password = 'password'; - expect(() => getBitbucketClient({ username })).toThrow(Error); - expect(() => getBitbucketClient({ appPassword: password })).toThrow(Error); + await expect(getBitbucketClient({ username })).rejects.toThrow(Error); + await expect(getBitbucketClient({ appPassword: password })).rejects.toThrow( + Error, + ); }); }); diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.ts index 233818e00a..a12f63f980 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudBranchRestriction.ts @@ -37,6 +37,8 @@ const createBitbucketCloudBranchRestriction = async (opts: { token?: string; username?: string; appPassword?: string; + clientId?: string; + clientSecret?: string; }; }) => { const { @@ -52,7 +54,7 @@ const createBitbucketCloudBranchRestriction = async (opts: { authorization, } = opts; - const bitbucket = getBitbucketClient(authorization); + const bitbucket = await getBitbucketClient(authorization); return await bitbucket.branchrestrictions.create({ _body: { groups: groups, diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts index 4bf9226db7..372f45c928 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts @@ -68,7 +68,7 @@ export const createBitbucketPipelinesRunAction = (options: { const host = 'bitbucket.org'; const integrationConfig = integrations.bitbucketCloud.byHost(host); - const authorization = getAuthorizationHeader( + const authorization = await getAuthorizationHeader( token ? { token } : integrationConfig!.config, ); let response: Response; diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts index 9969f13eb2..40dd09d386 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts @@ -28,6 +28,7 @@ import { import { Config } from '@backstage/config'; import fs from 'fs-extra'; import { getAuthorizationHeader } from './helpers'; +import { getBitbucketCloudOAuthToken } from '@backstage/integration'; import { examples } from './bitbucketCloudPullRequest.examples'; const createPullRequest = async (opts: { @@ -317,7 +318,7 @@ export function createPublishBitbucketCloudPullRequestAction(options: { ); } - const authorization = getAuthorizationHeader( + const authorization = await getAuthorizationHeader( ctx.input.token ? { token: ctx.input.token } : integrationConfig.config, ); @@ -365,6 +366,18 @@ export function createPublishBitbucketCloudPullRequestAction(options: { username: 'x-token-auth', password: ctx.input.token, }; + } else if ( + integrationConfig.config.clientId && + integrationConfig.config.clientSecret + ) { + const token = await getBitbucketCloudOAuthToken( + integrationConfig.config.clientId, + integrationConfig.config.clientSecret, + ); + auth = { + username: 'x-token-auth', + password: token, + }; } else { if ( !integrationConfig.config.username || diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts index 2e68d4e8b8..47a212fcab 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/helpers.ts @@ -15,12 +15,28 @@ */ import { Bitbucket } from 'bitbucket'; +import { getBitbucketCloudOAuthToken } from '@backstage/integration'; -export const getBitbucketClient = (config: { +export const getBitbucketClient = async (config: { token?: string; username?: string; appPassword?: string; + clientId?: string; + clientSecret?: string; }) => { + // If OAuth credentials provided, fetch token + if (config.clientId && config.clientSecret) { + const token = await getBitbucketCloudOAuthToken( + config.clientId, + config.clientSecret, + ); + return new Bitbucket({ + auth: { + token, + }, + }); + } + if (config.token) { return new Bitbucket({ auth: { @@ -38,15 +54,26 @@ export const getBitbucketClient = (config: { }); } throw new Error( - `Authorization has not been provided for Bitbucket Cloud. Please add either provide a username and token or username and appPassword to the Integrations config`, + `Authorization has not been provided for Bitbucket Cloud. Please provide either OAuth credentials (clientId/clientSecret), username and token, or username and appPassword in the Integrations config`, ); }; -export const getAuthorizationHeader = (config: { +export const getAuthorizationHeader = async (config: { username?: string; appPassword?: string; token?: string; -}) => { + clientId?: string; + clientSecret?: string; +}): Promise => { + // OAuth authentication + if (config.clientId && config.clientSecret) { + const token = await getBitbucketCloudOAuthToken( + config.clientId, + config.clientSecret, + ); + return `Bearer ${token}`; + } + // TODO: appPassword can be removed once fully // deprecated by BitBucket on 9th June 2026. if (config.username && (config.token ?? config.appPassword)) { @@ -62,6 +89,6 @@ export const getAuthorizationHeader = (config: { } throw new Error( - `Authorization has not been provided for Bitbucket Cloud. Please add either provide a username and token or username and appPassword to the Integrations config`, + `Authorization has not been provided for Bitbucket Cloud. Please provide either OAuth credentials (clientId/clientSecret), username and token, or username and appPassword in the Integrations config`, ); }; diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 761be5b8ed..bf7772b06f 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- 5a6aca2: Improve error message when provided target branch is missing +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index c5c1c0c8ed..43d4c88f91 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 337b24d4be..025b0876d5 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.17-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.3.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index d2720727d7..2d2958dbd5 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.3.17-next.1", + "version": "0.3.18-next.0", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index eaa585eef1..2290d72474 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.3.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.3.16-next.1 ### 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 9a4172f9c4..c8974eb762 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.3.16-next.1", + "version": "0.3.17-next.0", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 1307d6a5e9..4c47975b75 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + +## 0.3.18 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.3.18-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 91310eb1ba..5f16124d88 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.3.18-next.1", + "version": "0.3.19-next.1", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index cda0bf51f5..245caa18bc 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index fd100111cb..e1d636da48 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index c9330fa586..a206575bc9 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 644b7fca64..68cd290bd8 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index 94e70ce3f8..670e5b2b23 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 8a6baf517a..57db4e4bef 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.2.16-next.1", + "version": "0.2.17-next.0", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index a00a5a058f..7cd9b4b101 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.9.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.9.3 + +### Patch Changes + +- dab3d3f: Added autocompletion resource `owners` for retrieving GitHub repository owners. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.9.3-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index a57a96432e..789b77e278 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.9.3-next.1", + "version": "0.9.4-next.0", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.test.ts index 9b9aaff9c2..8076a4de01 100644 --- a/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.test.ts @@ -31,6 +31,9 @@ const mockOctokit = { listForAuthenticatedUser: jest.fn(), listBranches: jest.fn(), }, + orgs: { + listForAuthenticatedUser: jest.fn(), + }, }, }; jest.mock('octokit', () => ({ @@ -95,6 +98,30 @@ describe('handleAutocompleteRequest', () => { }); }); + it('should return owners', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + mockOctokit.rest.orgs.listForAuthenticatedUser.mockResolvedValue({ + data: [ + { + login: 'backstage', + }, + ], + }); + + const result = await handleAutocompleteRequest({ + resource: 'owners', + token: 'token', + context: {}, + }); + + expect(result).toEqual({ + results: [{ id: 'backstage' }], + }); + }); + it('should throw an error for invalid resource', async () => { const handleAutocompleteRequest = createHandleAutocompleteRequest({ integrations: mockIntegrations, diff --git a/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.ts index 35d6b4f930..b3efde9333 100644 --- a/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-github/src/autocomplete/autocomplete.ts @@ -64,6 +64,15 @@ export function createHandleAutocompleteRequest(options: { return { results }; } + case 'owners': { + const orgs = await client.paginate( + client.rest.orgs.listForAuthenticatedUser, + ); + + const results = orgs.map(r => ({ id: r.login })); + + return { results }; + } default: throw new InputError(`Invalid resource: ${resource}`); } diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 33fb7194a1..dfd09b5d16 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.11.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.11.0 + +### Minor Changes + +- f2d034b: In the `gitlabRepoPush` action, add 'auto' possibility for `commitAction` input. + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.11.0-next.1 ### Minor Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index 367c13d3e7..e0fa66ca1d 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.11.0-next.1", + "version": "0.11.1-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 59f47d7b4d..37998ea949 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-notifications-node@0.2.22 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.1.17-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index b9602f3434..ef5e8f73b3 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.1.17-next.1", + "version": "0.1.18-next.0", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 42edca5af2..210aa6a51c 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.5.16 + +### Patch Changes + +- 2bae83a: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.5.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index d197cdefbe..c9e9a3f89e 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.5.16-next.1", + "version": "0.5.17-next.0", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 400474d985..26b8e72dc1 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.2.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.2.16-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 007b31ac46..33ed045c85 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.2.16-next.1", + "version": "0.2.17-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index bc8d43c5ea..4bdf58641a 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.1 + +## 0.4.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-scaffolder-node-test-utils@0.3.7-next.0 + +## 0.4.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + - @backstage/plugin-scaffolder-node-test-utils@0.3.6 + ## 0.4.17-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 855489615e..be5bff5dde 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.4.17-next.1", + "version": "0.4.18-next.1", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index f4e7e7debe..0509a055b1 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,92 @@ # @backstage/plugin-scaffolder-backend +## 3.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.6-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.18-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.1-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.17-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.4-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.1-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.16-next.0 + +## 3.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-openapi-utils@0.6.5-next.0 + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-common@0.9.3 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.16 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.17 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.16 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.0 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-scaffolder-node@0.12.2 + +## 3.1.0 + +### Minor Changes + +- a4cd405: Add `defaultEnvironment` config to scaffolder to enable more flexible and custom templates. Now it's possible enable access to default parameters and secrets in templates, improving security and reducing complexity. + +### Patch Changes + +- be5972b: Fixed a bug where config was not passed to NunjucksWorkflowRunner, causing defaultEnvironment to be undefined +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 2bae83a: Updated `isolated-vm` to `6.0.1` +- 25b560e: Internal change to support new versions of the `logform` library +- 8f4aded: Fixing OpenAPI definition +- 1226647: Updated dependency `esbuild` to `^0.27.0`. +- Updated dependencies + - @backstage/plugin-scaffolder-backend-module-gitlab@0.11.0 + - @backstage/integration@1.19.0 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.3.5 + - @backstage/backend-defaults@0.14.0 + - @backstage/backend-openapi-utils@0.6.4 + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-permission-node@0.10.7 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.3 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.16 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.17 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.15 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.16 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.16 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 3.1.0-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 04cf514359..970c7b00e3 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "3.1.0-next.1", + "version": "3.1.1-next.1", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml index 0a7c841d8f..c8f85974ea 100644 --- a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml @@ -69,7 +69,7 @@ spec: url: https://github.com/backstage/community/tree/main/backstage-community-sessions - id: publish name: Publish - action: publish:bitbucket + action: publish:bitbucketCloud input: description: This is ${{ parameters.name }} repoUrl: ${{ parameters.repoUrl }} @@ -81,10 +81,28 @@ spec: repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} catalogInfoPath: '/catalog-info.yaml' + - id: create-pr-file + name: Create PR File + action: fetch:plain + input: + targetPath: ./pr-demo + url: https://github.com/backstage/community/blob/main/README.md + - id: create-pr + name: Create Pull Request + action: publish:bitbucketCloud:pull-request + input: + repoUrl: ${{ parameters.repoUrl }} + title: Test PR for ${{ parameters.name }} + description: This is a test pull request created by the scaffolder template to test OAuth support + sourceBranch: scaffolder-pr-${{ parameters.name }} + targetBranch: master + output: links: - title: Repository url: ${{ steps['publish'].output.remoteUrl }} + - title: Pull Request + url: ${{ steps['create-pr'].output.pullRequestUrl }} - title: Open in catalog icon: catalog entityRef: ${{ steps['register'].output.entityRef }} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index 3a15b345db..ef704bc9e0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -134,6 +134,7 @@ export class TaskWorker { additionalTemplateFilters, additionalTemplateGlobals, permissions, + config, }); return new TaskWorker({ diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 1bc44a09c5..7fa220df9a 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-common +## 1.7.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 1.7.4 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + ## 1.7.4-next.0 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 1949f12e18..35a3781847 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.7.4-next.0", + "version": "1.7.5-next.0", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 47362fb401..9c624361b3 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.12.3-next.0 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.6.0 + - @backstage/backend-test-utils@1.10.3-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.2 + +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.10.2 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-node@0.12.2 + ## 0.3.6-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index d081c42dc1..32273938be 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.3.6-next.1", + "version": "0.3.7-next.1", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index ba1b53b67c..8bde905896 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-node +## 0.12.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + +## 0.12.2 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-scaffolder-common@1.7.4 + ## 0.12.2-next.1 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index ae8e75cec6..3a6c1650fb 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.12.2-next.1", + "version": "0.12.3-next.0", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index f30fe5d9e3..2b96c13501 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-scaffolder-react +## 1.19.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 1.19.4 + +### Patch Changes + +- fb029b6: Updated luxon types +- 5ca461e: Fixed bug where custom `review.name` values were incorrectly formatted by `startCase`, preserving them exactly as written. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- 9b38f22: Updated dependency `use-immer` to `^0.11.0`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + ## 1.19.4-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index e1c16d4766..d256f0cbd2 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.19.4-next.2", + "version": "1.19.5-next.0", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", 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 b0746e0672..6a542396de 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.test.tsx @@ -514,11 +514,12 @@ describe('Stepper', () => { const mockFormData = { firstName: 'John' }; - Object.defineProperty(window, 'location', { - value: { - search: `?formData=${JSON.stringify(mockFormData)}`, - }, - }); + // Use history.replaceState to set the query string (jsdom 27 doesn't allow redefining window.location) + window.history.replaceState( + {}, + '', + `?formData=${JSON.stringify(mockFormData)}`, + ); const { getByRole } = await renderInTestApp( diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index e4f60d5251..f28464a029 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-scaffolder +## 1.35.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-scaffolder-common@1.7.5-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-scaffolder-react@1.19.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 1.35.0 + +### Minor Changes + +- dab3d3f: Added field extension `RepoOwnerPicker` for retrieving GitHub repository owners. + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- be21c5c: Updated dependency `@rjsf/utils` to `5.24.13`. + Updated dependency `@rjsf/core` to `5.24.13`. + Updated dependency `@rjsf/material-ui` to `5.24.13`. + Updated dependency `@rjsf/validator-ajv8` to `5.24.13`. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-scaffolder-react@1.19.4 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-permission-react@0.4.39 + - @backstage/plugin-scaffolder-common@1.7.4 + - @backstage/plugin-techdocs-react@1.3.6 + ## 1.34.4-next.1 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 5ad62724e3..cccd73ce0a 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.34.4-next.1", + "version": "1.35.1-next.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 7c0247cae9..7ffe367327 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -350,6 +350,21 @@ const _default: OverridableFrontendPlugin< field: () => Promise; }; }>; + 'scaffolder-form-field:scaffolder/repo-owner-picker': OverridableExtensionDefinition<{ + kind: 'scaffolder-form-field'; + name: 'repo-owner-picker'; + config: {}; + configInput: {}; + output: ExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >; + inputs: {}; + params: { + field: () => Promise; + }; + }>; 'scaffolder-form-field:scaffolder/repo-url-picker': OverridableExtensionDefinition<{ kind: 'scaffolder-form-field'; name: 'repo-url-picker'; @@ -499,6 +514,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'fields.repoUrlPicker.repository.title': 'Repositories Available'; readonly 'fields.repoUrlPicker.repository.description': 'The name of the repository'; readonly 'fields.repoUrlPicker.repository.inputTitle': 'Repository'; + readonly 'fields.repoOwnerPicker.title': 'Owner'; + readonly 'fields.repoOwnerPicker.description': 'The owner of the repository'; readonly 'aboutCard.launchTemplate': 'Launch Template'; readonly 'actionsPage.content.emptyState.title': 'No information to display'; readonly 'actionsPage.content.emptyState.description': 'There are no actions installed or there was an issue communicating with backend.'; diff --git a/plugins/scaffolder/report.api.md b/plugins/scaffolder/report.api.md index 2e9c6be1ef..e624b157fa 100644 --- a/plugins/scaffolder/report.api.md +++ b/plugins/scaffolder/report.api.md @@ -391,6 +391,30 @@ export const RepoBranchPickerFieldExtension: FieldExtensionComponent_2< } >; +// @public +export const RepoOwnerPickerFieldExtension: FieldExtensionComponent_2< + string, + { + host?: string | undefined; + requestUserCredentials?: + | { + secretsKey: string; + additionalScopes?: + | { + azure?: string[] | undefined; + github?: string[] | undefined; + gitlab?: string[] | undefined; + bitbucket?: string[] | undefined; + gerrit?: string[] | undefined; + gitea?: string[] | undefined; + } + | undefined; + } + | undefined; + excludedOwners?: string[] | undefined; + } +>; + // @public export const repoPickerValidation: ( value: string, diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx index 427f679188..86400fcfde 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorBrowser.test.tsx @@ -20,14 +20,6 @@ import { MockFileSystemAccess } from '../../../lib/filesystem/MockFileSystemAcce import { DirectoryEditorProvider } from './DirectoryEditorContext'; import { TemplateEditorBrowser } from './TemplateEditorBrowser'; -Blob.prototype.text = async function text() { - return new Promise(resolve => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result as string); - reader.readAsText(this); - }); -}; - describe('TemplateEditorBrowser', () => { it('should render files and expand dirs without exploding', async () => { await renderInTestApp( diff --git a/plugins/scaffolder/src/alpha/extensions.tsx b/plugins/scaffolder/src/alpha/extensions.tsx index 429e6d493a..5215fc0968 100644 --- a/plugins/scaffolder/src/alpha/extensions.tsx +++ b/plugins/scaffolder/src/alpha/extensions.tsx @@ -127,6 +127,14 @@ export const repoBranchPickerFormField = FormFieldBlueprint.make({ }, }); +export const repoOwnerPickerFormField = FormFieldBlueprint.make({ + name: 'repo-owner-picker', + params: { + field: () => + import('./fields/RepoOwnerPicker').then(m => m.RepoOwnerPicker), + }, +}); + export const scaffolderApi = ApiBlueprint.make({ params: defineParams => defineParams({ diff --git a/plugins/scaffolder/src/alpha/fields/RepoOwnerPicker.ts b/plugins/scaffolder/src/alpha/fields/RepoOwnerPicker.ts new file mode 100644 index 0000000000..059d71fb83 --- /dev/null +++ b/plugins/scaffolder/src/alpha/fields/RepoOwnerPicker.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createFormField } from '@backstage/plugin-scaffolder-react/alpha'; +import { + RepoOwnerPicker as Component, + RepoOwnerPickerFieldSchema, +} from '../../components/fields/RepoOwnerPicker'; + +export const RepoOwnerPicker = createFormField({ + component: Component, + name: 'RepoOwnerPicker', + schema: RepoOwnerPickerFieldSchema, +}); diff --git a/plugins/scaffolder/src/alpha/plugin.tsx b/plugins/scaffolder/src/alpha/plugin.tsx index 5bb744e2ea..502aab0bbc 100644 --- a/plugins/scaffolder/src/alpha/plugin.tsx +++ b/plugins/scaffolder/src/alpha/plugin.tsx @@ -35,6 +35,7 @@ import { ownedEntityPickerFormField, ownerPickerFormField, repoBranchPickerFormField, + repoOwnerPickerFormField, repoUrlPickerFormField, scaffolderApi, scaffolderNavItem, @@ -88,5 +89,6 @@ export default createFrontendPlugin({ myGroupsPickerFormField, ownedEntityPickerFormField, repoBranchPickerFormField, + repoOwnerPickerFormField, ], }); diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.test.tsx new file mode 100644 index 0000000000..2e335a44a3 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.test.tsx @@ -0,0 +1,72 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { fireEvent, screen } from '@testing-library/react'; +import { renderInTestApp } from '@backstage/test-utils'; + +import { DefaultRepoOwnerPicker } from './DefaultRepoOwnerPicker'; + +describe('DefaultRepoOwnerPicker', () => { + it('renders an input field', async () => { + const { getByRole } = await renderInTestApp( + , + ); + + expect(getByRole('textbox')).toBeInTheDocument(); + expect(getByRole('textbox')).toHaveValue('owner1'); + }); + + it('input field disabled', async () => { + await renderInTestApp( + , + ); + + const input = screen.getByRole('textbox'); + + // Expect input to be disabled + expect(input).toBeDisabled(); + expect(input).toHaveValue('owner1'); + }); + + it('calls onChange when the input field changes', async () => { + const onChange = jest.fn(); + + const { getByRole } = await renderInTestApp( + , + ); + + const input = getByRole('textbox'); + + fireEvent.change(input, { + target: { value: 'owner2' }, + }); + + expect(onChange).toHaveBeenCalledWith({ owner: 'owner2' }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.tsx new file mode 100644 index 0000000000..48d7da8ba8 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import TextField from '@material-ui/core/TextField'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; + +import { BaseRepoOwnerPickerProps } from './types'; +import { scaffolderTranslationRef } from '../../../translation'; + +/** + * The underlying component that is rendered in the form for the `DefaultRepoOwnerPicker` + * field extension. + * + * @public + * + */ +export const DefaultRepoOwnerPicker = ({ + onChange, + state, + rawErrors, + isDisabled, + required, + schema, +}: BaseRepoOwnerPickerProps) => { + const { owner } = state; + + const { t } = useTranslationRef(scaffolderTranslationRef); + + return ( + 0 && !owner} + > + onChange({ owner: e.target.value })} + value={owner} + /> + + {schema?.description ?? t('fields.repoOwnerPicker.description')} + + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.test.tsx new file mode 100644 index 0000000000..bfc6c76768 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.test.tsx @@ -0,0 +1,149 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ScaffolderApi, + scaffolderApiRef, +} from '@backstage/plugin-scaffolder-react'; +import { GitHubRepoOwnerPicker } from './GitHubRepoOwnerPicker'; +import { act, fireEvent, waitFor, screen } from '@testing-library/react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import userEvent from '@testing-library/user-event'; + +describe('GitHubRepoOwnerPicker', () => { + const scaffolderApiMock: Partial = { + autocomplete: jest + .fn() + .mockResolvedValue({ results: [{ id: 'owner1' }, { id: 'owner2' }] }), + }; + + it('renders an input field', async () => { + const { getByRole } = await renderInTestApp( + + + , + ); + + expect(getByRole('textbox')).toBeInTheDocument(); + expect(getByRole('textbox')).toHaveValue('owner1'); + }); + + it('input field disabled', async () => { + await renderInTestApp( + + + , + ); + + const input = screen.getByRole('textbox'); + + // Expect input to be disabled + expect(input).toBeDisabled(); + expect(input).toHaveValue('owner1'); + }); + + it('calls onChange when the input field changes', async () => { + const onChange = jest.fn(); + + const { getByRole } = await renderInTestApp( + + + , + ); + + const input = getByRole('textbox'); + + act(() => { + input.focus(); + fireEvent.change(input, { + target: { value: 'owner2' }, + }); + input.blur(); + }); + + expect(onChange).toHaveBeenCalledWith({ owner: 'owner2' }); + }); + + it('should populate owners', async () => { + const onChange = jest.fn(); + + const { getByRole, getByText } = await renderInTestApp( + + + , + ); + + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that the available owners are shown + await waitFor(() => expect(getByText('owner1')).toBeInTheDocument()); + + // Verify that selecting an option calls onChange + await userEvent.click(getByText('owner1')); + expect(onChange).toHaveBeenCalledWith({ + owner: 'owner1', + }); + }); + + it('should filter out excluded owners', async () => { + const onChange = jest.fn(); + + const { getByRole, getByText } = await renderInTestApp( + + + , + ); + + // Open the Autocomplete dropdown + const input = getByRole('textbox'); + await userEvent.click(input); + + // Verify that the excluded owners are not shown + await waitFor(() => expect(getByText('owner2')).toBeInTheDocument()); + expect(screen.queryByText('owner1')).not.toBeInTheDocument(); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.tsx new file mode 100644 index 0000000000..9258ef312d --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.tsx @@ -0,0 +1,113 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi } from '@backstage/core-plugin-api'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; +import FormControl from '@material-ui/core/FormControl'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { useCallback, useState } from 'react'; +import useDebounce from 'react-use/esm/useDebounce'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; + +import { BaseRepoOwnerPickerProps } from './types'; +import { scaffolderTranslationRef } from '../../../translation'; + +/** + * The underlying component that is rendered in the form for the `GitHubRepoOwnerPicker` + * field extension. + * + * @public + * + */ +export const GitHubRepoOwnerPicker = ({ + onChange, + state, + rawErrors, + accessToken, + isDisabled, + required, + schema, + excludedOwners = [], +}: BaseRepoOwnerPickerProps<{ + accessToken?: string; + excludedOwners?: string[]; +}>) => { + const { host, owner } = state; + + const [availableOwners, setAvailableOwners] = useState([]); + + const scaffolderApi = useApi(scaffolderApiRef); + const { t } = useTranslationRef(scaffolderTranslationRef); + + const updateAvailableOwners = useCallback(() => { + if (!scaffolderApi.autocomplete || !accessToken || !host) { + setAvailableOwners([]); + return; + } + + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'owners', + context: { host }, + provider: 'github', + }) + .then(({ results }) => { + const owners = results + .map(r => r.id) + .filter(id => !excludedOwners.includes(id)); + + setAvailableOwners(owners); + }) + .catch(() => { + setAvailableOwners([]); + }); + }, [host, accessToken, scaffolderApi, excludedOwners]); + + useDebounce(updateAvailableOwners, 500, [updateAvailableOwners]); + + return ( + 0 && !owner} + > + { + onChange({ owner: newValue || '' }); + }} + disabled={isDisabled} + options={availableOwners} + renderInput={params => ( + + )} + freeSolo + autoSelect + /> + + {schema?.description ?? t('fields.repoOwnerPicker.description')} + + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx new file mode 100644 index 0000000000..c51d74416b --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.test.tsx @@ -0,0 +1,308 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Form } from '@backstage/plugin-scaffolder-react/alpha'; +import validator from '@rjsf/validator-ajv8'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + scmIntegrationsApiRef, + ScmIntegrationsApi, + scmAuthApiRef, + ScmAuthApi, +} from '@backstage/integration-react'; + +import { + SecretsContextProvider, + scaffolderApiRef, + useTemplateSecrets, + ScaffolderRJSFField, +} from '@backstage/plugin-scaffolder-react'; +import { act, fireEvent, screen } from '@testing-library/react'; +import { RepoOwnerPicker } from './RepoOwnerPicker'; + +describe('RepoOwnerPicker', () => { + const mockIntegrationsApi: Partial = { + byHost: () => ({ type: 'github' }), + }; + + let mockScmAuthApi: Partial; + + beforeEach(() => { + mockScmAuthApi = { + getCredentials: jest.fn().mockResolvedValue({ token: 'abc123' }), + }; + }); + + describe('happy path rendering', () => { + it('should render the repo owner picker with minimal props', async () => { + const onSubmit = jest.fn(); + + const { getByRole, getByText } = await renderInTestApp( + + +
, + }} + onSubmit={onSubmit} + /> + + , + ); + + const input = getByRole('textbox'); + const submitButton = getByRole('button'); + + fireEvent.change(input, { target: { value: 'owner1' } }); + + fireEvent.click(submitButton); + + expect(onSubmit).toHaveBeenCalledWith( + expect.objectContaining({ + formData: 'owner1', + }), + expect.anything(), + ); + + expect(getByText('Owner')).toBeInTheDocument(); + expect(getByText('The owner of the repository')).toBeInTheDocument(); + }); + + it('should disable the picker when ui:disabled', async () => { + const onSubmit = jest.fn(); + + await renderInTestApp( + + + , + }} + onSubmit={onSubmit} + /> + + , + ); + + const input = screen.getByRole('textbox'); + + expect(input).toBeDisabled(); + }); + + it('should render properly with title and description', async () => { + const { getByText } = await renderInTestApp( + + + , + }} + /> + + , + ); + + expect(getByText('test title')).toBeInTheDocument(); + expect(getByText('test description')).toBeInTheDocument(); + }); + }); + + describe('requestUserCredentials', () => { + it('should call the scmAuthApi with the correct params', async () => { + const secretsKey = 'testKey'; + + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + const secret = secrets[secretsKey]; + return secret ?
{secret}
: null; + }; + + const { getByText } = await renderInTestApp( + + + , + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://github.com', + additionalScope: { + repoWrite: true, + customScopes: { + github: ['workflow'], + }, + }, + }); + + expect(getByText('abc123')).toBeInTheDocument(); + }); + + it('should call the scmAuthApi with the correct params if workspace is nested', async () => { + await renderInTestApp( + + + , + }} + /> + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://github.com', + additionalScope: { + repoWrite: true, + }, + }); + }); + + it('should not call the scmAuthApi if secret is available in the state', async () => { + const secretsKey = 'testKey'; + + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + const secret = secrets[secretsKey]; + return secret ?
{secret}
: null; + }; + + const { getByText } = await renderInTestApp( + + + , + }} + /> + + + , + ); + + await act(async () => { + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + // as we already have a secret in the state, getCredentials should not be called again. + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledTimes(0); + + expect(getByText('abc123')).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx new file mode 100644 index 0000000000..bcb1a0001c --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/RepoOwnerPicker.tsx @@ -0,0 +1,138 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi } from '@backstage/core-plugin-api'; +import { + scmIntegrationsApiRef, + scmAuthApiRef, +} from '@backstage/integration-react'; +import { useEffect, useState, useCallback, useMemo } from 'react'; +import useDebounce from 'react-use/esm/useDebounce'; +import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react'; + +import { RepoOwnerPickerProps } from './schema'; +import { RepoOwnerPickerState } from './types'; +import { DefaultRepoOwnerPicker } from './DefaultRepoOwnerPicker'; +import { GitHubRepoOwnerPicker } from './GitHubRepoOwnerPicker'; + +/** + * The underlying component that is rendered in the form for the `RepoOwnerPicker` + * field extension. + * + * @public + */ +export const RepoOwnerPicker = (props: RepoOwnerPickerProps) => { + const { uiSchema, onChange, rawErrors, formData, schema, required } = props; + const [state, setState] = useState({ + owner: formData || '', + }); + const excludedOwners = useMemo( + () => uiSchema?.['ui:options']?.excludedOwners ?? [], + [uiSchema], + ); + const { host, owner } = state; + + const integrationApi = useApi(scmIntegrationsApiRef); + const scmAuthApi = useApi(scmAuthApiRef); + + const { secrets, setSecrets } = useTemplateSecrets(); + + useDebounce( + async () => { + const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; + + if (!requestUserCredentials || !host) { + return; + } + + // don't show login prompt if secret value is already in state + if (secrets[requestUserCredentials.secretsKey]) { + return; + } + + // user has requested that we use the users credentials + // so lets grab them using the scmAuthApi and pass through + // any additional scopes from the ui:options + const { token } = await scmAuthApi.getCredentials({ + url: `https://${host}`, + additionalScope: { + repoWrite: true, + customScopes: requestUserCredentials.additionalScopes, + }, + }); + + // set the secret using the key provided in the ui:options for use + // in the templating the manifest with ${{ secrets[secretsKey] }} + setSecrets({ [requestUserCredentials.secretsKey]: token }); + }, + 500, + [host, uiSchema], + ); + + useEffect(() => { + if (uiSchema?.['ui:options']?.host) { + const hostUiOption = uiSchema['ui:options'].host; + setState(prevState => ({ ...prevState, host: hostUiOption })); + } + }, [uiSchema]); + + useEffect(() => { + onChange(owner); + }, [owner, onChange]); + + const updateLocalState = useCallback( + (newState: RepoOwnerPickerState) => { + setState(prevState => ({ ...prevState, ...newState })); + }, + [setState], + ); + + const hostType = (host && integrationApi.byHost(host)?.type) ?? null; + + const renderRepoOwnerPicker = () => { + switch (hostType) { + case 'github': + return ( + + ); + default: + return ( + + ); + } + }; + + return renderRepoOwnerPicker(); +}; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/index.ts b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/index.ts new file mode 100644 index 0000000000..d93e5e22e5 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { RepoOwnerPicker } from './RepoOwnerPicker'; +export { + RepoOwnerPickerFieldSchema, + type RepoOwnerPickerUiOptions, + RepoOwnerPickerSchema, +} from './schema'; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/schema.ts b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/schema.ts new file mode 100644 index 0000000000..7931ca1eec --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/schema.ts @@ -0,0 +1,86 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { makeFieldSchema } from '@backstage/plugin-scaffolder-react'; + +export const RepoOwnerPickerFieldSchema = makeFieldSchema({ + output: z => z.string(), + uiOptions: z => + z.object({ + host: z.string().optional(), + excludedOwners: z + .array(z.string()) + .optional() + .describe('List of excluded owners'), + requestUserCredentials: z + .object({ + secretsKey: z + .string() + .describe( + 'Key used within the template secrets context to store the credential', + ), + additionalScopes: z + .object({ + gitea: z + .array(z.string()) + .optional() + .describe('Additional Gitea scopes to request'), + gerrit: z + .array(z.string()) + .optional() + .describe('Additional Gerrit scopes to request'), + github: z + .array(z.string()) + .optional() + .describe('Additional GitHub scopes to request'), + gitlab: z + .array(z.string()) + .optional() + .describe('Additional GitLab scopes to request'), + bitbucket: z + .array(z.string()) + .optional() + .describe('Additional BitBucket scopes to request'), + azure: z + .array(z.string()) + .optional() + .describe('Additional Azure scopes to request'), + }) + .optional() + .describe('Additional permission scopes to request'), + }) + .optional() + .describe( + 'If defined will request user credentials to auth against the given SCM platform', + ), + }), +}); + +/** + * The input props that can be specified under `ui:options` for the + * `RepoOwnerPicker` field extension. + */ +export type RepoOwnerPickerUiOptions = NonNullable< + (typeof RepoOwnerPickerFieldSchema.TProps.uiSchema)['ui:options'] +>; + +export type RepoOwnerPickerProps = typeof RepoOwnerPickerFieldSchema.TProps; + +// This has been duplicated from /plugins/scaffolder/src/components/fields/RepoUrlPicker/schema.ts +// NOTE: There is a bug with this failing validation in the custom field explorer due +// to https://github.com/rjsf-team/react-jsonschema-form/issues/675 even if +// requestUserCredentials is not defined +export const RepoOwnerPickerSchema = RepoOwnerPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/RepoOwnerPicker/types.ts b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/types.ts new file mode 100644 index 0000000000..eceed58df5 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/RepoOwnerPicker/types.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RJSFSchema } from '@rjsf/utils'; + +export interface RepoOwnerPickerState { + host?: string; + owner?: string; +} + +export type BaseRepoOwnerPickerProps = T & { + onChange: (state: RepoOwnerPickerState) => void; + state: RepoOwnerPickerState; + rawErrors: string[]; + isDisabled?: boolean; + required?: boolean; + schema?: RJSFSchema; +}; diff --git a/plugins/scaffolder/src/components/fields/VirtualizedListbox.test.tsx b/plugins/scaffolder/src/components/fields/VirtualizedListbox.test.tsx index 59f311fe88..8a058d5320 100644 --- a/plugins/scaffolder/src/components/fields/VirtualizedListbox.test.tsx +++ b/plugins/scaffolder/src/components/fields/VirtualizedListbox.test.tsx @@ -33,7 +33,7 @@ describe('', () => { aria-expanded="true" class="MuiAutocomplete-root MuiAutocomplete-hasClearIcon MuiAutocomplete-hasPopupIcon" role="combobox" - style="position: relative; height: 18px; width: 100%; overflow: auto; will-change: transform; direction: ltr;" + style="position: relative; height: 18px; width: 100%; overflow: auto; -webkit-overflow-scrolling: touch; will-change: transform; direction: ltr;" >
', () => {
', () => {
', () => {
', () => {
{ expect(screen.getByText('Results per page:')).toBeInTheDocument(); expect(screen.getByText('25')).toBeInTheDocument(); expect(screen.getByText('1-25')).toBeInTheDocument(); - expect(screen.getByLabelText('Next page')).toBeEnabled(); + expect(screen.getByLabelText('Next page')).toBeDisabled(); expect(screen.getByLabelText('Previous page')).toBeDisabled(); }); @@ -176,6 +176,12 @@ describe('SearchPagination', () => { }); it('Set page limit in the context', async () => { + const initialState = { + term: 'a', + types: [], + filters: {}, + }; + await renderInTestApp( { [configApiRef, configApiMock], ]} > - + , @@ -205,7 +211,7 @@ describe('SearchPagination', () => { it('Set page cursor in the context', async () => { const initialState = { - term: '', + term: 'a', types: [], filters: {}, pageCursor: 'MQ==', // page: 1 @@ -253,7 +259,7 @@ describe('SearchPagination', () => { it('Resets page cursor when page limit changes', async () => { const initialState = { - term: '', + term: 'a', types: [], filters: {}, pageCursor: 'Mg==', // page: 2 @@ -280,9 +286,7 @@ describe('SearchPagination', () => { pageCursor: undefined, pageLimit: 10, }), - { - signal: expect.any(AbortSignal), - }, + { signal: expect.any(AbortSignal) }, ); }); }); diff --git a/plugins/search-react/src/components/SearchResultGroup/SearchResultGroup.test.tsx b/plugins/search-react/src/components/SearchResultGroup/SearchResultGroup.test.tsx index cb274be0a0..0f46f15ed4 100644 --- a/plugins/search-react/src/components/SearchResultGroup/SearchResultGroup.test.tsx +++ b/plugins/search-react/src/components/SearchResultGroup/SearchResultGroup.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { screen, waitFor } from '@testing-library/react'; +import { screen, waitFor, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import MenuItem from '@material-ui/core/MenuItem'; @@ -66,7 +66,7 @@ describe('SearchResultGroup', () => { }); it('Renders without exploding', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -96,7 +96,7 @@ describe('SearchResultGroup', () => { }); it('Renders search results from context', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -107,7 +107,9 @@ describe('SearchResultGroup', () => { [analyticsApiRef, analyticsApiMock], ]} > - + } title="Documentation" @@ -128,7 +130,7 @@ describe('SearchResultGroup', () => { }); it('Renders search results using extensions', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -166,7 +168,7 @@ describe('SearchResultGroup', () => { }); it('Defines a default link', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -190,7 +192,7 @@ describe('SearchResultGroup', () => { }); it('Defines a default render result item', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -221,6 +223,10 @@ describe('SearchResultGroup', () => { }); it('Could be customized with no results text', async () => { + query.mockResolvedValue({ + results: [], + }); + await renderInTestApp( { }); it('Could be customized with filters', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -272,7 +278,7 @@ describe('SearchResultGroup', () => { }); it('Could have a text search filter field', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -312,10 +318,10 @@ describe('SearchResultGroup', () => { await userEvent.click(screen.getByText('owner')); - await userEvent.type( - screen.getByRole('textbox'), - '{backspace}{backspace}{backspace}{backspace}techdocs-core', - ); + // Use fireEvent.blur for contentEditable elements since userEvent.type with + // backspace doesn't work properly in jsdom (jsdom limitation, not a bug) + const textbox = screen.getByRole('textbox'); + fireEvent.blur(textbox, { target: { textContent: 'techdocs-core' } }); await waitFor(() => { expect(screen.getByText('techdocs-core')).toBeInTheDocument(); @@ -323,7 +329,7 @@ describe('SearchResultGroup', () => { }); it('Could have a select search filter field', async () => { - query.mockResolvedValueOnce({ + query.mockResolvedValue({ results, }); @@ -376,7 +382,7 @@ describe('SearchResultGroup', () => { }); it('Shows a progress bar when loading results', async () => { - query.mockReturnValueOnce(new Promise(() => {})); + query.mockReturnValue(new Promise(() => {})); await renderInTestApp( { }); it('Does not render result group if no results returned and disableRenderingWithNoResults prop is provided', async () => { - query.mockResolvedValueOnce({ results: [] }); + query.mockResolvedValue({ results: [] }); await renderInTestApp( { }); it('Should render custom component when no results returned', async () => { - query.mockResolvedValueOnce({ results: [] }); + query.mockResolvedValue({ results: [] }); await renderInTestApp( { }); it('Shows an error panel when results rendering fails', async () => { - query.mockRejectedValueOnce(new Error()); + query.mockRejectedValue(new Error()); await renderInTestApp( ( initialValue.pageCursor, ); + const isFirstEmptyMount = useRef(true); const prevTerm = usePrevious(term); const prevFilters = usePrevious(filters); const abortControllerRef = useRef(null); - const result = useAsync(async () => { + const result = useAsync(async (): Promise => { + if (isFirstEmptyMount.current) { + if (!term && !types.length && !Object.keys(filters).length) { + return { + results: [], + numberOfResults: 0, + }; + } + + isFirstEmptyMount.current = false; + } + // Here we cancel the previous request before making a new one if (abortControllerRef.current) { abortControllerRef.current.abort(); diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 017baea2e3..1a10d1c081 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-search +## 1.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## 1.5.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + ## 1.5.1-next.1 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 4e305eb9cb..35d02fec32 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.5.1-next.1", + "version": "1.5.2-next.0", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index 5353fec09e..b129d4ab6c 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -264,8 +264,8 @@ export const searchTranslationRef: TranslationRef< readonly 'searchType.tabs.allTitle': 'All'; readonly 'searchType.allResults': 'All Results'; readonly 'searchType.accordion.collapse': 'Collapse'; - readonly 'searchType.accordion.allTitle': 'All'; readonly 'searchType.accordion.numberOfResults': '{{number}} results'; + readonly 'searchType.accordion.allTitle': 'All'; readonly 'sidebarSearchModal.title': 'Search'; } >; diff --git a/plugins/search/src/components/HomePageComponent/HomePageSearchBar.test.tsx b/plugins/search/src/components/HomePageComponent/HomePageSearchBar.test.tsx index e7c47b7d30..270bdbb2eb 100644 --- a/plugins/search/src/components/HomePageComponent/HomePageSearchBar.test.tsx +++ b/plugins/search/src/components/HomePageComponent/HomePageSearchBar.test.tsx @@ -46,12 +46,7 @@ describe('', () => { }, ); - expect(searchApiMock.query).toHaveBeenCalledWith( - expect.objectContaining({ term: '' }), - { - signal: expect.any(AbortSignal), - }, - ); + expect(searchApiMock.query).not.toHaveBeenCalled(); await userEvent.type(screen.getByLabelText('Search'), 'term{enter}'); diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index 8d8e1bb9b9..9424599130 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { screen } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import userEvent from '@testing-library/user-event'; import { configApiRef } from '@backstage/core-plugin-api'; @@ -63,7 +63,6 @@ describe('SearchModal', () => { ); expect(screen.getByRole('dialog')).toBeInTheDocument(); - expect(searchApiMock.query).toHaveBeenCalledTimes(1); }); it('Should use parent search context if defined', async () => { @@ -106,15 +105,21 @@ describe('SearchModal', () => { ); expect(screen.getByRole('dialog')).toBeInTheDocument(); - expect(searchApiMock.query).toHaveBeenCalledWith( - { - term: '', - filters: {}, - types: [], - pageCursor: undefined, - }, - { signal: expect.any(AbortSignal) }, - ); + + const input = screen.getByLabelText('Search'); + await userEvent.type(input, 'text'); + + await waitFor(() => { + expect(searchApiMock.query).toHaveBeenCalledWith( + { + term: 'text', + filters: {}, + types: [], + pageCursor: undefined, + }, + { signal: expect.any(AbortSignal) }, + ); + }); }); it('Should render a custom Modal correctly', async () => { @@ -146,7 +151,6 @@ describe('SearchModal', () => { }, ); - expect(searchApiMock.query).toHaveBeenCalledTimes(1); await userEvent.keyboard('{Escape}'); expect(toggleModal).toHaveBeenCalledTimes(1); }); diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index 188b7e1ba4..ba15a7f165 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-signals-backend +## 0.3.11 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-events-node@0.4.18 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.11-next.1 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 080fd73c2b..16ff55a7a4 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.3.11-next.1", + "version": "0.3.11", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 8225fe5587..89f3cbfc09 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-signals-node +## 0.1.27 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-events-node@0.4.18 + - @backstage/backend-plugin-api@1.6.0 + ## 0.1.27-next.1 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 6c4c4f7ffe..41df262538 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.27-next.1", + "version": "0.1.27", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/signals-react/CHANGELOG.md b/plugins/signals-react/CHANGELOG.md index 6938e0271b..d8ad46909e 100644 --- a/plugins/signals-react/CHANGELOG.md +++ b/plugins/signals-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-signals-react +## 0.0.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.1 + ## 0.0.18-next.0 ### Patch Changes diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json index fa67692556..debc7647ef 100644 --- a/plugins/signals-react/package.json +++ b/plugins/signals-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-react", - "version": "0.0.18-next.0", + "version": "0.0.18", "description": "Web library for the signals plugin", "backstage": { "role": "web-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index 20fadf416f..2e170fd29d 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals +## 0.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + ## 0.0.26-next.0 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 9a9ae4c9da..6ff62d6943 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.26-next.0", + "version": "0.0.26", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 1f78d1fa4b..1f25e8e7bd 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-techdocs-addons-test-utils +## 2.0.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-techdocs@1.16.2-next.0 + - @backstage/plugin-catalog@1.32.2-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/plugin-search-react@1.10.1 + +## 2.0.0 + +### Major Changes + +- 8d6709e: **BREAKING**: `TechDocsAddonTester.renderWithEffects()` no longer returns a screen; this means that you can no longer grab assertions such as `getByText` from its return value. + + Newer versions of `@testing-library` recommends using the `screen` export for assertions - and removing this from the addon tester contract allows us to more freely iterate on which underlying version of the testing library is being used. + + One notable effect of this, however, is that the `@testing-library` `screen` does NOT support assertions on the shadow DOM, which techdocs relies on. You will therefore want to add a dependency on [the `shadow-dom-testing-library` package](https://github.com/konnorrogers/shadow-dom-testing-library/) in your tests, and using its `screen` and its dedicated `*Shadow*` methods. As an example, if you keep doing `getByText` you will not get matches inside the shadow DOM - switch to `getByShadowText` instead. + + ```ts + import { screen } from 'shadow-dom-testing-library'; + + // ... render the addon ... + await TechDocsAddonTester.buildAddonsInTechDocs([]) + .withDom(TEST_CONTENT) + .renderWithEffects(); + + expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument(); + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/plugin-techdocs@1.16.1 + - @backstage/plugin-catalog@1.32.1 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/test-utils@1.7.14 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + ## 2.0.0-next.1 ### Major Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 9045f33b03..be91b53de3 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": "2.0.0-next.1", + "version": "2.0.1-next.0", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 46bbd1df35..f51e4c5526 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-techdocs-backend +## 2.1.4-next.1 + +### Patch Changes + +- b6ff2a5: Some AWS `publisher` config options such as `region`, `endpoint`, `accountId` are now marked as `@visibility backend` instead of `secret`. +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.1 + - @backstage/integration@1.19.2-next.0 + - @backstage/plugin-techdocs-node@1.13.11-next.0 + +## 2.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/catalog-client@1.12.1 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration@1.19.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-node@1.20.1 + - @backstage/plugin-techdocs-node@1.13.10 + +## 2.1.3 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 2bae83a: Corrected `ErrorCallback` type to work with Node 22 types +- 592361e: The `techdocs` config is now marked as optional. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-techdocs-node@1.13.10 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/plugin-catalog-node@1.20.1 + ## 2.1.3-next.2 ### Patch Changes diff --git a/plugins/techdocs-backend/config.d.ts b/plugins/techdocs-backend/config.d.ts index 1520ad70ec..5d3baa940a 100644 --- a/plugins/techdocs-backend/config.d.ts +++ b/plugins/techdocs-backend/config.d.ts @@ -100,7 +100,6 @@ export interface Config { * If account ID is not set and no credentials are set, environment variables or aws config file will be used to authenticate. * @see https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html * @see https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-shared.html - * @visibility secret */ accountId?: string; /** @@ -141,14 +140,12 @@ export interface Config { * (Optional) AWS Region. * If not set, AWS_REGION environment variable or aws config file will be used. * @see https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html - * @visibility secret */ region?: string; /** * (Optional) AWS Endpoint. * The endpoint URI to send requests to. The default endpoint is built from the configured region. * @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property - * @visibility secret */ endpoint?: string; /** diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 62d1e82240..ddbe467f3b 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "2.1.3-next.2", + "version": "2.1.4-next.1", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 922e295257..4ec64bf527 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 1.1.31 + +### Patch Changes + +- 8d6709e: Updated tests to match test-utils change +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-techdocs-react@1.3.6 + ## 1.1.31-next.1 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 7d04f6268a..ea884f5360 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.31-next.1", + "version": "1.1.32-next.0", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index c05eadf12a..1c4d3a06fe 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-node +## 1.13.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + +## 1.13.10 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- 703f8c0: There was an issue in the uploading of large size files to the AWS S3. We have modified the logic by adding retry along with multipart uploading functionality. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/backend-plugin-api@1.6.0 + ## 1.13.10-next.1 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 3b3d3f9539..8fdf278c37 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.13.10-next.1", + "version": "1.13.11-next.0", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 426ff95859..1763386235 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-techdocs-react +## 1.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/core-plugin-api@1.12.1 + ## 1.3.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index fa8d2c5935..44bed4646f 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.3.6-next.0", + "version": "1.3.6", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 5d15b4a023..8ee8a0ccac 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-techdocs +## 1.16.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.19.2-next.0 + - @backstage/integration-react@1.2.14-next.0 + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/plugin-search-react@1.10.1 + +## 1.16.1 + +### Patch Changes + +- f3f84f1: Minor extension type updates after frontend API bump +- 5c33821: Fixed schema type for additionalAllowedURIProtocols +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- 592361e: The `techdocs` config is now marked as optional. +- Updated dependencies + - @backstage/integration@1.19.0 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/plugin-search-react@1.10.1 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/integration-react@1.2.13 + - @backstage/plugin-auth-react@0.1.22 + - @backstage/plugin-techdocs-react@1.3.6 + ## 1.16.1-next.2 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index ac3917eeae..9593147e26 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.16.1-next.2", + "version": "1.16.2-next.0", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/techdocs/src/reader/transformers/handleMetaRedirects.test.ts b/plugins/techdocs/src/reader/transformers/handleMetaRedirects.test.ts index 0be1773846..00180464cf 100644 --- a/plugins/techdocs/src/reader/transformers/handleMetaRedirects.test.ts +++ b/plugins/techdocs/src/reader/transformers/handleMetaRedirects.test.ts @@ -21,21 +21,13 @@ import { screen } from '@testing-library/react'; describe('handleMetaRedirects', () => { const navigate = jest.fn(); - const setUpNewTestShadowDom = async ( - html: string, - rootHref: string, - rootPath: string, - ) => { + const setUpNewTestShadowDom = async (html: string, rootHref: string) => { const entityName = 'testEntity'; - // Mock window.location.href for each test - Object.defineProperty(window, 'location', { - value: { - href: rootHref, - pathname: rootPath, - hostname: 'localhost', - }, - writable: true, - }); + // Use history.replaceState to change location (jsdom 27+ doesn't allow redefining location) + // Jest's jsdom starts at http://localhost/, so replaceState updates the pathname while + // keeping hostname and origin as 'localhost'. + const url = new URL(rootHref); + history.replaceState(null, '', `${url.pathname}${url.search}${url.hash}`); return await createTestShadowDom(html, { preTransformers: [], postTransformers: [handleMetaRedirects(navigate, entityName)], @@ -55,7 +47,6 @@ describe('handleMetaRedirects', () => { await setUpNewTestShadowDom( ``, 'http://localhost/docs/default/component/testEntity/subpath', - '/docs/default/component/testEntity/subpath', ); expect( @@ -73,7 +64,6 @@ describe('handleMetaRedirects', () => { await setUpNewTestShadowDom( ``, 'http://localhost/docs/default/component/testEntity/subpath', - '/docs/default/component/testEntity/subpath', ); expect( @@ -91,7 +81,6 @@ describe('handleMetaRedirects', () => { await setUpNewTestShadowDom( ``, 'http://localhost/docs/default/component/testEntity/subpath', - '/docs/default/component/testEntity/subpath', ); expect( @@ -107,7 +96,6 @@ describe('handleMetaRedirects', () => { await setUpNewTestShadowDom( ``, 'http://localhost/docs/default/component/testEntity/subpath', - '/docs/default/component/testEntity/subpath', ); jest.runAllTimers(); diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index dcca2b7ae7..166490f4e9 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-user-settings-backend +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.14.1-next.0 + - @backstage/backend-plugin-api@1.6.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.10 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.3.9 + +### Patch Changes + +- de96a60: chore(deps): bump `express` from 4.21.2 to 4.22.0 +- Updated dependencies + - @backstage/plugin-auth-node@0.6.10 + - @backstage/backend-defaults@0.14.0 + - @backstage/plugin-signals-node@0.1.27 + - @backstage/backend-plugin-api@1.6.0 + ## 0.3.9-next.1 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 6549870a80..53689197fc 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.3.9-next.1", + "version": "0.3.10-next.0", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index e28fb0427b..5d51b56c25 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-user-settings +## 0.8.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.21.5-next.0 + - @backstage/frontend-plugin-api@0.13.2 + +## 0.8.30 + +### Patch Changes + +- d02db50: Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. +- Updated dependencies + - @backstage/core-app-api@1.19.3 + - @backstage/frontend-plugin-api@0.13.2 + - @backstage/core-components@0.18.4 + - @backstage/plugin-catalog-react@1.21.4 + - @backstage/core-plugin-api@1.12.1 + - @backstage/theme@0.7.1 + - @backstage/plugin-signals-react@0.0.18 + ## 0.8.30-next.0 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index ce73f21d5e..7ab451b0b5 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.8.30-next.0", + "version": "0.8.31-next.0", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/yarn.lock b/yarn.lock index 586916e80c..393cd37bd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,13 @@ __metadata: languageName: node linkType: hard +"@acemir/cssom@npm:^0.9.28": + version: 0.9.28 + resolution: "@acemir/cssom@npm:0.9.28" + checksum: 10/429faa2af7bffdcf3311e984f6b8ced77bf58d936e0e9a22c2fc892a84e54d2c8cbd71ae3a979ef54241509ac7c866cb880d919e3e713e64c865a1cd4ede3a1f + languageName: node + linkType: hard + "@adobe/css-tools@npm:^4.4.0": version: 4.4.0 resolution: "@adobe/css-tools@npm:4.4.0" @@ -263,6 +270,52 @@ __metadata: languageName: node linkType: hard +"@asamuzakjp/css-color@npm:^3.2.0": + version: 3.2.0 + resolution: "@asamuzakjp/css-color@npm:3.2.0" + dependencies: + "@csstools/css-calc": "npm:^2.1.3" + "@csstools/css-color-parser": "npm:^3.0.9" + "@csstools/css-parser-algorithms": "npm:^3.0.4" + "@csstools/css-tokenizer": "npm:^3.0.3" + lru-cache: "npm:^10.4.3" + checksum: 10/870f661460173174fef8bfebea0799ba26566f3aa7b307e5adabb7aae84fed2da68e40080104ed0c83b43c5be632ee409e65396af13bfe948a3ef4c2c729ecd9 + languageName: node + linkType: hard + +"@asamuzakjp/css-color@npm:^4.1.0": + version: 4.1.0 + resolution: "@asamuzakjp/css-color@npm:4.1.0" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + lru-cache: "npm:^11.2.2" + checksum: 10/e76b57fff34b958e224662d2afb19d23bc6c95d6ea40055e23a8f7417ae79904b7741655bbe6a883c09d5ee68ebb20e9313036aed3680fe85e383e0527397566 + languageName: node + linkType: hard + +"@asamuzakjp/dom-selector@npm:^6.7.6": + version: 6.7.6 + resolution: "@asamuzakjp/dom-selector@npm:6.7.6" + dependencies: + "@asamuzakjp/nwsapi": "npm:^2.3.9" + bidi-js: "npm:^1.0.3" + css-tree: "npm:^3.1.0" + is-potential-custom-element-name: "npm:^1.0.1" + lru-cache: "npm:^11.2.4" + checksum: 10/91a479f5f59a3b1b23f46407d874882c05b50e72316e57af105c88603fb1008120c46c7fe7504c5be556ea4c9a68ee10aee43433bd8d34f000b9aaf6dcae4d5c + languageName: node + linkType: hard + +"@asamuzakjp/nwsapi@npm:^2.3.9": + version: 2.3.9 + resolution: "@asamuzakjp/nwsapi@npm:2.3.9" + checksum: 10/95a6d1c102e1117fe818da087fcc5b914d23e0699855991bae50b891435dd1945ad7d384198f8bcf616207fd85b7ec32e3db6b96e9309d84c6903b8dc4151e34 + languageName: node + linkType: hard + "@asyncapi/avro-schema-parser@npm:^3.0.24": version: 3.0.24 resolution: "@asyncapi/avro-schema-parser@npm:3.0.24" @@ -2238,7 +2291,7 @@ __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.27.1, @babel/code-frame@npm:^7.8.3": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.27.1, @babel/code-frame@npm:^7.8.3": version: 7.27.1 resolution: "@babel/code-frame@npm:7.27.1" dependencies: @@ -2256,39 +2309,39 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.24.7, @babel/core@npm:^7.28.0": - version: 7.28.4 - resolution: "@babel/core@npm:7.28.4" +"@babel/core@npm:^7.23.9, @babel/core@npm:^7.24.7, @babel/core@npm:^7.27.4, @babel/core@npm:^7.28.0": + version: 7.28.5 + resolution: "@babel/core@npm:7.28.5" dependencies: "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.3" + "@babel/generator": "npm:^7.28.5" "@babel/helper-compilation-targets": "npm:^7.27.2" "@babel/helper-module-transforms": "npm:^7.28.3" "@babel/helpers": "npm:^7.28.4" - "@babel/parser": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.5" "@babel/template": "npm:^7.27.2" - "@babel/traverse": "npm:^7.28.4" - "@babel/types": "npm:^7.28.4" + "@babel/traverse": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" "@jridgewell/remapping": "npm:^2.3.5" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10/0593295241fac9be567145ef16f3858d34fc91390a9438c6d47476be9823af4cc0488c851c59702dd46b968e9fd46d17ddf0105ea30195ca85f5a66b4044c519 + checksum: 10/2f1e224125179f423f4300d605a0c5a3ef315003281a63b1744405b2605ee2a2ffc5b1a8349aa4f262c72eca31c7e1802377ee04ad2b852a2c88f8ace6cac324 languageName: node linkType: hard -"@babel/generator@npm:^7.28.3, @babel/generator@npm:^7.7.2": - version: 7.28.3 - resolution: "@babel/generator@npm:7.28.3" +"@babel/generator@npm:^7.27.5, @babel/generator@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/generator@npm:7.28.5" dependencies: - "@babel/parser": "npm:^7.28.3" - "@babel/types": "npm:^7.28.2" + "@babel/parser": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" "@jridgewell/gen-mapping": "npm:^0.3.12" "@jridgewell/trace-mapping": "npm:^0.3.28" jsesc: "npm:^3.0.2" - checksum: 10/d00d1e6b51059e47594aab7920b88ec6fcef6489954a9172235ab57ad2e91b39c95376963a6e2e4cc7e8b88fa4f931018f71f9ab32bbc9c0bc0de35a0231f26c + checksum: 10/ae618f0a17a6d76c3983e1fd5d9c2f5fdc07703a119efdb813a7d9b8ad4be0a07d4c6f0d718440d2de01a68e321f64e2d63c77fc5d43ae47ae143746ef28ac1f languageName: node linkType: hard @@ -2380,10 +2433,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.25.9 - resolution: "@babel/helper-plugin-utils@npm:7.25.9" - checksum: 10/e347d87728b1ab10b6976d46403941c8f9008c045ea6d99997a7ffca7b852dc34b6171380f7b17edf94410e0857ff26f3a53d8618f11d73744db86e8ca9b8c64 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.27.1 + resolution: "@babel/helper-plugin-utils@npm:7.27.1" + checksum: 10/96136c2428888e620e2ec493c25888f9ceb4a21099dcf3dd4508ea64b58cdedbd5a9fb6c7b352546de84d6c24edafe482318646932a22c449ebd16d16c22d864 languageName: node linkType: hard @@ -2427,10 +2480,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-identifier@npm:7.27.1" - checksum: 10/75041904d21bdc0cd3b07a8ac90b11d64cd3c881e89cb936fa80edd734bf23c35e6bd1312611e8574c4eab1f3af0f63e8a5894f4699e9cfdf70c06fcf4252320 +"@babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 10/8e5d9b0133702cfacc7f368bf792f0f8ac0483794877c6dca5fcb73810ee138e27527701826fb58a40a004f3a5ec0a2f3c3dd5e326d262530b119918f3132ba7 languageName: node linkType: hard @@ -2463,14 +2516,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.26.7, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.27.5, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4": - version: 7.28.4 - resolution: "@babel/parser@npm:7.28.4" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.26.7, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.27.5, @babel/parser@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/parser@npm:7.28.5" dependencies: - "@babel/types": "npm:^7.28.4" + "@babel/types": "npm:^7.28.5" bin: parser: ./bin/babel-parser.js - checksum: 10/f54c46213ef180b149f6a17ea765bf40acc1aebe2009f594e2a283aec69a190c6dda1fdf24c61a258dbeb903abb8ffb7a28f1a378f8ab5d333846ce7b7e23bf1 + checksum: 10/8d9bfb437af6c97a7f6351840b9ac06b4529ba79d6d3def24d6c2996ab38ff7f1f9d301e868ca84a93a3050fadb3d09dbc5105b24634cd281671ac11eebe8df7 languageName: node linkType: hard @@ -2496,7 +2549,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-class-properties@npm:^7.8.3": +"@babel/plugin-syntax-class-properties@npm:^7.12.13": version: 7.12.13 resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" dependencies: @@ -2507,6 +2560,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + "@babel/plugin-syntax-flow@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-syntax-flow@npm:7.24.7" @@ -2518,7 +2582,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-meta@npm:^7.8.3": +"@babel/plugin-syntax-import-attributes@npm:^7.24.7": + version: 7.27.1 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/97973982fff1bbf86b3d1df13380567042887c50e2ae13a400d02a8ff2c9742a60a75e279bfb73019e1cd9710f04be5e6ab81f896e6678dcfcec8b135e8896cf + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" dependencies: @@ -2540,18 +2615,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.24.7, @babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.24.7 - resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" +"@babel/plugin-syntax-jsx@npm:^7.24.7, @babel/plugin-syntax-jsx@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-syntax-jsx@npm:7.27.1" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.27.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/a93516ae5b34868ab892a95315027d4e5e38e8bd1cfca6158f2974b0901cbb32bbe64ea10ad5b25f919ddc40c6d8113c4823372909c9c9922170c12b0b1acecb + checksum: 10/c6d1324cff286a369aa95d99b8abd21dd07821b5d3affd5fe7d6058c84cff9190743287826463ee57a7beecd10fa1e4bc99061df532ee14e188c1c8937b13e3a languageName: node linkType: hard -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" dependencies: @@ -2573,7 +2648,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-numeric-separator@npm:^7.8.3": +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" dependencies: @@ -2617,7 +2692,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-top-level-await@npm:^7.8.3": +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" dependencies: @@ -2628,14 +2714,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.25.9 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" +"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-syntax-typescript@npm:7.27.1" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.27.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 + checksum: 10/87836f7e32af624c2914c73cd6b9803cf324e07d43f61dbb973c6a86f75df725e12540d91fac7141c14b697aa9268fd064220998daced156e96ac3062d7afb41 languageName: node linkType: hard @@ -2787,7 +2873,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": +"@babel/template@npm:^7.27.2": version: 7.27.2 resolution: "@babel/template@npm:7.27.2" dependencies: @@ -2798,28 +2884,28 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4, @babel/traverse@npm:^7.4.5": - version: 7.28.4 - resolution: "@babel/traverse@npm:7.28.4" +"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.5, @babel/traverse@npm:^7.4.5": + version: 7.28.5 + resolution: "@babel/traverse@npm:7.28.5" dependencies: "@babel/code-frame": "npm:^7.27.1" - "@babel/generator": "npm:^7.28.3" + "@babel/generator": "npm:^7.28.5" "@babel/helper-globals": "npm:^7.28.0" - "@babel/parser": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.5" "@babel/template": "npm:^7.27.2" - "@babel/types": "npm:^7.28.4" + "@babel/types": "npm:^7.28.5" debug: "npm:^4.3.1" - checksum: 10/c3099364b7b1c36bcd111099195d4abeef16499e5defb1e56766b754e8b768c252e856ed9041665158aa1b31215fc6682632756803c8fa53405381ec08c4752b + checksum: 10/1fce426f5ea494913c40f33298ce219708e703f71cac7ac045ebde64b5a7b17b9275dfa4e05fb92c3f123136913dff62c8113172f4a5de66dab566123dbe7437 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.27.1, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4, @babel/types@npm:^7.3.3": - version: 7.28.4 - resolution: "@babel/types@npm:7.28.4" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/types@npm:7.28.5" dependencies: "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.27.1" - checksum: 10/db50bf257aafa5d845ad16dae0587f57d596e4be4cbb233ea539976a4c461f9fbcc0bf3d37adae3f8ce5dcb4001462aa608f3558161258b585f6ce6ce21a2e45 + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10/4256bb9fb2298c4f9b320bde56e625b7091ea8d2433d98dcf524d4086150da0b6555aabd7d0725162670614a9ac5bf036d1134ca13dedc9707f988670f1362d7 languageName: node linkType: hard @@ -3212,6 +3298,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" + "@jest/environment-jsdom-abstract": "npm:^30.0.0" "@manypkg/get-packages": "npm:^1.1.3" "@module-federation/enhanced": "npm:^0.9.0" "@octokit/request": "npm:^8.0.0" @@ -3226,16 +3313,16 @@ __metadata: "@spotify/eslint-config-base": "npm:^15.0.0" "@spotify/eslint-config-react": "npm:^15.0.0" "@spotify/eslint-config-typescript": "npm:^15.0.0" - "@swc/core": "npm:^1.3.46" - "@swc/helpers": "npm:^0.5.0" - "@swc/jest": "npm:^0.2.22" + "@swc/core": "npm:^1.15.6" + "@swc/helpers": "npm:^0.5.17" + "@swc/jest": "npm:^0.2.39" "@types/cross-spawn": "npm:^6.0.2" "@types/ejs": "npm:^3.1.3" "@types/express": "npm:^4.17.6" "@types/fs-extra": "npm:^11.0.0" "@types/http-proxy": "npm:^1.17.4" "@types/inquirer": "npm:^8.1.3" - "@types/jest": "npm:^29.5.11" + "@types/jest": "npm:^30.0.0" "@types/node": "npm:^22.13.14" "@types/npm-packlist": "npm:^3.0.0" "@types/recursive-readdir": "npm:^2.2.0" @@ -3285,11 +3372,9 @@ __metadata: handlebars: "npm:^4.7.3" html-webpack-plugin: "npm:^5.6.3" inquirer: "npm:^8.2.0" - jest: "npm:^29.7.0" - jest-cli: "npm:^29.7.0" + jest: "npm:^30.2.0" jest-css-modules: "npm:^2.1.0" - jest-environment-jsdom: "npm:^29.0.2" - jest-runtime: "npm:^29.0.2" + jsdom: "npm:^27.1.0" json-schema: "npm:^0.4.0" lodash: "npm:^4.17.21" mini-css-extract-plugin: "npm:^2.4.2" @@ -3332,16 +3417,22 @@ __metadata: zod: "npm:^3.22.4" zod-validation-error: "npm:^3.4.0" peerDependencies: + "@jest/environment-jsdom-abstract": ^30.0.0 "@module-federation/enhanced": ^0.9.0 "@pmmmwh/react-refresh-webpack-plugin": ^0.6.0 esbuild-loader: ^4.0.0 eslint-webpack-plugin: ^4.2.0 fork-ts-checker-webpack-plugin: ^9.0.0 + jest: ^29.0.0 || ^30.0.0 + jest-environment-jsdom: "*" + jsdom: ^27.1.0 mini-css-extract-plugin: ^2.4.2 terser-webpack-plugin: ^5.1.3 webpack: ~5.103.0 webpack-dev-server: ^5.0.0 peerDependenciesMeta: + "@jest/environment-jsdom-abstract": + optional: true "@module-federation/enhanced": optional: true "@pmmmwh/react-refresh-webpack-plugin": @@ -3352,6 +3443,10 @@ __metadata: optional: true fork-ts-checker-webpack-plugin: optional: true + jest-environment-jsdom: + optional: true + jsdom: + optional: true mini-css-extract-plugin: optional: true terser-webpack-plugin: @@ -3403,7 +3498,7 @@ __metadata: json-schema-traverse: "npm:^1.0.0" lodash: "npm:^4.17.21" minimist: "npm:^1.2.5" - msw: "npm:^1.0.0" + msw: "npm:^2.0.0" typescript-json-schema: "npm:^0.67.0" yaml: "npm:^2.0.0" zen-observable: "npm:^0.10.0" @@ -5702,7 +5797,7 @@ __metadata: content-type: "npm:^1.0.5" cross-fetch: "npm:^4.0.0" express: "npm:^4.22.0" - msw: "npm:^1.0.0" + msw: "npm:^2.0.0" uri-template: "npm:^2.0.0" languageName: unknown linkType: soft @@ -5719,7 +5814,7 @@ __metadata: "@opentelemetry/api": "npm:^1.9.0" "@opentelemetry/core": "npm:^1.29.0" "@types/express": "npm:^4.17.6" - eventsource: "npm:^3.0.6" + eventsource: "npm:^4.0.0" express: "npm:^4.22.0" http-proxy-middleware: "npm:^3.0.3" wait-for-expect: "npm:^3.0.2" @@ -5950,7 +6045,7 @@ __metadata: kubernetes-models: "npm:^4.3.1" lodash: "npm:^4.17.21" luxon: "npm:^3.0.0" - msw: "npm:^1.3.1" + msw: "npm:^2.0.0" react: "npm:^18.0.2" react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" @@ -6091,7 +6186,7 @@ __metadata: "@backstage/plugin-notifications-node": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" - "@faker-js/faker": "npm:^8.4.1" + "@faker-js/faker": "npm:^10.0.0" "@opentelemetry/api": "npm:^1.9.0" "@slack/bolt": "npm:^3.21.4" "@slack/types": "npm:^2.14.0" @@ -7848,7 +7943,7 @@ __metadata: "@types/react-dom": "npm:^18.0.0" chalk: "npm:^5.4.1" clsx: "npm:^2.1.1" - eslint-plugin-storybook: "npm:^9.1.7" + eslint-plugin-storybook: "npm:^10.1.9" glob: "npm:^11.0.1" globals: "npm:^15.11.0" lightningcss: "npm:^1.29.1" @@ -7857,7 +7952,7 @@ __metadata: react-aria-components: "npm:^1.13.0" react-dom: "npm:^18.0.2" react-router-dom: "npm:^6.3.0" - storybook: "npm:^9.1.7" + storybook: "npm:^10.1.10" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -8287,6 +8382,61 @@ __metadata: languageName: node linkType: hard +"@csstools/color-helpers@npm:^5.1.0": + version: 5.1.0 + resolution: "@csstools/color-helpers@npm:5.1.0" + checksum: 10/0138b3d5ccbe77aeccf6721fd008a53523c70e932f0c82dca24a1277ca780447e1d8357da47512ebf96358476f8764de57002f3e491920d67e69202f5a74c383 + languageName: node + linkType: hard + +"@csstools/css-calc@npm:^2.1.3, @csstools/css-calc@npm:^2.1.4": + version: 2.1.4 + resolution: "@csstools/css-calc@npm:2.1.4" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10/06975b650c0f44c60eeb7afdb3fd236f2dd607b2c622e0bc908d3f54de39eb84e0692833320d03dac04bd6c1ab0154aa3fa0dd442bd9e5f917cf14d8e2ba8d74 + languageName: node + linkType: hard + +"@csstools/css-color-parser@npm:^3.0.9, @csstools/css-color-parser@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/css-color-parser@npm:3.1.0" + dependencies: + "@csstools/color-helpers": "npm:^5.1.0" + "@csstools/css-calc": "npm:^2.1.4" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10/4741095fdc4501e8e7ada4ed14fbf9dbbe6fea9b989818790ebca15657c29c62defbebacf18592cde2aa638a1d098bbe86d742d2c84ba932fbc00fac51cb8805 + languageName: node + linkType: hard + +"@csstools/css-parser-algorithms@npm:^3.0.4, @csstools/css-parser-algorithms@npm:^3.0.5": + version: 3.0.5 + resolution: "@csstools/css-parser-algorithms@npm:3.0.5" + peerDependencies: + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10/e93083b5cb36a3c1e7a47ce10cf62961d05bd1e4c608bb3ee50186ff740157ab0ec16a3956f7b86251efd10703034d849693201eea858ae904848c68d2d46ada + languageName: node + linkType: hard + +"@csstools/css-syntax-patches-for-csstree@npm:1.0.14": + version: 1.0.14 + resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.0.14" + peerDependencies: + postcss: ^8.4 + checksum: 10/c783d5db307552f483d95266452a7765ca138a9e64f12d013c63e960c9c8abbf82c899a34028af1f5ad714e0e94edd97b1aa31784923c1d7d1756d775c3c1d0a + languageName: node + linkType: hard + +"@csstools/css-tokenizer@npm:^3.0.3, @csstools/css-tokenizer@npm:^3.0.4": + version: 3.0.4 + resolution: "@csstools/css-tokenizer@npm:3.0.4" + checksum: 10/eb6c84c086312f6bb8758dfe2c85addd7475b0927333c5e39a4d59fb210b9810f8c346972046f95e60a721329cffe98895abe451e51de753ad1ca7a8c24ec65f + languageName: node + linkType: hard + "@dabh/diagnostics@npm:^2.0.8": version: 2.0.8 resolution: "@dabh/diagnostics@npm:2.0.8" @@ -8391,7 +8541,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/core@npm:^1.5.0, @emnapi/core@npm:^1.7.1": +"@emnapi/core@npm:^1.4.3, @emnapi/core@npm:^1.5.0, @emnapi/core@npm:^1.7.1": version: 1.7.1 resolution: "@emnapi/core@npm:1.7.1" dependencies: @@ -8401,7 +8551,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.5.0, @emnapi/runtime@npm:^1.7.1": +"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.5.0, @emnapi/runtime@npm:^1.7.1": version: 1.7.1 resolution: "@emnapi/runtime@npm:1.7.1" dependencies: @@ -9015,10 +9165,10 @@ __metadata: languageName: node linkType: hard -"@faker-js/faker@npm:^8.4.1": - version: 8.4.1 - resolution: "@faker-js/faker@npm:8.4.1" - checksum: 10/5983c2ea64f26055ad6648de748878e11ebe2fb751e3c7435ae141cdffabc2dccfe4c4f49da69a3d2add71e21b415c683ac5fba196fab0d5ed6779fbec436c80 +"@faker-js/faker@npm:^10.0.0": + version: 10.1.0 + resolution: "@faker-js/faker@npm:10.1.0" + checksum: 10/3332795debec5793dfaea79e740ed44bd7d94fb43cea8b1bd5d59af19f15c4a9533fa696cfebf024a9bba5d9d1a8a28cde40a92670c03cc11170a3025e551e65 languageName: node linkType: hard @@ -10107,10 +10257,10 @@ __metadata: languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2": - version: 0.1.2 - resolution: "@istanbuljs/schema@npm:0.1.2" - checksum: 10/e4a7fffc72fb2cfe2edfee8a09f68b2da18b1ab328a29d8be2933681f9e36103f0b083a5ae07129f4de26296eb7c2a1cc144cfea6cdb47f871a69766947144d3 +"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 10/a9b1e49acdf5efc2f5b2359f2df7f90c5c725f2656f16099e8b2cd3a000619ecca9fc48cf693ba789cf0fd989f6e0df6a22bc05574be4223ecdbb7997d04384b languageName: node linkType: hard @@ -10123,58 +10273,58 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/console@npm:29.7.0" +"@jest/console@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/console@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - chalk: "npm:^4.0.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" + chalk: "npm:^4.1.2" + jest-message-util: "npm:30.2.0" + jest-util: "npm:30.2.0" slash: "npm:^3.0.0" - checksum: 10/4a80c750e8a31f344233cb9951dee9b77bf6b89377cb131f8b3cde07ff218f504370133a5963f6a786af4d2ce7f85642db206ff7a15f99fe58df4c38ac04899e + checksum: 10/7cda9793962afa5c7fcfdde0ff5012694683b17941ee3c6a55ea9fd9a02f1c51ec4b4c767b867e1226f85a26af1d0f0d72c6a344e34c5bc4300312ebffd6e50b languageName: node linkType: hard -"@jest/core@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/core@npm:29.7.0" +"@jest/core@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/core@npm:30.2.0" dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/reporters": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/console": "npm:30.2.0" + "@jest/pattern": "npm:30.0.1" + "@jest/reporters": "npm:30.2.0" + "@jest/test-result": "npm:30.2.0" + "@jest/transform": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-changed-files: "npm:^29.7.0" - jest-config: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-resolve-dependencies: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.2.0" + exit-x: "npm:^0.2.2" + graceful-fs: "npm:^4.2.11" + jest-changed-files: "npm:30.2.0" + jest-config: "npm:30.2.0" + jest-haste-map: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-regex-util: "npm:30.0.1" + jest-resolve: "npm:30.2.0" + jest-resolve-dependencies: "npm:30.2.0" + jest-runner: "npm:30.2.0" + jest-runtime: "npm:30.2.0" + jest-snapshot: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-validate: "npm:30.2.0" + jest-watcher: "npm:30.2.0" + micromatch: "npm:^4.0.8" + pretty-format: "npm:30.2.0" slash: "npm:^3.0.0" - strip-ansi: "npm:^6.0.0" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - checksum: 10/ab6ac2e562d083faac7d8152ec1cc4eccc80f62e9579b69ed40aedf7211a6b2d57024a6cd53c4e35fd051c39a236e86257d1d99ebdb122291969a0a04563b51e + checksum: 10/6763bb1efd937778f009821cd94c3705d3c31a156258a224b8745c1e0887976683f5413745ffb361b526f0fa2692e36aaa963aa197cc77ba932cff9d6d28af9d languageName: node linkType: hard @@ -10187,60 +10337,95 @@ __metadata: languageName: node linkType: hard -"@jest/environment@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/environment@npm:29.7.0" +"@jest/diff-sequences@npm:30.0.1": + version: 30.0.1 + resolution: "@jest/diff-sequences@npm:30.0.1" + checksum: 10/0ddb7c7ba92d6057a2ee51a9cfc2155b77cca707fe959167466ea02dcb0687018cc3c22b9622f25f3a417d6ad370e2d4dcfedf9f1410dc9c02954a7484423cc7 + languageName: node + linkType: hard + +"@jest/environment-jsdom-abstract@npm:^30.0.0": + version: 30.2.0 + resolution: "@jest/environment-jsdom-abstract@npm:30.2.0" dependencies: - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/environment": "npm:30.2.0" + "@jest/fake-timers": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + "@types/jsdom": "npm:^21.1.7" "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - checksum: 10/90b5844a9a9d8097f2cf107b1b5e57007c552f64315da8c1f51217eeb0a9664889d3f145cdf8acf23a84f4d8309a6675e27d5b059659a004db0ea9546d1c81a8 + jest-mock: "npm:30.2.0" + jest-util: "npm:30.2.0" + peerDependencies: + canvas: ^3.0.0 + jsdom: "*" + peerDependenciesMeta: + canvas: + optional: true + checksum: 10/65a9c8504f213f4d125956383ffe6c4e566cfb0ff2fe67783adf9ebde33f772339e61fdd98ddc2bbae3029e3356d2386abedb9d101aa95d6fd51fabac38bebe0 languageName: node linkType: hard -"@jest/expect-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect-utils@npm:29.7.0" +"@jest/environment@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/environment@npm:30.2.0" dependencies: - jest-get-type: "npm:^29.6.3" - checksum: 10/ef8d379778ef574a17bde2801a6f4469f8022a46a5f9e385191dc73bb1fc318996beaed4513fbd7055c2847227a1bed2469977821866534593a6e52a281499ee - languageName: node - linkType: hard - -"@jest/expect@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect@npm:29.7.0" - dependencies: - expect: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - checksum: 10/fea6c3317a8da5c840429d90bfe49d928e89c9e89fceee2149b93a11b7e9c73d2f6e4d7cdf647163da938fc4e2169e4490be6bae64952902bc7a701033fd4880 - languageName: node - linkType: hard - -"@jest/fake-timers@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/fake-timers@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - "@sinonjs/fake-timers": "npm:^10.0.2" + "@jest/fake-timers": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9b394e04ffc46f91725ecfdff34c4e043eb7a16e1d78964094c9db3fde0b1c8803e45943a980e8c740d0a3d45661906de1416ca5891a538b0660481a3a828c27 + jest-mock: "npm:30.2.0" + checksum: 10/e168a4ff328980eb9fde5e43aea80807fd0b2dbd4579ae8f68a03415a1e58adf5661db298054fa2351c7cb2b5a74bf67b8ab996656cf5927d0b0d0b6e2c2966b languageName: node linkType: hard -"@jest/globals@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/globals@npm:29.7.0" +"@jest/expect-utils@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/expect-utils@npm:30.2.0" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - jest-mock: "npm:^29.7.0" - checksum: 10/97dbb9459135693ad3a422e65ca1c250f03d82b2a77f6207e7fa0edd2c9d2015fbe4346f3dc9ebff1678b9d8da74754d4d440b7837497f8927059c0642a22123 + "@jest/get-type": "npm:30.1.0" + checksum: 10/f2442f1bceb3411240d0f16fd0074377211b4373d3b8b2dc28929e861b6527a6deb403a362c25afa511d933cda4dfbdc98d4a08eeb51ee4968f7cb0299562349 + languageName: node + linkType: hard + +"@jest/expect@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/expect@npm:30.2.0" + dependencies: + expect: "npm:30.2.0" + jest-snapshot: "npm:30.2.0" + checksum: 10/d950d95a64d5c6a39d56171dabb8dbe59423096231bb4f21d8ee0019878e6626701ac9d782803dc2589e2799ed39704031f818533f8a3e571b57032eafa85d12 + languageName: node + linkType: hard + +"@jest/fake-timers@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/fake-timers@npm:30.2.0" + dependencies: + "@jest/types": "npm:30.2.0" + "@sinonjs/fake-timers": "npm:^13.0.0" + "@types/node": "npm:*" + jest-message-util: "npm:30.2.0" + jest-mock: "npm:30.2.0" + jest-util: "npm:30.2.0" + checksum: 10/c2df66576ba8049b07d5f239777243e21fcdaa09a446be1e55fac709d6273e2a926c1562e0372c3013142557ed9d386381624023549267a667b6e1b656e37fe6 + languageName: node + linkType: hard + +"@jest/get-type@npm:30.1.0": + version: 30.1.0 + resolution: "@jest/get-type@npm:30.1.0" + checksum: 10/e2a95fbb49ce2d15547db8af5602626caf9b05f62a5e583b4a2de9bd93a2bfe7175f9bbb2b8a5c3909ce261d467b6991d7265bb1d547cb60e7e97f571f361a70 + languageName: node + linkType: hard + +"@jest/globals@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/globals@npm:30.2.0" + dependencies: + "@jest/environment": "npm:30.2.0" + "@jest/expect": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + jest-mock: "npm:30.2.0" + checksum: 10/d4a331d3847cebb3acefe120350d8a6bb5517c1403de7cd2b4dc67be425f37ba0511beee77d6837b4da2d93a25a06d6f829ad7837da365fae45e1da57523525c languageName: node linkType: hard @@ -10254,40 +10439,39 @@ __metadata: languageName: node linkType: hard -"@jest/reporters@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/reporters@npm:29.7.0" +"@jest/reporters@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/reporters@npm:30.2.0" dependencies: "@bcoe/v8-coverage": "npm:^0.2.3" - "@jest/console": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" + "@jest/console": "npm:30.2.0" + "@jest/test-result": "npm:30.2.0" + "@jest/transform": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + "@jridgewell/trace-mapping": "npm:^0.3.25" "@types/node": "npm:*" - chalk: "npm:^4.0.0" - collect-v8-coverage: "npm:^1.0.0" - exit: "npm:^0.1.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" + chalk: "npm:^4.1.2" + collect-v8-coverage: "npm:^1.0.2" + exit-x: "npm:^0.2.2" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.11" istanbul-lib-coverage: "npm:^3.0.0" istanbul-lib-instrument: "npm:^6.0.0" istanbul-lib-report: "npm:^3.0.0" - istanbul-lib-source-maps: "npm:^4.0.0" + istanbul-lib-source-maps: "npm:^5.0.0" istanbul-reports: "npm:^3.1.3" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" + jest-message-util: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-worker: "npm:30.2.0" slash: "npm:^3.0.0" - string-length: "npm:^4.0.1" - strip-ansi: "npm:^6.0.0" + string-length: "npm:^4.0.2" v8-to-istanbul: "npm:^9.0.1" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - checksum: 10/a17d1644b26dea14445cedd45567f4ba7834f980be2ef74447204e14238f121b50d8b858fde648083d2cd8f305f81ba434ba49e37a5f4237a6f2a61180cc73dc + checksum: 10/3848b59bf740c10c4e5c234dcc41c54adbd74932bf05d1d1582d09d86e9baa86ddaf3c43903505fd042ba1203c2889a732137d08058ce9dc0069ba33b5d5373d languageName: node linkType: hard @@ -10309,61 +10493,73 @@ __metadata: languageName: node linkType: hard -"@jest/source-map@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/source-map@npm:29.6.3" +"@jest/snapshot-utils@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/snapshot-utils@npm:30.2.0" dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.18" - callsites: "npm:^3.0.0" - graceful-fs: "npm:^4.2.9" - checksum: 10/bcc5a8697d471396c0003b0bfa09722c3cd879ad697eb9c431e6164e2ea7008238a01a07193dfe3cbb48b1d258eb7251f6efcea36f64e1ebc464ea3c03ae2deb + "@jest/types": "npm:30.2.0" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" + natural-compare: "npm:^1.4.0" + checksum: 10/6b30ab2b0682117e3ce775e70b5be1eb01e1ea53a74f12ac7090cd1a5f37e9b795cd8de83853afa7b4b799c96b1c482499aa993ca2034ea0679525d32b7f9625 languageName: node linkType: hard -"@jest/test-result@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-result@npm:29.7.0" +"@jest/source-map@npm:30.0.1": + version: 30.0.1 + resolution: "@jest/source-map@npm:30.0.1" dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/istanbul-lib-coverage": "npm:^2.0.0" - collect-v8-coverage: "npm:^1.0.0" - checksum: 10/c073ab7dfe3c562bff2b8fee6cc724ccc20aa96bcd8ab48ccb2aa309b4c0c1923a9e703cea386bd6ae9b71133e92810475bb9c7c22328fc63f797ad3324ed189 + "@jridgewell/trace-mapping": "npm:^0.3.25" + callsites: "npm:^3.1.0" + graceful-fs: "npm:^4.2.11" + checksum: 10/161b27cdf8d9d80fd99374d55222b90478864c6990514be6ebee72b7184a034224c9aceed12c476f3a48d48601bf8ed2e0c047a5a81bd907dc192ebe71365ed4 languageName: node linkType: hard -"@jest/test-sequencer@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/test-sequencer@npm:29.7.0" +"@jest/test-result@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/test-result@npm:30.2.0" dependencies: - "@jest/test-result": "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" + "@jest/console": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + "@types/istanbul-lib-coverage": "npm:^2.0.6" + collect-v8-coverage: "npm:^1.0.2" + checksum: 10/f58f79c3c3ba6dd15325e05b0b5a300777cd8cc38327f622608b6fe849b1073ee9633e33d1e5d7ef5b97a1ce71543d0ad92674b7a279f53033143e8dd7c22959 + languageName: node + linkType: hard + +"@jest/test-sequencer@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/test-sequencer@npm:30.2.0" + dependencies: + "@jest/test-result": "npm:30.2.0" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.2.0" slash: "npm:^3.0.0" - checksum: 10/4420c26a0baa7035c5419b0892ff8ffe9a41b1583ec54a10db3037cd46a7e29dd3d7202f8aa9d376e9e53be5f8b1bc0d16e1de6880a6d319b033b01dc4c8f639 + checksum: 10/7923964b27048b2233858b32aa1b34d4dd9e404311626d944a706bcdcaa0b1585f43f2ffa3fa893ecbf133566f31ba2b79ab5eaaaf674b8558c6c7029ecbea5e languageName: node linkType: hard -"@jest/transform@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/transform@npm:29.7.0" +"@jest/transform@npm:30.2.0": + version: 30.2.0 + resolution: "@jest/transform@npm:30.2.0" dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/types": "npm:^29.6.3" - "@jridgewell/trace-mapping": "npm:^0.3.18" - babel-plugin-istanbul: "npm:^6.1.1" - chalk: "npm:^4.0.0" + "@babel/core": "npm:^7.27.4" + "@jest/types": "npm:30.2.0" + "@jridgewell/trace-mapping": "npm:^0.3.25" + babel-plugin-istanbul: "npm:^7.0.1" + chalk: "npm:^4.1.2" convert-source-map: "npm:^2.0.0" fast-json-stable-stringify: "npm:^2.1.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - pirates: "npm:^4.0.4" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.2.0" + jest-regex-util: "npm:30.0.1" + jest-util: "npm:30.2.0" + micromatch: "npm:^4.0.8" + pirates: "npm:^4.0.7" slash: "npm:^3.0.0" - write-file-atomic: "npm:^4.0.2" - checksum: 10/30f42293545ab037d5799c81d3e12515790bb58513d37f788ce32d53326d0d72ebf5b40f989e6896739aa50a5f77be44686e510966370d58511d5ad2637c68c1 + write-file-atomic: "npm:^5.0.1" + checksum: 10/c75d72d524c2a50ea6c05778a9b76a6e48bc228a3390896a6edd4416f7b4954ee0a07e229ed7b4949ce8889324b70034c784751e3fc455a25648bd8dcad17d0d languageName: node linkType: hard @@ -10396,12 +10592,11 @@ __metadata: languageName: node linkType: hard -"@joshwooding/vite-plugin-react-docgen-typescript@npm:0.6.1": - version: 0.6.1 - resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.6.1" +"@joshwooding/vite-plugin-react-docgen-typescript@npm:^0.6.3": + version: 0.6.3 + resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.6.3" dependencies: - glob: "npm:^10.0.0" - magic-string: "npm:^0.30.0" + glob: "npm:^11.1.0" react-docgen-typescript: "npm:^2.2.2" peerDependencies: typescript: ">= 4.3.x" @@ -10409,7 +10604,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/a82b6005378ccda13250fcfeaa04ec2ba17d1c2923b5bba5907d5b2fd658c661b29c1215eb1c0fe305b390bee89ec77c684aa68506262734c3bb3cd76d8a6963 + checksum: 10/8a0f2c52b99e0dff4eeee574cf373b794e5398ee3c6b4d272378ccfe3b7dc2f3dc647d446716998ee2d88ee26df617e7b10da949702edcb625ee49e93b7daa95 languageName: node linkType: hard @@ -10467,13 +10662,13 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.30 - resolution: "@jridgewell/trace-mapping@npm:0.3.30" +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" dependencies: "@jridgewell/resolve-uri": "npm:^3.1.0" "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10/f9fabe1122058f4fedc242bdc43fcaacb6b222c6fb712b7904c37704dcb16e50e07ca137ff99043da44292b18a8720296ff97f7703e960678b8ef51d0db4d250 + checksum: 10/da0283270e691bdb5543806077548532791608e52386cfbbf3b9e8fb00457859d1bd01d512851161c886eb3a2f3ce6fd9bcf25db8edf3bddedd275bd4a88d606 languageName: node linkType: hard @@ -11671,6 +11866,17 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^0.2.11": + version: 0.2.12 + resolution: "@napi-rs/wasm-runtime@npm:0.2.12" + dependencies: + "@emnapi/core": "npm:^1.4.3" + "@emnapi/runtime": "npm:^1.4.3" + "@tybys/wasm-util": "npm:^0.10.0" + checksum: 10/5fd518182427980c28bc724adf06c5f32f9a8915763ef560b5f7d73607d30cd15ac86d0cbd2eb80d4cfab23fc80d0876d89ca36a9daadcb864bc00917c94187c + languageName: node + linkType: hard + "@napi-rs/wasm-runtime@npm:^1.1.0": version: 1.1.0 resolution: "@napi-rs/wasm-runtime@npm:1.1.0" @@ -13997,6 +14203,13 @@ __metadata: languageName: node linkType: hard +"@pkgr/core@npm:^0.2.9": + version: 0.2.9 + resolution: "@pkgr/core@npm:0.2.9" + checksum: 10/bb2fb86977d63f836f8f5b09015d74e6af6488f7a411dcd2bfdca79d76b5a681a9112f41c45bdf88a9069f049718efc6f3900d7f1de66a2ec966068308ae517f + languageName: node + linkType: hard + "@playwright/test@npm:^1.32.3": version: 1.57.0 resolution: "@playwright/test@npm:1.57.0" @@ -16742,92 +16955,92 @@ __metadata: languageName: node linkType: hard -"@rspack/binding-darwin-arm64@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-darwin-arm64@npm:1.6.6" +"@rspack/binding-darwin-arm64@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-darwin-arm64@npm:1.6.7" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-darwin-x64@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-darwin-x64@npm:1.6.6" +"@rspack/binding-darwin-x64@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-darwin-x64@npm:1.6.7" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rspack/binding-linux-arm64-gnu@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-linux-arm64-gnu@npm:1.6.6" +"@rspack/binding-linux-arm64-gnu@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-linux-arm64-gnu@npm:1.6.7" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-arm64-musl@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-linux-arm64-musl@npm:1.6.6" +"@rspack/binding-linux-arm64-musl@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-linux-arm64-musl@npm:1.6.7" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rspack/binding-linux-x64-gnu@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-linux-x64-gnu@npm:1.6.6" +"@rspack/binding-linux-x64-gnu@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-linux-x64-gnu@npm:1.6.7" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-x64-musl@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-linux-x64-musl@npm:1.6.6" +"@rspack/binding-linux-x64-musl@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-linux-x64-musl@npm:1.6.7" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rspack/binding-wasm32-wasi@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-wasm32-wasi@npm:1.6.6" +"@rspack/binding-wasm32-wasi@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-wasm32-wasi@npm:1.6.7" dependencies: "@napi-rs/wasm-runtime": "npm:1.0.7" conditions: cpu=wasm32 languageName: node linkType: hard -"@rspack/binding-win32-arm64-msvc@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-win32-arm64-msvc@npm:1.6.6" +"@rspack/binding-win32-arm64-msvc@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-win32-arm64-msvc@npm:1.6.7" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-win32-ia32-msvc@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-win32-ia32-msvc@npm:1.6.6" +"@rspack/binding-win32-ia32-msvc@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-win32-ia32-msvc@npm:1.6.7" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rspack/binding-win32-x64-msvc@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding-win32-x64-msvc@npm:1.6.6" +"@rspack/binding-win32-x64-msvc@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding-win32-x64-msvc@npm:1.6.7" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rspack/binding@npm:1.6.6": - version: 1.6.6 - resolution: "@rspack/binding@npm:1.6.6" +"@rspack/binding@npm:1.6.7": + version: 1.6.7 + resolution: "@rspack/binding@npm:1.6.7" dependencies: - "@rspack/binding-darwin-arm64": "npm:1.6.6" - "@rspack/binding-darwin-x64": "npm:1.6.6" - "@rspack/binding-linux-arm64-gnu": "npm:1.6.6" - "@rspack/binding-linux-arm64-musl": "npm:1.6.6" - "@rspack/binding-linux-x64-gnu": "npm:1.6.6" - "@rspack/binding-linux-x64-musl": "npm:1.6.6" - "@rspack/binding-wasm32-wasi": "npm:1.6.6" - "@rspack/binding-win32-arm64-msvc": "npm:1.6.6" - "@rspack/binding-win32-ia32-msvc": "npm:1.6.6" - "@rspack/binding-win32-x64-msvc": "npm:1.6.6" + "@rspack/binding-darwin-arm64": "npm:1.6.7" + "@rspack/binding-darwin-x64": "npm:1.6.7" + "@rspack/binding-linux-arm64-gnu": "npm:1.6.7" + "@rspack/binding-linux-arm64-musl": "npm:1.6.7" + "@rspack/binding-linux-x64-gnu": "npm:1.6.7" + "@rspack/binding-linux-x64-musl": "npm:1.6.7" + "@rspack/binding-wasm32-wasi": "npm:1.6.7" + "@rspack/binding-win32-arm64-msvc": "npm:1.6.7" + "@rspack/binding-win32-ia32-msvc": "npm:1.6.7" + "@rspack/binding-win32-x64-msvc": "npm:1.6.7" dependenciesMeta: "@rspack/binding-darwin-arm64": optional: true @@ -16849,23 +17062,23 @@ __metadata: optional: true "@rspack/binding-win32-x64-msvc": optional: true - checksum: 10/37b69398a0679c25e0479b6eb11ea2c110a8b57367af2c808a473d19d58c9dd09e7763b3dfbec06284d6863e7a301d71509128fe22da2b0c57c06b718f67e66a + checksum: 10/80837f5cbdcac9eb6fb2213436baa3a5a841508340456c473e36bed2882197f456462db675b2d43cc1ed84d61109bae4bef0d474131a670113601ad80727769f languageName: node linkType: hard "@rspack/core@npm:^1.4.11": - version: 1.6.6 - resolution: "@rspack/core@npm:1.6.6" + version: 1.6.7 + resolution: "@rspack/core@npm:1.6.7" dependencies: "@module-federation/runtime-tools": "npm:0.21.6" - "@rspack/binding": "npm:1.6.6" + "@rspack/binding": "npm:1.6.7" "@rspack/lite-tapable": "npm:1.1.0" peerDependencies: "@swc/helpers": ">=0.5.1" peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/e706c19085729f52f3e80c6945edc32def2091270fc9a15d6aea336754719d0bdce93e62dae3a675c412b5e433cc2fc093591d74e731722196d0de2ff269b198 + checksum: 10/c374d954c86a24dfba59b6e3c6388ce365723c83ea7012a6e95175b6245f7080b13e8560c25d744558e850c04a10d95fbe7ee92b4eabbd40a1ef578caf60615b languageName: node linkType: hard @@ -17296,21 +17509,12 @@ __metadata: languageName: node linkType: hard -"@sinonjs/fake-timers@npm:^10.0.2": - version: 10.3.0 - resolution: "@sinonjs/fake-timers@npm:10.3.0" - dependencies: - "@sinonjs/commons": "npm:^3.0.0" - checksum: 10/78155c7bd866a85df85e22028e046b8d46cf3e840f72260954f5e3ed5bd97d66c595524305a6841ffb3f681a08f6e5cef572a2cce5442a8a232dc29fb409b83e - languageName: node - linkType: hard - -"@sinonjs/fake-timers@npm:^13.0.1": - version: 13.0.2 - resolution: "@sinonjs/fake-timers@npm:13.0.2" +"@sinonjs/fake-timers@npm:^13.0.0, @sinonjs/fake-timers@npm:^13.0.1": + version: 13.0.5 + resolution: "@sinonjs/fake-timers@npm:13.0.5" dependencies: "@sinonjs/commons": "npm:^3.0.1" - checksum: 10/77cca5c548e2529931908c48ac375f162ee901bc52110197b4c470b2535c6c571f9ecd4fa12157f4d2ae174c5391f03940fb563a681a691fb44204a0ef3ded35 + checksum: 10/11ee417968fc4dce1896ab332ac13f353866075a9d2a88ed1f6258f17cc4f7d93e66031b51fcddb8c203aa4d53fd980b0ae18aba06269f4682164878a992ec3f languageName: node linkType: hard @@ -18899,82 +19103,121 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-a11y@npm:^9.1.7": - version: 9.1.16 - resolution: "@storybook/addon-a11y@npm:9.1.16" +"@storybook/addon-a11y@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/addon-a11y@npm:10.1.9" dependencies: "@storybook/global": "npm:^5.0.0" axe-core: "npm:^4.2.0" peerDependencies: - storybook: ^9.1.16 - checksum: 10/24645a9df98aa52f7e52ac0ba5a87eb5b3ac533130b490628925a657ddbaab9ac370930594f5a879b9c30a36f0d2f9b752e9643a57ac8f2f835379143afb2f06 + storybook: ^10.1.9 + checksum: 10/d004f9975d20368ce58bb6c25bc421920ed6898ae2342a821776c41b6ed7597e41f7bfe932fc6be73f7611ba053cdcd63b18cf7c9ec0e5375a0c01fe45635b0f languageName: node linkType: hard -"@storybook/addon-docs@npm:^9.1.7": - version: 9.1.16 - resolution: "@storybook/addon-docs@npm:9.1.16" +"@storybook/addon-docs@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/addon-docs@npm:10.1.9" dependencies: "@mdx-js/react": "npm:^3.0.0" - "@storybook/csf-plugin": "npm:9.1.16" - "@storybook/icons": "npm:^1.4.0" - "@storybook/react-dom-shim": "npm:9.1.16" + "@storybook/csf-plugin": "npm:10.1.9" + "@storybook/icons": "npm:^2.0.0" + "@storybook/react-dom-shim": "npm:10.1.9" react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" react-dom: "npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^9.1.16 - checksum: 10/02081dd9c9e6273e8030b7ab24470d1d29513870245aaf2741cd97eea1350918db354fb78484f192c191942d75f834e81176717e59aefc28572c88909979e8a9 + storybook: ^10.1.9 + checksum: 10/4f24aa255b2cc3c5ad1560730e40aba5f2019a8069456e1f03043cf67de14cbb9ac26650eb805fddb6395182db62d850df127fc310a1fff49c39cf166a63aa02 languageName: node linkType: hard -"@storybook/addon-links@npm:^9.1.7": - version: 9.1.16 - resolution: "@storybook/addon-links@npm:9.1.16" +"@storybook/addon-links@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/addon-links@npm:10.1.9" dependencies: "@storybook/global": "npm:^5.0.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.1.9 peerDependenciesMeta: react: optional: true - checksum: 10/04eca604043d55c391512bf5e63cb742c84759eedb535f3deb8b1e9fcc68fb0cf8222df4990cefba34cae8321a6ecd380be34111ebc6b6a109dd5e910fe0a5a7 + checksum: 10/c0f9c97b64dd50e0ea0642eb75e2f7af81548958aeef35e1d44992c7d85ee8796cc034088aebba5e81b760932e064e39b7bdc64f572bbd68d237f6870c95f52e languageName: node linkType: hard -"@storybook/addon-themes@npm:^9.1.7": - version: 9.1.16 - resolution: "@storybook/addon-themes@npm:9.1.16" +"@storybook/addon-themes@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/addon-themes@npm:10.1.9" dependencies: ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^9.1.16 - checksum: 10/c596f386a6aad3638febcc2df4d53e5e185c8c7b7e1bef17dd12b83a9ad6102769b2244869065912fd5c563915baf52b631a872fff239c80539ac49e5daad85e + storybook: ^10.1.9 + checksum: 10/66d231efb94919aa89bbb92291925d96519c993d6d75326850caad432a1425c4aa93b4249bf46fffc5b41724ef007d01477045a74e55e937410d8fa7be7037f6 languageName: node linkType: hard -"@storybook/builder-vite@npm:9.1.16": - version: 9.1.16 - resolution: "@storybook/builder-vite@npm:9.1.16" +"@storybook/addon-vitest@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/addon-vitest@npm:10.1.9" dependencies: - "@storybook/csf-plugin": "npm:9.1.16" + "@storybook/global": "npm:^5.0.0" + "@storybook/icons": "npm:^2.0.0" + peerDependencies: + "@vitest/browser": ^3.0.0 || ^4.0.0 + "@vitest/browser-playwright": ^4.0.0 + "@vitest/runner": ^3.0.0 || ^4.0.0 + storybook: ^10.1.9 + vitest: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + "@vitest/browser": + optional: true + "@vitest/browser-playwright": + optional: true + "@vitest/runner": + optional: true + vitest: + optional: true + checksum: 10/8d1be8902a243d6c42a84d0acd1550014e5fa6cb509cdfbec6603e6b3d34def5f28d483f8d4289ef7be87d48f41a47f34f4f7028eef7add49cec5d98cf477a0d + languageName: node + linkType: hard + +"@storybook/builder-vite@npm:10.1.9": + version: 10.1.9 + resolution: "@storybook/builder-vite@npm:10.1.9" + dependencies: + "@storybook/csf-plugin": "npm:10.1.9" + "@vitest/mocker": "npm:3.2.4" ts-dedent: "npm:^2.0.0" peerDependencies: - storybook: ^9.1.16 + storybook: ^10.1.9 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10/bd30ad08a0222aa0d44a4127e959402058c7aedf7dddf3114a4ad54cd49384c24f738fe61e3e9be7be17943557e9ccbdd7311101f69af98d83c6eca5e433c855 + checksum: 10/4dc086193b45219b24e528404ed51c4dbc240a9ac20feeef88a1b051ae286264006741b402f4936745f5733c8b568e090b029aaea73bf5e3a078047aa957f8ba languageName: node linkType: hard -"@storybook/csf-plugin@npm:9.1.16": - version: 9.1.16 - resolution: "@storybook/csf-plugin@npm:9.1.16" +"@storybook/csf-plugin@npm:10.1.9": + version: 10.1.9 + resolution: "@storybook/csf-plugin@npm:10.1.9" dependencies: - unplugin: "npm:^1.3.1" + unplugin: "npm:^2.3.5" peerDependencies: - storybook: ^9.1.16 - checksum: 10/81612bfa904673d5a28094dce40cc0890091f6e3a82bdcedc34dd43c103d7f20d838c81744f87e65a9efb7b98779b4d89ecc95a14a5b550efe2aeff53de0c6ea + esbuild: "*" + rollup: "*" + storybook: ^10.1.9 + vite: "*" + webpack: "*" + peerDependenciesMeta: + esbuild: + optional: true + rollup: + optional: true + vite: + optional: true + webpack: + optional: true + checksum: 10/604339107f7bd57f64b5b0d9ddc16a447fc0987d348cb9add5bb2fc75b568760afb3689cd51c73df48cc13bf2d82386f89da57e53f500687434d403cd7395e49 languageName: node linkType: hard @@ -18985,64 +19228,65 @@ __metadata: languageName: node linkType: hard -"@storybook/icons@npm:^1.4.0": - version: 1.4.0 - resolution: "@storybook/icons@npm:1.4.0" +"@storybook/icons@npm:^2.0.0": + version: 2.0.1 + resolution: "@storybook/icons@npm:2.0.1" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - checksum: 10/513d36188bb84f1f64dd982b6bd577de4c3d7bc2aa9d318a2acf8c654d16994bac0b669787a4ced6720e471251bcb0ec68b8d8dc2cc7245d11102bd617243700 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10/04ffa285f4defc611def51f82492688bc49f6f4e8ce4e7ba5c99a1c1410b7e8820b5da65c33610a497df2409de7b48fae399052c5cacab6a4a4a9b48a36ebfd5 languageName: node linkType: hard -"@storybook/react-dom-shim@npm:9.1.16": - version: 9.1.16 - resolution: "@storybook/react-dom-shim@npm:9.1.16" +"@storybook/react-dom-shim@npm:10.1.9": + version: 10.1.9 + resolution: "@storybook/react-dom-shim@npm:10.1.9" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 - checksum: 10/05c1426a02416b353e61f267d901ce938919a2cc1e94eebe11938c15466e1d584034421798cc228a00cfafeb3aa2bf28cf2814bdf328896a117734c4c8a6890e + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.1.9 + checksum: 10/2b6e598eb8ddac80fd6cd4d888b3a8da1c352e9ffc666a1bcce6f4ac404c77cc75571a57b433e1a12f34cfd255db31fb399a7f38e70bde5d197de2d072eeac85 languageName: node linkType: hard -"@storybook/react-vite@npm:^9.1.7": - version: 9.1.16 - resolution: "@storybook/react-vite@npm:9.1.16" +"@storybook/react-vite@npm:^10.1.9": + version: 10.1.9 + resolution: "@storybook/react-vite@npm:10.1.9" dependencies: - "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.6.1" + "@joshwooding/vite-plugin-react-docgen-typescript": "npm:^0.6.3" "@rollup/pluginutils": "npm:^5.0.2" - "@storybook/builder-vite": "npm:9.1.16" - "@storybook/react": "npm:9.1.16" - find-up: "npm:^7.0.0" + "@storybook/builder-vite": "npm:10.1.9" + "@storybook/react": "npm:10.1.9" + empathic: "npm:^2.0.0" magic-string: "npm:^0.30.0" react-docgen: "npm:^8.0.0" resolve: "npm:^1.22.8" tsconfig-paths: "npm:^4.2.0" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.1.9 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - checksum: 10/5d5e1ab752c2212d5c00d0150f46b1a9ef3d86ac3ee8ec359de301ba7801b0272eadd52a3e647b2d40db72ca1d321c981b8e392ec060d5e1ec39c4a3227c3aa5 + checksum: 10/e55978b8eaee2f5d9a7b30c2547d3f29497468c0bac5f20308633554f381d066d2f0549a4997d9ec29693f018d6889d9b9c4bfb4b2e822c4730999fa1605c573 languageName: node linkType: hard -"@storybook/react@npm:9.1.16": - version: 9.1.16 - resolution: "@storybook/react@npm:9.1.16" +"@storybook/react@npm:10.1.9": + version: 10.1.9 + resolution: "@storybook/react@npm:10.1.9" dependencies: "@storybook/global": "npm:^5.0.0" - "@storybook/react-dom-shim": "npm:9.1.16" + "@storybook/react-dom-shim": "npm:10.1.9" + react-docgen: "npm:^8.0.2" peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.1.9 typescript: ">= 4.9.x" peerDependenciesMeta: typescript: optional: true - checksum: 10/ead1396a6fdd3cbb4170fbf1f390073d64a07fb4114243a5a6d7c975d8f35aae0220c0c731c62f5f6be2f6a6a92b2b8b150066da7b463ae848cc43dd4b8670f1 + checksum: 10/964f5a3b77638597289c72be0991323fcbe0f5d7451b5c7bceac7e998dd819897936fb486e38d0b70e42507ca6895850d9a484acc8d171a6ecbd9ce41a0b19ad languageName: node linkType: hard @@ -19586,90 +19830,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-darwin-arm64@npm:1.15.3" +"@swc/core-darwin-arm64@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-darwin-arm64@npm:1.15.6" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-darwin-x64@npm:1.15.3" +"@swc/core-darwin-x64@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-darwin-x64@npm:1.15.6" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.3" +"@swc/core-linux-arm-gnueabihf@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.6" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm64-gnu@npm:1.15.3" +"@swc/core-linux-arm64-gnu@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm64-gnu@npm:1.15.6" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-arm64-musl@npm:1.15.3" +"@swc/core-linux-arm64-musl@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-arm64-musl@npm:1.15.6" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-x64-gnu@npm:1.15.3" +"@swc/core-linux-x64-gnu@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-x64-gnu@npm:1.15.6" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-linux-x64-musl@npm:1.15.3" +"@swc/core-linux-x64-musl@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-linux-x64-musl@npm:1.15.6" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-arm64-msvc@npm:1.15.3" +"@swc/core-win32-arm64-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-arm64-msvc@npm:1.15.6" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-ia32-msvc@npm:1.15.3" +"@swc/core-win32-ia32-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-ia32-msvc@npm:1.15.6" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.15.3": - version: 1.15.3 - resolution: "@swc/core-win32-x64-msvc@npm:1.15.3" +"@swc/core-win32-x64-msvc@npm:1.15.6": + version: 1.15.6 + resolution: "@swc/core-win32-x64-msvc@npm:1.15.6" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.46": - version: 1.15.3 - resolution: "@swc/core@npm:1.15.3" +"@swc/core@npm:^1.15.6": + version: 1.15.6 + resolution: "@swc/core@npm:1.15.6" dependencies: - "@swc/core-darwin-arm64": "npm:1.15.3" - "@swc/core-darwin-x64": "npm:1.15.3" - "@swc/core-linux-arm-gnueabihf": "npm:1.15.3" - "@swc/core-linux-arm64-gnu": "npm:1.15.3" - "@swc/core-linux-arm64-musl": "npm:1.15.3" - "@swc/core-linux-x64-gnu": "npm:1.15.3" - "@swc/core-linux-x64-musl": "npm:1.15.3" - "@swc/core-win32-arm64-msvc": "npm:1.15.3" - "@swc/core-win32-ia32-msvc": "npm:1.15.3" - "@swc/core-win32-x64-msvc": "npm:1.15.3" + "@swc/core-darwin-arm64": "npm:1.15.6" + "@swc/core-darwin-x64": "npm:1.15.6" + "@swc/core-linux-arm-gnueabihf": "npm:1.15.6" + "@swc/core-linux-arm64-gnu": "npm:1.15.6" + "@swc/core-linux-arm64-musl": "npm:1.15.6" + "@swc/core-linux-x64-gnu": "npm:1.15.6" + "@swc/core-linux-x64-musl": "npm:1.15.6" + "@swc/core-win32-arm64-msvc": "npm:1.15.6" + "@swc/core-win32-ia32-msvc": "npm:1.15.6" + "@swc/core-win32-x64-msvc": "npm:1.15.6" "@swc/counter": "npm:^0.1.3" "@swc/types": "npm:^0.1.25" peerDependencies: @@ -19698,7 +19942,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10/280330d82328818138ed64fdcf9ea9abde6b6f16eca65a9d4db27dde06a8dfffd2649f3447d2243387277513c7430fa4142cafcfd64e943d682ce6a713cb8c2d + checksum: 10/d17d1b5e6e81f8c262b668f237b863dd612eaa19fc35e74067b2a27ba3998c0c511ec7f49cd91c02f61fa77dd1b5d7e65d293736f65ec45d6c13989904b1c7eb languageName: node linkType: hard @@ -19709,7 +19953,7 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:^0.5.0, @swc/helpers@npm:^0.5.8": +"@swc/helpers@npm:^0.5.0, @swc/helpers@npm:^0.5.17, @swc/helpers@npm:^0.5.8": version: 0.5.17 resolution: "@swc/helpers@npm:0.5.17" dependencies: @@ -19718,7 +19962,7 @@ __metadata: languageName: node linkType: hard -"@swc/jest@npm:^0.2.22": +"@swc/jest@npm:^0.2.39": version: 0.2.39 resolution: "@swc/jest@npm:0.2.39" dependencies: @@ -20054,7 +20298,7 @@ __metadata: languageName: node linkType: hard -"@tybys/wasm-util@npm:^0.10.1": +"@tybys/wasm-util@npm:^0.10.0, @tybys/wasm-util@npm:^0.10.1": version: 0.10.1 resolution: "@tybys/wasm-util@npm:0.10.1" dependencies: @@ -20120,7 +20364,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.5": +"@types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -20152,7 +20396,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6, @types/babel__traverse@npm:^7.20.7": +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.20.7": version: 7.28.0 resolution: "@types/babel__traverse@npm:7.28.0" dependencies: @@ -20644,15 +20888,6 @@ __metadata: languageName: node linkType: hard -"@types/graceful-fs@npm:^4.1.3": - version: 4.1.5 - resolution: "@types/graceful-fs@npm:4.1.5" - dependencies: - "@types/node": "npm:*" - checksum: 10/d076bb61f45d0fc42dee496ef8b1c2f8742e15d5e47e90e20d0243386e426c04d4efd408a48875ab432f7960b4ce3414db20ed0fbbfc7bcc89d84e574f6e045a - languageName: node - linkType: hard - "@types/hast@npm:^2.0.0": version: 2.3.4 resolution: "@types/hast@npm:2.3.4" @@ -20787,13 +21022,13 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:*, @types/jest@npm:^29.5.11": - version: 29.5.14 - resolution: "@types/jest@npm:29.5.14" +"@types/jest@npm:*, @types/jest@npm:^30.0.0": + version: 30.0.0 + resolution: "@types/jest@npm:30.0.0" dependencies: - expect: "npm:^29.0.0" - pretty-format: "npm:^29.0.0" - checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b + expect: "npm:^30.0.0" + pretty-format: "npm:^30.0.0" + checksum: 10/cdeaa924c68b5233d9ff92861a89e7042df2b0f197633729bcf3a31e65bd4e9426e751c5665b5ac2de0b222b33f100a5502da22aefce3d2c62931c715e88f209 languageName: node linkType: hard @@ -20837,14 +21072,14 @@ __metadata: languageName: node linkType: hard -"@types/jsdom@npm:^20.0.0": - version: 20.0.0 - resolution: "@types/jsdom@npm:20.0.0" +"@types/jsdom@npm:^21.1.7": + version: 21.1.7 + resolution: "@types/jsdom@npm:21.1.7" dependencies: "@types/node": "npm:*" "@types/tough-cookie": "npm:*" parse5: "npm:^7.0.0" - checksum: 10/4cd814a948aa9b739652cde183acc6a9a10bcf04ed82c3a53f691bbc52d156b49269fa3046c70842680a29d240607fcd7be5f35a73ddbf571d95a664e8e49cec + checksum: 10/a5ee54aec813ac928ef783f69828213af4d81325f584e1fe7573a9ae139924c40768d1d5249237e62d51b9a34ed06bde059c86c6b0248d627457ec5e5d532dfa languageName: node linkType: hard @@ -21676,10 +21911,10 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0": - version: 2.0.0 - resolution: "@types/stack-utils@npm:2.0.0" - checksum: 10/b3fbae25b073116977ecb5c67d22f14567b51a7792403b0bf46e5de8f29bde3bd4ec1626afb22065495ca7f1c699c8bd66720050c94b8f8f9bcefbee79d161fd +"@types/stack-utils@npm:^2.0.3": + version: 2.0.3 + resolution: "@types/stack-utils@npm:2.0.3" + checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 languageName: node linkType: hard @@ -22254,10 +22489,145 @@ __metadata: languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.2.0": - version: 1.2.0 - resolution: "@ungap/structured-clone@npm:1.2.0" - checksum: 10/c6fe89a505e513a7592e1438280db1c075764793a2397877ff1351721fe8792a966a5359769e30242b3cd023f2efb9e63ca2ca88019d73b564488cc20e3eab12 +"@ungap/structured-clone@npm:^1.2.0, @ungap/structured-clone@npm:^1.3.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448 + languageName: node + linkType: hard + +"@unrs/resolver-binding-android-arm-eabi@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.11.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-android-arm64@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-android-arm64@npm:1.11.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-arm64@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.11.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-darwin-x64@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-darwin-x64@npm:1.11.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-freebsd-x64@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.11.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@unrs/resolver-binding-linux-x64-musl@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.11.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@unrs/resolver-binding-wasm32-wasi@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.11.1" + dependencies: + "@napi-rs/wasm-runtime": "npm:^0.2.11" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1": + version: 1.11.1 + resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -23580,13 +23950,6 @@ __metadata: languageName: node linkType: hard -"abab@npm:^2.0.6": - version: 2.0.6 - resolution: "abab@npm:2.0.6" - checksum: 10/ebe95d7278999e605823fc515a3b05d689bc72e7f825536e73c95ebf621636874c6de1b749b3c4bf866b96ccd4b3a2802efa313d0e45ad51a413c8c73247db20 - languageName: node - linkType: hard - "abbrev@npm:1": version: 1.1.1 resolution: "abbrev@npm:1.1.1" @@ -23630,16 +23993,6 @@ __metadata: languageName: node linkType: hard -"acorn-globals@npm:^6.0.0": - version: 6.0.0 - resolution: "acorn-globals@npm:6.0.0" - dependencies: - acorn: "npm:^7.1.1" - acorn-walk: "npm:^7.1.1" - checksum: 10/72d95e5b5e585f9acd019b993ab8bbba68bb3cbc9d9b5c1ebb3c2f1fe5981f11deababfb4949f48e6262f9c57878837f5958c0cca396f81023814680ca878042 - languageName: node - linkType: hard - "acorn-import-attributes@npm:^1.9.5": version: 1.9.5 resolution: "acorn-import-attributes@npm:1.9.5" @@ -23667,13 +24020,6 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^7.1.1": - version: 7.1.1 - resolution: "acorn-walk@npm:7.1.1" - checksum: 10/f3cbf2f7eba3bd27b6e2c0a68d10304de365581fa30b129d0420697135791f44a6d1b0da341d40a2e8af319574f4bd5cb970279dd35fdd1fc5beacaba29c6a4e - languageName: node - linkType: hard - "acorn-walk@npm:^8.1.1": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" @@ -23681,16 +24027,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^7.1.1": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" - bin: - acorn: bin/acorn - checksum: 10/8be2a40714756d713dfb62544128adce3b7102c6eb94bc312af196c2cc4af76e5b93079bd66b05e9ca31b35a9b0ce12171d16bc55f366cafdb794fdab9d753ec - languageName: node - linkType: hard - -"acorn@npm:^8.14.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn@npm:^8.14.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -24009,7 +24346,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": +"ansi-styles@npm:^5.0.0, ansi-styles@npm:^5.2.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" checksum: 10/d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 @@ -24030,13 +24367,13 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": - version: 3.1.2 - resolution: "anymatch@npm:3.1.2" +"anymatch@npm:^3.1.3, anymatch@npm:~3.1.2": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" dependencies: normalize-path: "npm:^3.0.0" picomatch: "npm:^2.0.4" - checksum: 10/985163db2292fac9e5a1e072bf99f1b5baccf196e4de25a0b0b81865ebddeb3b3eb4480734ef0a2ac8c002845396b91aa89121f5b84f93981a4658164a9ec6e9 + checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 languageName: node linkType: hard @@ -24703,45 +25040,42 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "babel-jest@npm:29.7.0" +"babel-jest@npm:30.2.0": + version: 30.2.0 + resolution: "babel-jest@npm:30.2.0" dependencies: - "@jest/transform": "npm:^29.7.0" - "@types/babel__core": "npm:^7.1.14" - babel-plugin-istanbul: "npm:^6.1.1" - babel-preset-jest: "npm:^29.6.3" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" + "@jest/transform": "npm:30.2.0" + "@types/babel__core": "npm:^7.20.5" + babel-plugin-istanbul: "npm:^7.0.1" + babel-preset-jest: "npm:30.2.0" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" slash: "npm:^3.0.0" peerDependencies: - "@babel/core": ^7.8.0 - checksum: 10/8a0953bd813b3a8926008f7351611055548869e9a53dd36d6e7e96679001f71e65fd7dbfe253265c3ba6a4e630dc7c845cf3e78b17d758ef1880313ce8fba258 + "@babel/core": ^7.11.0 || ^8.0.0-0 + checksum: 10/4c7351a366cf8ac2b8a2e4e438867693eb9d83ed24c29c648da4576f700767aaf72a5d14337fc3f92c50b069f5025b26c7b89e3b7b867914b7cf8997fc15f095 languageName: node linkType: hard -"babel-plugin-istanbul@npm:^6.1.1": - version: 6.1.1 - resolution: "babel-plugin-istanbul@npm:6.1.1" +"babel-plugin-istanbul@npm:^7.0.1": + version: 7.0.1 + resolution: "babel-plugin-istanbul@npm:7.0.1" dependencies: "@babel/helper-plugin-utils": "npm:^7.0.0" "@istanbuljs/load-nyc-config": "npm:^1.0.0" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-instrument: "npm:^5.0.4" + "@istanbuljs/schema": "npm:^0.1.3" + istanbul-lib-instrument: "npm:^6.0.2" test-exclude: "npm:^6.0.0" - checksum: 10/ffd436bb2a77bbe1942a33245d770506ab2262d9c1b3c1f1da7f0592f78ee7445a95bc2efafe619dd9c1b6ee52c10033d6c7d29ddefe6f5383568e60f31dfe8d + checksum: 10/fe9f865f975aaa7a033de9ccb2b63fdcca7817266c5e98d3e02ac7ffd774c695093d215302796cb3770a71ef4574e7a9b298504c3c0c104cf4b48c8eda67b2a6 languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-plugin-jest-hoist@npm:29.6.3" +"babel-plugin-jest-hoist@npm:30.2.0": + version: 30.2.0 + resolution: "babel-plugin-jest-hoist@npm:30.2.0" dependencies: - "@babel/template": "npm:^7.3.3" - "@babel/types": "npm:^7.3.3" - "@types/babel__core": "npm:^7.1.14" - "@types/babel__traverse": "npm:^7.0.6" - checksum: 10/9bfa86ec4170bd805ab8ca5001ae50d8afcb30554d236ba4a7ffc156c1a92452e220e4acbd98daefc12bf0216fccd092d0a2efed49e7e384ec59e0597a926d65 + "@types/babel__core": "npm:^7.20.5" + checksum: 10/360e87a9aa35f4cf208a10ba79e1821ea906f9e3399db2a9762cbc5076fd59f808e571d88b5b1106738d22e23f9ddefbb8137b2780b2abd401c8573b85c8a2f5 languageName: node linkType: hard @@ -24789,37 +25123,40 @@ __metadata: languageName: node linkType: hard -"babel-preset-current-node-syntax@npm:^1.0.0": - version: 1.0.0 - resolution: "babel-preset-current-node-syntax@npm:1.0.0" +"babel-preset-current-node-syntax@npm:^1.2.0": + version: 1.2.0 + resolution: "babel-preset-current-node-syntax@npm:1.2.0" dependencies: "@babel/plugin-syntax-async-generators": "npm:^7.8.4" "@babel/plugin-syntax-bigint": "npm:^7.8.3" - "@babel/plugin-syntax-class-properties": "npm:^7.8.3" - "@babel/plugin-syntax-import-meta": "npm:^7.8.3" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" + "@babel/plugin-syntax-import-meta": "npm:^7.10.4" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" - "@babel/plugin-syntax-numeric-separator": "npm:^7.8.3" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - "@babel/plugin-syntax-top-level-await": "npm:^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/2d45944dc78da3a7ec3bce2a48664bd33e21f5b718a724cc2860921d2e2152678a3de50df9a8d5add8c3c3a10b444925f03ead28090c9dde89ea695044a010db + "@babel/core": ^7.0.0 || ^8.0.0-0 + checksum: 10/3608fa671cfa46364ea6ec704b8fcdd7514b7b70e6ec09b1199e13ae73ed346c51d5ce2cb6d4d5b295f6a3f2cad1fdeec2308aa9e037002dd7c929194cc838ea languageName: node linkType: hard -"babel-preset-jest@npm:^29.6.3": - version: 29.6.3 - resolution: "babel-preset-jest@npm:29.6.3" +"babel-preset-jest@npm:30.2.0": + version: 30.2.0 + resolution: "babel-preset-jest@npm:30.2.0" dependencies: - babel-plugin-jest-hoist: "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" + babel-plugin-jest-hoist: "npm:30.2.0" + babel-preset-current-node-syntax: "npm:^1.2.0" peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/aa4ff2a8a728d9d698ed521e3461a109a1e66202b13d3494e41eea30729a5e7cc03b3a2d56c594423a135429c37bf63a9fa8b0b9ce275298be3095a88c69f6fb + "@babel/core": ^7.11.0 || ^8.0.0-beta.1 + checksum: 10/f75e155a8cf63ea1c5ca942bf757b934427630a1eeafdf861e9117879b3367931fc521da3c41fd52f8d59d705d1093ffb46c9474b3fd4d765d194bea5659d7d9 languageName: node linkType: hard @@ -24962,11 +25299,11 @@ __metadata: linkType: hard "baseline-browser-mapping@npm:^2.8.25": - version: 2.8.32 - resolution: "baseline-browser-mapping@npm:2.8.32" + version: 2.9.8 + resolution: "baseline-browser-mapping@npm:2.9.8" bin: baseline-browser-mapping: dist/cli.js - checksum: 10/d3223faeb8a5d5aa0c2aecc7ecff85e0f2452ba79f8a1ab170a828a1b0efd5eabf38a5264f8ea223cfdee526cf9df689cefbef2f4f22825fc462c37b3483c607 + checksum: 10/1c9cf2fb0cc008ba86d5f1bd1f1a771d6f508dbd6124d173549c650734d6d305eba49622e8bc0160beea9ecafcd2f5f104ffdc92f4a815a4926b74a2d7a6d986 languageName: node linkType: hard @@ -25000,15 +25337,6 @@ __metadata: languageName: node linkType: hard -"better-opn@npm:^3.0.2": - version: 3.0.2 - resolution: "better-opn@npm:3.0.2" - dependencies: - open: "npm:^8.0.4" - checksum: 10/24668e5a837d0d2c0edf17ad5ebcfeb00a8a5578a5eb09f7a409e1a60617cdfea40b8ebfc95e5f12d9568157930d033e6805788fcf0780413ac982c95d3745d1 - languageName: node - linkType: hard - "better-path-resolve@npm:1.0.0": version: 1.0.0 resolution: "better-path-resolve@npm:1.0.0" @@ -25042,6 +25370,15 @@ __metadata: languageName: node linkType: hard +"bidi-js@npm:^1.0.3": + version: 1.0.3 + resolution: "bidi-js@npm:1.0.3" + dependencies: + require-from-string: "npm:^2.0.2" + checksum: 10/c4341c7a98797efe3d186cd99d6f97e9030a4f959794ca200ef2ec0a678483a916335bba6c2c0608a21d04a221288a31c9fd0faa0cd9b3903b93594b42466a6a + languageName: node + linkType: hard + "big.js@npm:^5.2.2": version: 5.2.2 resolution: "big.js@npm:5.2.2" @@ -25306,13 +25643,6 @@ __metadata: languageName: node linkType: hard -"browser-process-hrtime@npm:^1.0.0": - version: 1.0.0 - resolution: "browser-process-hrtime@npm:1.0.0" - checksum: 10/e30f868cdb770b1201afb714ad1575dd86366b6e861900884665fb627109b3cc757c40067d3bfee1ff2a29c835257ea30725a8018a9afd02ac1c24b408b1e45f - languageName: node - linkType: hard - "browser-resolve@npm:^2.0.0": version: 2.0.0 resolution: "browser-resolve@npm:2.0.0" @@ -25450,7 +25780,7 @@ __metadata: languageName: node linkType: hard -"buffer-equal-constant-time@npm:1.0.1, buffer-equal-constant-time@npm:^1.0.1": +"buffer-equal-constant-time@npm:^1.0.1": version: 1.0.1 resolution: "buffer-equal-constant-time@npm:1.0.1" checksum: 10/80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab @@ -25770,7 +26100,7 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^3.0.0": +"callsites@npm:^3.0.0, callsites@npm:^3.1.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" checksum: 10/072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 @@ -25801,7 +26131,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.2.0": +"camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 10/8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d @@ -25828,9 +26158,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001754": - version: 1.0.30001759 - resolution: "caniuse-lite@npm:1.0.30001759" - checksum: 10/da0ec28dd993dffa99402914903426b9466d2798d41c1dc9341fcb7dd10f58fdd148122e2c65001246c030ba1c939645b7b4597f6321e3246dc792323bb11541 + version: 1.0.30001760 + resolution: "caniuse-lite@npm:1.0.30001760" + checksum: 10/ac5c13d00b946c3ace331d25379ed9d85743b1028aba79ae80402cb128b4b491122585144898fefb836d4d9879c13c717a081ae241a00420cbbc7e1b934ec685 languageName: node linkType: hard @@ -26048,10 +26378,10 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^4.0.0": - version: 4.0.0 - resolution: "ci-info@npm:4.0.0" - checksum: 10/c983bb7ff1b06648f4a47432201abbd58291147d8ab5043dbb5c03e1a0e3fb2347f40d29b66a3044f28ffeb5dade01ac35aa6bd4e7464a44d9a49a3d7532415a +"ci-info@npm:^4.0.0, ci-info@npm:^4.2.0": + version: 4.3.1 + resolution: "ci-info@npm:4.3.1" + checksum: 10/9dc952bef67e665ccde2e7a552d42d5d095529d21829ece060a00925ede2dfa136160c70ef2471ea6ed6c9b133218b47c007f56955c0f1734a2e57f240aa7445 languageName: node linkType: hard @@ -26074,13 +26404,20 @@ __metadata: languageName: node linkType: hard -"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2": +"cjs-module-lexer@npm:^1.2.2": version: 1.4.3 resolution: "cjs-module-lexer@npm:1.4.3" checksum: 10/d2b92f919a2dedbfd61d016964fce8da0035f827182ed6839c97cac56e8a8077cfa6a59388adfe2bc588a19cef9bbe830d683a76a6e93c51f65852062cfe2591 languageName: node linkType: hard +"cjs-module-lexer@npm:^2.1.0": + version: 2.1.1 + resolution: "cjs-module-lexer@npm:2.1.1" + checksum: 10/db4331152f4414f3a451865554290eb7d146699aa2aefe1504891951d791ab450f1a75b0477630a4f2942be26f257c4e0627fbfed29d322b5266956b3643f3c1 + languageName: node + linkType: hard + "classnames@npm:*, classnames@npm:^2.2.6, classnames@npm:^2.3.1, classnames@npm:^2.5.1": version: 2.5.1 resolution: "classnames@npm:2.5.1" @@ -26432,10 +26769,10 @@ __metadata: languageName: node linkType: hard -"collect-v8-coverage@npm:^1.0.0": - version: 1.0.0 - resolution: "collect-v8-coverage@npm:1.0.0" - checksum: 10/99d6059eb0e04bf792e27824d43d1139ede28914b7f55ddedd9c43594926221579fa6925ecc7e2f47dec14f5199e5ea3afbfc1da9a32ad542f859022d57f9d80 +"collect-v8-coverage@npm:^1.0.2": + version: 1.0.3 + resolution: "collect-v8-coverage@npm:1.0.3" + checksum: 10/656443261fb7b79cf79e89cba4b55622b07c1d4976c630829d7c5c585c73cda1c2ff101f316bfb19bb9e2c58d724c7db1f70a21e213dcd14099227c5e6019860 languageName: node linkType: hard @@ -27198,23 +27535,6 @@ __metadata: languageName: node linkType: hard -"create-jest@npm:^29.7.0": - version: 29.7.0 - resolution: "create-jest@npm:29.7.0" - dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - prompts: "npm:^2.0.1" - bin: - create-jest: bin/create-jest.js - checksum: 10/847b4764451672b4174be4d5c6d7d63442ec3aa5f3de52af924e4d996d87d7801c18e125504f25232fc75840f6625b3ac85860fac6ce799b5efae7bdcaf4a2b7 - languageName: node - linkType: hard - "create-require@npm:^1.1.0, create-require@npm:^1.1.1": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -27474,6 +27794,16 @@ __metadata: languageName: node linkType: hard +"css-tree@npm:^3.1.0": + version: 3.1.0 + resolution: "css-tree@npm:3.1.0" + dependencies: + mdn-data: "npm:2.12.2" + source-map-js: "npm:^1.0.1" + checksum: 10/e8c5c8e98e3aa4a620fda0b813ce57ccf99281652bf9d23e5cdfc9961c9a93a6769941f9a92e31e65d90f446f42fa83879ab0185206dc7a178d9f656d0913e14 + languageName: node + linkType: hard + "css-vendor@npm:^2.0.8": version: 2.0.8 resolution: "css-vendor@npm:2.0.8" @@ -27578,35 +27908,24 @@ __metadata: languageName: node linkType: hard -"cssom@npm:^0.5.0": - version: 0.5.0 - resolution: "cssom@npm:0.5.0" - checksum: 10/b502a315b1ce020a692036cc38cb36afa44157219b80deadfa040ab800aa9321fcfbecf02fd2e6ec87db169715e27978b4ab3701f916461e9cf7808899f23b54 - languageName: node - linkType: hard - -"cssom@npm:~0.3.6": - version: 0.3.8 - resolution: "cssom@npm:0.3.8" - checksum: 10/49eacc88077555e419646c0ea84ddc73c97e3a346ad7cb95e22f9413a9722d8964b91d781ce21d378bd5ae058af9a745402383fa4e35e9cdfd19654b63f892a9 - languageName: node - linkType: hard - -"cssstyle@npm:^2.3.0": - version: 2.3.0 - resolution: "cssstyle@npm:2.3.0" - dependencies: - cssom: "npm:~0.3.6" - checksum: 10/46f7f05a153446c4018b0454ee1464b50f606cb1803c90d203524834b7438eb52f3b173ba0891c618f380ced34ee12020675dc0052a7f1be755fe4ebc27ee977 - languageName: node - linkType: hard - "cssstyle@npm:^4.1.0": - version: 4.1.0 - resolution: "cssstyle@npm:4.1.0" + version: 4.6.0 + resolution: "cssstyle@npm:4.6.0" dependencies: - rrweb-cssom: "npm:^0.7.1" - checksum: 10/8ca9e2d1f1b24f93bb5f3f20a7a1e271e58060957880e985ee55614e196a798ffab309ec6bac105af8a439a6764546761813835ebb7f929d60823637ee838a8f + "@asamuzakjp/css-color": "npm:^3.2.0" + rrweb-cssom: "npm:^0.8.0" + checksum: 10/1cb25c9d66b87adb165f978b75cdeb6f225d7e31ba30a8934666046a0be037e4e7200d359bfa79d4f1a4aef1083ea09633b81bcdb36a2f2ac888e8c73ea3a289 + languageName: node + linkType: hard + +"cssstyle@npm:^5.3.4": + version: 5.3.4 + resolution: "cssstyle@npm:5.3.4" + dependencies: + "@asamuzakjp/css-color": "npm:^4.1.0" + "@csstools/css-syntax-patches-for-csstree": "npm:1.0.14" + css-tree: "npm:^3.1.0" + checksum: 10/4eeb85cbaba47c2e4eb9f9a9dea9633e311f1cb706258f582fc8d099edc0b8c0deea93a6943981960d7f920ac0f3bbb5277cc4c355915406c17a95d0049a073d languageName: node linkType: hard @@ -27767,17 +28086,6 @@ __metadata: languageName: node linkType: hard -"data-urls@npm:^3.0.2": - version: 3.0.2 - resolution: "data-urls@npm:3.0.2" - dependencies: - abab: "npm:^2.0.6" - whatwg-mimetype: "npm:^3.0.0" - whatwg-url: "npm:^11.0.0" - checksum: 10/033fc3dd0fba6d24bc9a024ddcf9923691dd24f90a3d26f6545d6a2f71ec6956f93462f2cdf2183cc46f10dc01ed3bcb36731a8208456eb1a08147e571fe2a76 - languageName: node - linkType: hard - "data-urls@npm:^5.0.0": version: 5.0.0 resolution: "data-urls@npm:5.0.0" @@ -27788,6 +28096,16 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^6.0.0": + version: 6.0.0 + resolution: "data-urls@npm:6.0.0" + dependencies: + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^15.0.0" + checksum: 10/a47f0dde184337c4f168d455aedf0b486fed87b6ca583b4b9ad55d1515f4836b418d4bdc5b5b6fc55e321feb826029586a0d47e1c9a9e7ac4d52a78faceb7fb0 + languageName: node + linkType: hard + "data-view-buffer@npm:^1.0.2": version: 1.0.2 resolution: "data-view-buffer@npm:1.0.2" @@ -27930,10 +28248,10 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:10, decimal.js@npm:^10.3.1, decimal.js@npm:^10.4.3": - version: 10.4.3 - resolution: "decimal.js@npm:10.4.3" - checksum: 10/de663a7bc4d368e3877db95fcd5c87b965569b58d16cdc4258c063d231ca7118748738df17cd638f7e9dd0be8e34cec08d7234b20f1f2a756a52fc5a38b188d0 +"decimal.js@npm:10, decimal.js@npm:^10.4.3, decimal.js@npm:^10.6.0": + version: 10.6.0 + resolution: "decimal.js@npm:10.6.0" + checksum: 10/c0d45842d47c311d11b38ce7ccc911121953d4df3ebb1465d92b31970eb4f6738a065426a06094af59bee4b0d64e42e7c8984abd57b6767c64ea90cf90bb4a69 languageName: node linkType: hard @@ -27964,15 +28282,15 @@ __metadata: languageName: node linkType: hard -"dedent@npm:^1.0.0": - version: 1.5.3 - resolution: "dedent@npm:1.5.3" +"dedent@npm:^1.6.0": + version: 1.7.0 + resolution: "dedent@npm:1.7.0" peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - checksum: 10/e5277f6268f288649503125b781a7b7a2c9b22d011139688c0b3619fe40121e600eb1f077c891938d4b2428bdb6326cc3c77a763e4b1cc681bd9666ab1bad2a1 + checksum: 10/c902f3e7e828923bd642c12c1d8996616ff5588f8279a2951790bd7c7e479fa4dd7f016b55ce2c9ea1aa2895fc503e7d6c0cde6ebc95ca683ac0230f7c911fd7 languageName: node linkType: hard @@ -28251,7 +28569,7 @@ __metadata: languageName: node linkType: hard -"detect-newline@npm:^3.0.0": +"detect-newline@npm:^3.1.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" checksum: 10/ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 @@ -28605,15 +28923,6 @@ __metadata: languageName: node linkType: hard -"domexception@npm:^4.0.0": - version: 4.0.0 - resolution: "domexception@npm:4.0.0" - dependencies: - webidl-conversions: "npm:^7.0.0" - checksum: 10/4ed443227d2871d76c58d852b2e93c68e0443815b2741348f20881bedee8c1ad4f9bfc5d30c7dec433cd026b57da63407c010260b1682fef4c8847e7181ea43f - languageName: node - linkType: hard - "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" @@ -28645,14 +28954,14 @@ __metadata: linkType: hard "dompurify@npm:^3.1.7, dompurify@npm:^3.2.4": - version: 3.3.0 - resolution: "dompurify@npm:3.3.0" + version: 3.3.1 + resolution: "dompurify@npm:3.3.1" dependencies: "@types/trusted-types": "npm:^2.0.7" dependenciesMeta: "@types/trusted-types": optional: true - checksum: 10/d8782b10a0454344476936c91038d06c9450b3e3ada2ceb8f722525e6b54e64d847939b9f35bf385facd4139f0a2eaf7f5553efce351f8e9295620570875f002 + checksum: 10/f71cca489e628591165d16e8cf4fa4f0d3e2ee48db4d73e9d2c5bedc6f915c92f9e9f101f8c4ba790bec0cdffe7f4e1747f5e31c69dc53ce7ae20a81ff6b0022 languageName: node linkType: hard @@ -28931,6 +29240,13 @@ __metadata: languageName: node linkType: hard +"empathic@npm:^2.0.0": + version: 2.0.0 + resolution: "empathic@npm:2.0.0" + checksum: 10/90f47d93f8d1db3aa00ce1bfae2940bf76379dbb34bd562edbd92c3564a173cb1d6bd3cadb645fad0224839c25886abde801155d9b972dda6add7a5cc8b35d48 + languageName: node + linkType: hard + "enabled@npm:2.0.x": version: 2.0.0 resolution: "enabled@npm:2.0.0" @@ -29022,6 +29338,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10/62af1307202884349d2867f0aac5c60d8b57102ea0b0e768b16246099512c28e239254ad772d6834e7e14cb1b6f153fc3d0c031934e3183b086c86d3838d874a + languageName: node + linkType: hard + "entities@npm:~2.1.0": version: 2.1.0 resolution: "entities@npm:2.1.0" @@ -29328,107 +29651,7 @@ __metadata: languageName: node linkType: hard -"esbuild-register@npm:^3.5.0": - version: 3.6.0 - resolution: "esbuild-register@npm:3.6.0" - dependencies: - debug: "npm:^4.3.4" - peerDependencies: - esbuild: ">=0.12 <1" - checksum: 10/4ae1a016e3dad5b53c3d68cf07e31d8c1cec1a0b584038ece726097ac80bd33ab48fb224c766c9b341c04793837e652461eaca9327a116e7564f553b61ccca71 - languageName: node - linkType: hard - -"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0, esbuild@npm:^0.25.0": - version: 0.25.8 - resolution: "esbuild@npm:0.25.8" - dependencies: - "@esbuild/aix-ppc64": "npm:0.25.8" - "@esbuild/android-arm": "npm:0.25.8" - "@esbuild/android-arm64": "npm:0.25.8" - "@esbuild/android-x64": "npm:0.25.8" - "@esbuild/darwin-arm64": "npm:0.25.8" - "@esbuild/darwin-x64": "npm:0.25.8" - "@esbuild/freebsd-arm64": "npm:0.25.8" - "@esbuild/freebsd-x64": "npm:0.25.8" - "@esbuild/linux-arm": "npm:0.25.8" - "@esbuild/linux-arm64": "npm:0.25.8" - "@esbuild/linux-ia32": "npm:0.25.8" - "@esbuild/linux-loong64": "npm:0.25.8" - "@esbuild/linux-mips64el": "npm:0.25.8" - "@esbuild/linux-ppc64": "npm:0.25.8" - "@esbuild/linux-riscv64": "npm:0.25.8" - "@esbuild/linux-s390x": "npm:0.25.8" - "@esbuild/linux-x64": "npm:0.25.8" - "@esbuild/netbsd-arm64": "npm:0.25.8" - "@esbuild/netbsd-x64": "npm:0.25.8" - "@esbuild/openbsd-arm64": "npm:0.25.8" - "@esbuild/openbsd-x64": "npm:0.25.8" - "@esbuild/openharmony-arm64": "npm:0.25.8" - "@esbuild/sunos-x64": "npm:0.25.8" - "@esbuild/win32-arm64": "npm:0.25.8" - "@esbuild/win32-ia32": "npm:0.25.8" - "@esbuild/win32-x64": "npm:0.25.8" - dependenciesMeta: - "@esbuild/aix-ppc64": - optional: true - "@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-arm64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-arm64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/openharmony-arm64": - 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: 10/9897411732768e652d90fa5dfadae965e8f420d24e5f23fa0604331a1441769e2c7ee4e41ca53e926f1fb51a53af52e01fc9070fdc1a4edf3e9ec9208ee41273 - languageName: node - linkType: hard - -"esbuild@npm:^0.27.0": +"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0, esbuild@npm:^0.27.0": version: 0.27.1 resolution: "esbuild@npm:0.27.1" dependencies: @@ -29517,6 +29740,95 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.25.0": + version: 0.25.8 + resolution: "esbuild@npm:0.25.8" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.8" + "@esbuild/android-arm": "npm:0.25.8" + "@esbuild/android-arm64": "npm:0.25.8" + "@esbuild/android-x64": "npm:0.25.8" + "@esbuild/darwin-arm64": "npm:0.25.8" + "@esbuild/darwin-x64": "npm:0.25.8" + "@esbuild/freebsd-arm64": "npm:0.25.8" + "@esbuild/freebsd-x64": "npm:0.25.8" + "@esbuild/linux-arm": "npm:0.25.8" + "@esbuild/linux-arm64": "npm:0.25.8" + "@esbuild/linux-ia32": "npm:0.25.8" + "@esbuild/linux-loong64": "npm:0.25.8" + "@esbuild/linux-mips64el": "npm:0.25.8" + "@esbuild/linux-ppc64": "npm:0.25.8" + "@esbuild/linux-riscv64": "npm:0.25.8" + "@esbuild/linux-s390x": "npm:0.25.8" + "@esbuild/linux-x64": "npm:0.25.8" + "@esbuild/netbsd-arm64": "npm:0.25.8" + "@esbuild/netbsd-x64": "npm:0.25.8" + "@esbuild/openbsd-arm64": "npm:0.25.8" + "@esbuild/openbsd-x64": "npm:0.25.8" + "@esbuild/openharmony-arm64": "npm:0.25.8" + "@esbuild/sunos-x64": "npm:0.25.8" + "@esbuild/win32-arm64": "npm:0.25.8" + "@esbuild/win32-ia32": "npm:0.25.8" + "@esbuild/win32-x64": "npm:0.25.8" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@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-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + 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: 10/9897411732768e652d90fa5dfadae965e8f420d24e5f23fa0604331a1441769e2c7ee4e41ca53e926f1fb51a53af52e01fc9070fdc1a4edf3e9ec9208ee41273 + languageName: node + linkType: hard + "esbuild@npm:esbuild-wasm@^0.23.0": version: 0.23.1 resolution: "esbuild-wasm@npm:0.23.1" @@ -29594,7 +29906,7 @@ __metadata: languageName: node linkType: hard -"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0": +"escodegen@npm:^2.1.0": version: 2.1.0 resolution: "escodegen@npm:2.1.0" dependencies: @@ -29795,15 +30107,15 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-storybook@npm:^9.1.7": - version: 9.1.16 - resolution: "eslint-plugin-storybook@npm:9.1.16" +"eslint-plugin-storybook@npm:^10.1.9": + version: 10.1.9 + resolution: "eslint-plugin-storybook@npm:10.1.9" dependencies: "@typescript-eslint/utils": "npm:^8.8.1" peerDependencies: eslint: ">=8" - storybook: ^9.1.16 - checksum: 10/3142e70ee2a8cead5c891b76861914dc5e675d85be758171e4c63db912351e57da0ce4cbccf5a3cf7aaf9cf8fc2f40cf6110ef9a459d0c61cef287b82570e88b + storybook: ^10.1.9 + checksum: 10/65ea272cf450373d8b1f718f6c1ab878309f88b7cb2b27071b941d2b9d3402b0a102c1a83565c3bec64a9bc4a99ccbc8c25860fdf3112fed4dbfbe56361b0213 languageName: node linkType: hard @@ -30134,7 +30446,7 @@ __metadata: languageName: node linkType: hard -"eventsource@npm:^3.0.2, eventsource@npm:^3.0.6": +"eventsource@npm:^3.0.2": version: 3.0.7 resolution: "eventsource@npm:3.0.7" dependencies: @@ -30143,6 +30455,15 @@ __metadata: languageName: node linkType: hard +"eventsource@npm:^4.0.0": + version: 4.1.0 + resolution: "eventsource@npm:4.1.0" + dependencies: + eventsource-parser: "npm:^3.0.1" + checksum: 10/d23b1c2a56a1dd7344a151ca57d70ebc624972150395c1c82110bda1d2918487260e8ec76c1c79677406184ecb1847509a675d4ee5367925ef77f03c9cae594d + languageName: node + linkType: hard + "evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": version: 1.0.3 resolution: "evp_bytestokey@npm:1.0.3" @@ -30360,7 +30681,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:^5.0.0, execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -30408,10 +30729,10 @@ __metadata: languageName: node linkType: hard -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: 10/387555050c5b3c10e7a9e8df5f43194e95d7737c74532c409910e585d5554eaff34960c166643f5e23d042196529daad059c292dcf1fb61b8ca878d3677f4b87 +"exit-x@npm:^0.2.2": + version: 0.2.2 + resolution: "exit-x@npm:0.2.2" + checksum: 10/ee043053e6c1e237adf5ad9c4faf9f085b606f64a4ff859e2b138fab63fe642711d00c9af452a9134c4c92c55f752e818bfabab78c24d345022db163f3137027 languageName: node linkType: hard @@ -30431,16 +30752,17 @@ __metadata: languageName: node linkType: hard -"expect@npm:>28.1.3, expect@npm:^29.0.0, expect@npm:^29.7.0": - version: 29.7.0 - resolution: "expect@npm:29.7.0" +"expect@npm:30.2.0, expect@npm:>28.1.3, expect@npm:^30.0.0": + version: 30.2.0 + resolution: "expect@npm:30.2.0" dependencies: - "@jest/expect-utils": "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/63f97bc51f56a491950fb525f9ad94f1916e8a014947f8d8445d3847a665b5471b768522d659f5e865db20b6c2033d2ac10f35fcbd881a4d26407a4f6f18451a + "@jest/expect-utils": "npm:30.2.0" + "@jest/get-type": "npm:30.1.0" + jest-matcher-utils: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-mock: "npm:30.2.0" + jest-util: "npm:30.2.0" + checksum: 10/cf98ab45ab2e9f2fb9943a3ae0097f72d63a94be179a19fd2818d8fdc3b7681d31cc8ef540606eb8dd967d9c44d73fef263a614e9de260c22943ffb122ad66fd languageName: node linkType: hard @@ -30806,12 +31128,12 @@ __metadata: languageName: node linkType: hard -"fb-watchman@npm:^2.0.0": - version: 2.0.1 - resolution: "fb-watchman@npm:2.0.1" +"fb-watchman@npm:^2.0.2": + version: 2.0.2 + resolution: "fb-watchman@npm:2.0.2" dependencies: bser: "npm:2.1.1" - checksum: 10/9a03efc7d41ce3ca3d799d63505a1f7312caddf4e7737d39f2165bfe4872cbd4b87eccc9e6c57229ea08f14b4d7187896da31a7270b8da7a4aaa8fba2d3d1c42 + checksum: 10/4f95d336fb805786759e383fd7fff342ceb7680f53efcc0ef82f502eb479ce35b98e8b207b6dfdfeea0eba845862107dc73813775fc6b56b3098c6e90a2dad77 languageName: node linkType: hard @@ -31137,17 +31459,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^7.0.0": - version: 7.0.0 - resolution: "find-up@npm:7.0.0" - dependencies: - locate-path: "npm:^7.2.0" - path-exists: "npm:^5.0.0" - unicorn-magic: "npm:^0.1.0" - checksum: 10/7e6b08fbc05a10677e25e74bb0a020054a86b31d1806c5e6a9e32e75472bbf177210bc16e5f97453be8bda7ae2e3d97669dbb2901f8c30b39ce53929cbea6746 - languageName: node - linkType: hard - "find-yarn-workspace-root2@npm:1.2.16": version: 1.2.16 resolution: "find-yarn-workspace-root2@npm:1.2.16" @@ -31595,7 +31906,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": +"fsevents@npm:^2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -31614,7 +31925,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.3#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -32057,7 +32368,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^11.0.1": +"glob@npm:^11.0.1, glob@npm:^11.1.0": version: 11.1.0 resolution: "glob@npm:11.1.0" dependencies: @@ -32907,15 +33218,6 @@ __metadata: languageName: node linkType: hard -"html-encoding-sniffer@npm:^3.0.0": - version: 3.0.0 - resolution: "html-encoding-sniffer@npm:3.0.0" - dependencies: - whatwg-encoding: "npm:^2.0.0" - checksum: 10/707a812ec2acaf8bb5614c8618dc81e2fb6b4399d03e95ff18b65679989a072f4e919b9bef472039301a1bbfba64063ba4c79ea6e851c653ac9db80dbefe8fe5 - languageName: node - linkType: hard - "html-encoding-sniffer@npm:^4.0.0": version: 4.0.0 resolution: "html-encoding-sniffer@npm:4.0.0" @@ -33246,9 +33548,9 @@ __metadata: linkType: hard "humanize-duration@npm:^3.25.1": - version: 3.33.1 - resolution: "humanize-duration@npm:3.33.1" - checksum: 10/e2ecc7f4b0c816355610a77dcaa96706bae1457b8cee3ddbc12d68ca8d1f1b913240c5f1419dddf9773413ef47ce6a0b4554af4a13d81a7f9e7c2566945b3169 + version: 3.33.2 + resolution: "humanize-duration@npm:3.33.2" + checksum: 10/ac6bc74b095d53e6ff320126d64c0998de213d0e38d0996f23389603c034c8f825915d4318fc19cfdb0612c4963d72d200da43cd7c28ac865bbf9a61f53418f4 languageName: node linkType: hard @@ -33475,15 +33777,15 @@ __metadata: languageName: node linkType: hard -"import-local@npm:^3.0.2": - version: 3.0.2 - resolution: "import-local@npm:3.0.2" +"import-local@npm:^3.2.0": + version: 3.2.0 + resolution: "import-local@npm:3.2.0" dependencies: pkg-dir: "npm:^4.2.0" resolve-cwd: "npm:^3.0.0" bin: import-local-fixture: fixtures/cli.js - checksum: 10/c74d9f9484c878cda1de3434613c7ff72d5dadcf20e5482542232d7c2575b713ff88701d6675fcf09a3684cb23fb407c8b333b9cbc59438712723d058d8e976c + checksum: 10/0b0b0b412b2521739fbb85eeed834a3c34de9bc67e670b3d0b86248fc460d990a7b116ad056c084b87a693ef73d1f17268d6a5be626bb43c998a8b1c8a230004 languageName: node linkType: hard @@ -34019,7 +34321,7 @@ __metadata: languageName: node linkType: hard -"is-generator-fn@npm:^2.0.0": +"is-generator-fn@npm:^2.1.0": version: 2.1.0 resolution: "is-generator-fn@npm:2.1.0" checksum: 10/a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 @@ -34658,29 +34960,16 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^5.0.4": - version: 5.1.0 - resolution: "istanbul-lib-instrument@npm:5.1.0" +"istanbul-lib-instrument@npm:^6.0.0, istanbul-lib-instrument@npm:^6.0.2": + version: 6.0.3 + resolution: "istanbul-lib-instrument@npm:6.0.3" dependencies: - "@babel/core": "npm:^7.12.3" - "@babel/parser": "npm:^7.14.7" - "@istanbuljs/schema": "npm:^0.1.2" - istanbul-lib-coverage: "npm:^3.2.0" - semver: "npm:^6.3.0" - checksum: 10/7447ba3f8049f331d5b4a1c450183e88c2fdad044149ad0d9830f71bc8da90d841c393b830bc33237ae75122c3b0e03ca845701873d6c51690bc25caa1f13a94 - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^6.0.0": - version: 6.0.1 - resolution: "istanbul-lib-instrument@npm:6.0.1" - dependencies: - "@babel/core": "npm:^7.12.3" - "@babel/parser": "npm:^7.14.7" - "@istanbuljs/schema": "npm:^0.1.2" + "@babel/core": "npm:^7.23.9" + "@babel/parser": "npm:^7.23.9" + "@istanbuljs/schema": "npm:^0.1.3" istanbul-lib-coverage: "npm:^3.2.0" semver: "npm:^7.5.4" - checksum: 10/95fd8c66e586840989cb3c7819c6da66c4742a6fedbf16b51a5c7f1898941ad07b79ddff020f479d3a1d76743ecdbf255d93c35221875687477d4b118026e7e7 + checksum: 10/aa5271c0008dfa71b6ecc9ba1e801bf77b49dc05524e8c30d58aaf5b9505e0cd12f25f93165464d4266a518c5c75284ecb598fbd89fec081ae77d2c9d3327695 languageName: node linkType: hard @@ -34695,14 +34984,14 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.0 - resolution: "istanbul-lib-source-maps@npm:4.0.0" +"istanbul-lib-source-maps@npm:^5.0.0": + version: 5.0.6 + resolution: "istanbul-lib-source-maps@npm:5.0.6" dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.23" debug: "npm:^4.1.1" istanbul-lib-coverage: "npm:^3.0.0" - source-map: "npm:^0.6.1" - checksum: 10/765252abc6b5c9d29905fc97ce04b92da87d198f2c0161e62fe0aac8bb74fb7bd472a5e1d90fe3e78723d8cad43913f08d8eefa0339536fcc33b3a1922cf5fc3 + checksum: 10/569dd0a392ee3464b1fe1accbaef5cc26de3479eacb5b91d8c67ebb7b425d39fd02247d85649c3a0e9c29b600809fa60b5af5a281a75a89c01f385b1e24823a2 languageName: node linkType: hard @@ -34797,106 +35086,110 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-changed-files@npm:29.7.0" +"jest-changed-files@npm:30.2.0": + version: 30.2.0 + resolution: "jest-changed-files@npm:30.2.0" dependencies: - execa: "npm:^5.0.0" - jest-util: "npm:^29.7.0" + execa: "npm:^5.1.1" + jest-util: "npm:30.2.0" p-limit: "npm:^3.1.0" - checksum: 10/3d93742e56b1a73a145d55b66e96711fbf87ef89b96c2fab7cfdfba8ec06612591a982111ca2b712bb853dbc16831ec8b43585a2a96b83862d6767de59cbf83d + checksum: 10/ff2275ed5839b88c12ffa66fdc5c17ba02d3e276be6b558bed92872c282d050c3fdd1a275a81187cbe35c16d6d40337b85838772836463c7a2fbd1cba9785ca0 languageName: node linkType: hard -"jest-circus@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-circus@npm:29.7.0" +"jest-circus@npm:30.2.0": + version: 30.2.0 + resolution: "jest-circus@npm:30.2.0" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/expect": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/environment": "npm:30.2.0" + "@jest/expect": "npm:30.2.0" + "@jest/test-result": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - chalk: "npm:^4.0.0" + chalk: "npm:^4.1.2" co: "npm:^4.6.0" - dedent: "npm:^1.0.0" - is-generator-fn: "npm:^2.0.0" - jest-each: "npm:^29.7.0" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" + dedent: "npm:^1.6.0" + is-generator-fn: "npm:^2.1.0" + jest-each: "npm:30.2.0" + jest-matcher-utils: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-runtime: "npm:30.2.0" + jest-snapshot: "npm:30.2.0" + jest-util: "npm:30.2.0" p-limit: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - pure-rand: "npm:^6.0.0" + pretty-format: "npm:30.2.0" + pure-rand: "npm:^7.0.0" slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/716a8e3f40572fd0213bcfc1da90274bf30d856e5133af58089a6ce45089b63f4d679bd44e6be9d320e8390483ebc3ae9921981993986d21639d9019b523123d + stack-utils: "npm:^2.0.6" + checksum: 10/68bfc65d92385db1017643988215e4ff5af0b10bcab86fb749a063be6bb7d5eb556dc53dd21bedf833a19aa6ae1a781a8d27b2bea25562de02d294b3017435a9 languageName: node linkType: hard -"jest-cli@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-cli@npm:29.7.0" +"jest-cli@npm:30.2.0": + version: 30.2.0 + resolution: "jest-cli@npm:30.2.0" dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - create-jest: "npm:^29.7.0" - exit: "npm:^0.1.2" - import-local: "npm:^3.0.2" - jest-config: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - yargs: "npm:^17.3.1" + "@jest/core": "npm:30.2.0" + "@jest/test-result": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + chalk: "npm:^4.1.2" + exit-x: "npm:^0.2.2" + import-local: "npm:^3.2.0" + jest-config: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-validate: "npm:30.2.0" + yargs: "npm:^17.7.2" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true bin: - jest: bin/jest.js - checksum: 10/6cc62b34d002c034203065a31e5e9a19e7c76d9e8ef447a6f70f759c0714cb212c6245f75e270ba458620f9c7b26063cd8cf6cd1f7e3afd659a7cc08add17307 + jest: ./bin/jest.js + checksum: 10/1cc8304f0e2608801c84cdecce9565a6178f668a6475aed3767a1d82cc539915f98e7404d7c387510313684011dc3095c15397d6725f73aac80fbd96c4155faa languageName: node linkType: hard -"jest-config@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-config@npm:29.7.0" +"jest-config@npm:30.2.0": + version: 30.2.0 + resolution: "jest-config@npm:30.2.0" dependencies: - "@babel/core": "npm:^7.11.6" - "@jest/test-sequencer": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-jest: "npm:^29.7.0" - chalk: "npm:^4.0.0" - ci-info: "npm:^3.2.0" - deepmerge: "npm:^4.2.2" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-circus: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-runner: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - micromatch: "npm:^4.0.4" + "@babel/core": "npm:^7.27.4" + "@jest/get-type": "npm:30.1.0" + "@jest/pattern": "npm:30.0.1" + "@jest/test-sequencer": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + babel-jest: "npm:30.2.0" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.2.0" + deepmerge: "npm:^4.3.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.11" + jest-circus: "npm:30.2.0" + jest-docblock: "npm:30.2.0" + jest-environment-node: "npm:30.2.0" + jest-regex-util: "npm:30.0.1" + jest-resolve: "npm:30.2.0" + jest-runner: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-validate: "npm:30.2.0" + micromatch: "npm:^4.0.8" parse-json: "npm:^5.2.0" - pretty-format: "npm:^29.7.0" + pretty-format: "npm:30.2.0" slash: "npm:^3.0.0" strip-json-comments: "npm:^3.1.1" peerDependencies: "@types/node": "*" + esbuild-register: ">=3.4.0" ts-node: ">=9.0.0" peerDependenciesMeta: "@types/node": optional: true + esbuild-register: + optional: true ts-node: optional: true - checksum: 10/6bdf570e9592e7d7dd5124fc0e21f5fe92bd15033513632431b211797e3ab57eaa312f83cc6481b3094b72324e369e876f163579d60016677c117ec4853cf02b + checksum: 10/296786b0a3d62de77e2f691f208d54ab541c1a73f87747d922eda643c6f25b89125ef3150170c07a6c8a316a30c15428e46237d499f688b0777f38de8a61ad16 languageName: node linkType: hard @@ -34909,7 +35202,19 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.2.0, jest-diff@npm:^29.7.0": +"jest-diff@npm:30.2.0": + version: 30.2.0 + resolution: "jest-diff@npm:30.2.0" + dependencies: + "@jest/diff-sequences": "npm:30.0.1" + "@jest/get-type": "npm:30.1.0" + chalk: "npm:^4.1.2" + pretty-format: "npm:30.2.0" + checksum: 10/1fb9e4fb7dff81814b4f69eaa7db28e184d62306a3a8ea2447d02ca53d2cfa771e83ede513f67ec5239dffacfaac32ff2b49866d211e4c7516f51c1fc06ede42 + languageName: node + linkType: hard + +"jest-diff@npm:^29.2.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" dependencies: @@ -34921,60 +35226,40 @@ __metadata: languageName: node linkType: hard -"jest-docblock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-docblock@npm:29.7.0" +"jest-docblock@npm:30.2.0": + version: 30.2.0 + resolution: "jest-docblock@npm:30.2.0" dependencies: - detect-newline: "npm:^3.0.0" - checksum: 10/8d48818055bc96c9e4ec2e217a5a375623c0d0bfae8d22c26e011074940c202aa2534a3362294c81d981046885c05d304376afba9f2874143025981148f3e96d + detect-newline: "npm:^3.1.0" + checksum: 10/e01a7d1193947ed0f9713c26bfc7852e51cb758cafec807e5665a0a8d582473a43778bee099f8aa5c70b2941963e5341f4b10bd86b036a4fa3bcec0f4c04e099 languageName: node linkType: hard -"jest-each@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-each@npm:29.7.0" +"jest-each@npm:30.2.0": + version: 30.2.0 + resolution: "jest-each@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - pretty-format: "npm:^29.7.0" - checksum: 10/bd1a077654bdaa013b590deb5f7e7ade68f2e3289180a8c8f53bc8a49f3b40740c0ec2d3a3c1aee906f682775be2bebbac37491d80b634d15276b0aa0f2e3fda + "@jest/get-type": "npm:30.1.0" + "@jest/types": "npm:30.2.0" + chalk: "npm:^4.1.2" + jest-util: "npm:30.2.0" + pretty-format: "npm:30.2.0" + checksum: 10/f95e7dc1cef4b6a77899325702a214834ae25d01276cc31279654dc7e04f63c1925a37848dd16a0d16508c0fd3d182145f43c10af93952b7a689df3aeac198e9 languageName: node linkType: hard -"jest-environment-jsdom@npm:^29.0.2": - version: 29.7.0 - resolution: "jest-environment-jsdom@npm:29.7.0" +"jest-environment-node@npm:30.2.0": + version: 30.2.0 + resolution: "jest-environment-node@npm:30.2.0" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/jsdom": "npm:^20.0.0" + "@jest/environment": "npm:30.2.0" + "@jest/fake-timers": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jsdom: "npm:^20.0.0" - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - checksum: 10/23bbfc9bca914baef4b654f7983175a4d49b0f515a5094ebcb8f819f28ec186f53c0ba06af1855eac04bab1457f4ea79dae05f70052cf899863e8096daa6e0f5 - languageName: node - linkType: hard - -"jest-environment-node@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-environment-node@npm:29.7.0" - dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - "@types/node": "npm:*" - jest-mock: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - checksum: 10/9cf7045adf2307cc93aed2f8488942e39388bff47ec1df149a997c6f714bfc66b2056768973770d3f8b1bf47396c19aa564877eb10ec978b952c6018ed1bd637 + jest-mock: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-validate: "npm:30.2.0" + checksum: 10/7918bfea7367bd3e12dbbc4ea5afb193b5c47e480a6d1382512f051e2f028458fc9f5ef2f6260737ad41a0b1894661790ff3aaf3cbb4148a33ce2ce7aec64847 languageName: node linkType: hard @@ -34985,111 +35270,87 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:29.7.0": - version: 29.7.0 - resolution: "jest-haste-map@npm:29.7.0" +"jest-haste-map@npm:30.2.0": + version: 30.2.0 + resolution: "jest-haste-map@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" - "@types/graceful-fs": "npm:^4.1.3" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - anymatch: "npm:^3.0.3" - fb-watchman: "npm:^2.0.0" - fsevents: "npm:^2.3.2" - graceful-fs: "npm:^4.2.9" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - micromatch: "npm:^4.0.4" + anymatch: "npm:^3.1.3" + fb-watchman: "npm:^2.0.2" + fsevents: "npm:^2.3.3" + graceful-fs: "npm:^4.2.11" + jest-regex-util: "npm:30.0.1" + jest-util: "npm:30.2.0" + jest-worker: "npm:30.2.0" + micromatch: "npm:^4.0.8" walker: "npm:^1.0.8" dependenciesMeta: fsevents: optional: true - checksum: 10/8531b42003581cb18a69a2774e68c456fb5a5c3280b1b9b77475af9e346b6a457250f9d756bfeeae2fe6cbc9ef28434c205edab9390ee970a919baddfa08bb85 + checksum: 10/a88be6b0b672144aa30fe2d72e630d639c8d8729ee2cef84d0f830eac2005ac021cd8354f8ed8ecd74223f6a8b281efb62f466f5c9e01ed17650e38761051f4c languageName: node linkType: hard -"jest-haste-map@patch:jest-haste-map@npm%3A29.7.0#./.yarn/patches/jest-haste-map-npm-29.7.0-e3be419eff.patch::locator=root%40workspace%3A.": - version: 29.7.0 - resolution: "jest-haste-map@patch:jest-haste-map@npm%3A29.7.0#./.yarn/patches/jest-haste-map-npm-29.7.0-e3be419eff.patch::version=29.7.0&hash=feed88&locator=root%40workspace%3A." +"jest-leak-detector@npm:30.2.0": + version: 30.2.0 + resolution: "jest-leak-detector@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" - "@types/graceful-fs": "npm:^4.1.3" - "@types/node": "npm:*" - anymatch: "npm:^3.0.3" - fb-watchman: "npm:^2.0.0" - fsevents: "npm:^2.3.2" - graceful-fs: "npm:^4.2.9" - jest-regex-util: "npm:^29.6.3" - jest-util: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" - micromatch: "npm:^4.0.4" - walker: "npm:^1.0.8" - dependenciesMeta: - fsevents: - optional: true - checksum: 10/e93fab6316f0cdb5e930491efe87e9957a83200a58c37acedbea84472fbf67472675e3235d249b04726aaf09a23a5eadc4a7890e85969e2a8c7bf6b402c1ff5e + "@jest/get-type": "npm:30.1.0" + pretty-format: "npm:30.2.0" + checksum: 10/c430d6ed7910b2174738fbdca4ea64cbfe805216414c0d143c1090148f1389fec99d0733c0a8ed0a86709c89b4a4085b4749ac3a2cbc7deaf3ca87457afd24fc languageName: node linkType: hard -"jest-leak-detector@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-leak-detector@npm:29.7.0" +"jest-matcher-utils@npm:30.2.0": + version: 30.2.0 + resolution: "jest-matcher-utils@npm:30.2.0" dependencies: - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/e3950e3ddd71e1d0c22924c51a300a1c2db6cf69ec1e51f95ccf424bcc070f78664813bef7aed4b16b96dfbdeea53fe358f8aeaaea84346ae15c3735758f1605 + "@jest/get-type": "npm:30.1.0" + chalk: "npm:^4.1.2" + jest-diff: "npm:30.2.0" + pretty-format: "npm:30.2.0" + checksum: 10/f3f1ecf68ca63c9d1d80a175637a8fc655edfd1ee83220f6e3f6bd464ecbe2f93148fdd440a5a5e5a2b0b2cc8ee84ddc3dcef58a6dbc66821c792f48d260c6d4 languageName: node linkType: hard -"jest-matcher-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-matcher-utils@npm:29.7.0" +"jest-message-util@npm:30.2.0": + version: 30.2.0 + resolution: "jest-message-util@npm:30.2.0" dependencies: - chalk: "npm:^4.0.0" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - pretty-format: "npm:^29.7.0" - checksum: 10/981904a494299cf1e3baed352f8a3bd8b50a8c13a662c509b6a53c31461f94ea3bfeffa9d5efcfeb248e384e318c87de7e3baa6af0f79674e987482aa189af40 - languageName: node - linkType: hard - -"jest-message-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-message-util@npm:29.7.0" - dependencies: - "@babel/code-frame": "npm:^7.12.13" - "@jest/types": "npm:^29.6.3" - "@types/stack-utils": "npm:^2.0.0" - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.7.0" + "@babel/code-frame": "npm:^7.27.1" + "@jest/types": "npm:30.2.0" + "@types/stack-utils": "npm:^2.0.3" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" + micromatch: "npm:^4.0.8" + pretty-format: "npm:30.2.0" slash: "npm:^3.0.0" - stack-utils: "npm:^2.0.3" - checksum: 10/31d53c6ed22095d86bab9d14c0fa70c4a92c749ea6ceece82cf30c22c9c0e26407acdfbdb0231435dc85a98d6d65ca0d9cbcd25cd1abb377fe945e843fb770b9 + stack-utils: "npm:^2.0.6" + checksum: 10/e29ec76e8c8e4da5f5b25198be247535626ccf3a940e93fdd51fc6a6bcf70feaa2921baae3806182a090431d90b08c939eb13fb64249b171d2e9ae3a452a8fd2 languageName: node linkType: hard -"jest-mock@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-mock@npm:29.7.0" +"jest-mock@npm:30.2.0": + version: 30.2.0 + resolution: "jest-mock@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - jest-util: "npm:^29.7.0" - checksum: 10/ae51d1b4f898724be5e0e52b2268a68fcd876d9b20633c864a6dd6b1994cbc48d62402b0f40f3a1b669b30ebd648821f086c26c08ffde192ced951ff4670d51c + jest-util: "npm:30.2.0" + checksum: 10/cde9b56805f90bf811a9231873ee88a0fb83bf4bf50972ae76960725da65220fcb119688f2e90e1ef33fbfd662194858d7f43809d881f1c41bb55d94e62adeab languageName: node linkType: hard -"jest-pnp-resolver@npm:^1.2.2": - version: 1.2.2 - resolution: "jest-pnp-resolver@npm:1.2.2" +"jest-pnp-resolver@npm:^1.2.3": + version: 1.2.3 + resolution: "jest-pnp-resolver@npm:1.2.3" peerDependencies: jest-resolve: "*" peerDependenciesMeta: jest-resolve: optional: true - checksum: 10/bd85dcc0e76e0eb0c3d56382ec140f08d25ff4068cda9d0e360bb78fb176cb726d0beab82dc0e8694cafd09f55fee7622b8bcb240afa5fad301f4ed3eebb4f47 + checksum: 10/db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 languageName: node linkType: hard @@ -35100,124 +35361,132 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-regex-util@npm:29.6.3" - checksum: 10/0518beeb9bf1228261695e54f0feaad3606df26a19764bc19541e0fc6e2a3737191904607fb72f3f2ce85d9c16b28df79b7b1ec9443aa08c3ef0e9efda6f8f2a +"jest-resolve-dependencies@npm:30.2.0": + version: 30.2.0 + resolution: "jest-resolve-dependencies@npm:30.2.0" + dependencies: + jest-regex-util: "npm:30.0.1" + jest-snapshot: "npm:30.2.0" + checksum: 10/0ff1a574f8c07f2e54a4ac8ab17aea00dfe2982e99b03fbd44f4211a94b8e5a59fdc43a59f9d6c0578a10a7b56a0611ad5ab40e4893973ff3f40dd414433b194 languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve-dependencies@npm:29.7.0" +"jest-resolve@npm:30.2.0": + version: 30.2.0 + resolution: "jest-resolve@npm:30.2.0" dependencies: - jest-regex-util: "npm:^29.6.3" - jest-snapshot: "npm:^29.7.0" - checksum: 10/1e206f94a660d81e977bcfb1baae6450cb4a81c92e06fad376cc5ea16b8e8c6ea78c383f39e95591a9eb7f925b6a1021086c38941aa7c1b8a6a813c2f6e93675 - languageName: node - linkType: hard - -"jest-resolve@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-resolve@npm:29.7.0" - dependencies: - chalk: "npm:^4.0.0" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-pnp-resolver: "npm:^1.2.2" - jest-util: "npm:^29.7.0" - jest-validate: "npm:^29.7.0" - resolve: "npm:^1.20.0" - resolve.exports: "npm:^2.0.0" + chalk: "npm:^4.1.2" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.2.0" + jest-pnp-resolver: "npm:^1.2.3" + jest-util: "npm:30.2.0" + jest-validate: "npm:30.2.0" slash: "npm:^3.0.0" - checksum: 10/faa466fd9bc69ea6c37a545a7c6e808e073c66f46ab7d3d8a6ef084f8708f201b85d5fe1799789578b8b47fa1de47b9ee47b414d1863bc117a49e032ba77b7c7 + unrs-resolver: "npm:^1.7.11" + checksum: 10/e1f03da6811a946f5d885ea739a973975d099cc760641f9e1f90ac9c6621408538ba1e909f789d45d6e8d2411b78fb09230f16f15669621aa407aed7511fdf01 languageName: node linkType: hard -"jest-runner@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runner@npm:29.7.0" +"jest-runner@npm:30.2.0": + version: 30.2.0 + resolution: "jest-runner@npm:30.2.0" dependencies: - "@jest/console": "npm:^29.7.0" - "@jest/environment": "npm:^29.7.0" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/console": "npm:30.2.0" + "@jest/environment": "npm:30.2.0" + "@jest/test-result": "npm:30.2.0" + "@jest/transform": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - chalk: "npm:^4.0.0" + chalk: "npm:^4.1.2" emittery: "npm:^0.13.1" - graceful-fs: "npm:^4.2.9" - jest-docblock: "npm:^29.7.0" - jest-environment-node: "npm:^29.7.0" - jest-haste-map: "npm:^29.7.0" - jest-leak-detector: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-resolve: "npm:^29.7.0" - jest-runtime: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - jest-watcher: "npm:^29.7.0" - jest-worker: "npm:^29.7.0" + exit-x: "npm:^0.2.2" + graceful-fs: "npm:^4.2.11" + jest-docblock: "npm:30.2.0" + jest-environment-node: "npm:30.2.0" + jest-haste-map: "npm:30.2.0" + jest-leak-detector: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-resolve: "npm:30.2.0" + jest-runtime: "npm:30.2.0" + jest-util: "npm:30.2.0" + jest-watcher: "npm:30.2.0" + jest-worker: "npm:30.2.0" p-limit: "npm:^3.1.0" source-map-support: "npm:0.5.13" - checksum: 10/9d8748a494bd90f5c82acea99be9e99f21358263ce6feae44d3f1b0cd90991b5df5d18d607e73c07be95861ee86d1cbab2a3fc6ca4b21805f07ac29d47c1da1e + checksum: 10/d3706aa70e64a7ef8b38360d34ea6c261ba4d0b42136d7fb603c4fa71c24fa81f22c39ed2e39ee0db2363a42827810291f3ceb6a299e5996b41d701ad9b24184 languageName: node linkType: hard -"jest-runtime@npm:^29.0.2, jest-runtime@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-runtime@npm:29.7.0" +"jest-runtime@npm:30.2.0": + version: 30.2.0 + resolution: "jest-runtime@npm:30.2.0" dependencies: - "@jest/environment": "npm:^29.7.0" - "@jest/fake-timers": "npm:^29.7.0" - "@jest/globals": "npm:^29.7.0" - "@jest/source-map": "npm:^29.6.3" - "@jest/test-result": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/environment": "npm:30.2.0" + "@jest/fake-timers": "npm:30.2.0" + "@jest/globals": "npm:30.2.0" + "@jest/source-map": "npm:30.0.1" + "@jest/test-result": "npm:30.2.0" + "@jest/transform": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - chalk: "npm:^4.0.0" - cjs-module-lexer: "npm:^1.0.0" - collect-v8-coverage: "npm:^1.0.0" - glob: "npm:^7.1.3" - graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-mock: "npm:^29.7.0" - jest-regex-util: "npm:^29.6.3" - jest-resolve: "npm:^29.7.0" - jest-snapshot: "npm:^29.7.0" - jest-util: "npm:^29.7.0" + chalk: "npm:^4.1.2" + cjs-module-lexer: "npm:^2.1.0" + collect-v8-coverage: "npm:^1.0.2" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.11" + jest-haste-map: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-mock: "npm:30.2.0" + jest-regex-util: "npm:30.0.1" + jest-resolve: "npm:30.2.0" + jest-snapshot: "npm:30.2.0" + jest-util: "npm:30.2.0" slash: "npm:^3.0.0" strip-bom: "npm:^4.0.0" - checksum: 10/59eb58eb7e150e0834a2d0c0d94f2a0b963ae7182cfa6c63f2b49b9c6ef794e5193ef1634e01db41420c36a94cefc512cdd67a055cd3e6fa2f41eaf0f82f5a20 + checksum: 10/81a3a9951420863f001e74c510bf35b85ae983f636f43ee1ffa1618b5a8ddafb681bc2810f71814bc8c8373e9593c89576b2325daf3c765e50057e48d5941df3 languageName: node linkType: hard -"jest-snapshot@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-snapshot@npm:29.7.0" +"jest-snapshot@npm:30.2.0": + version: 30.2.0 + resolution: "jest-snapshot@npm:30.2.0" dependencies: - "@babel/core": "npm:^7.11.6" - "@babel/generator": "npm:^7.7.2" - "@babel/plugin-syntax-jsx": "npm:^7.7.2" - "@babel/plugin-syntax-typescript": "npm:^7.7.2" - "@babel/types": "npm:^7.3.3" - "@jest/expect-utils": "npm:^29.7.0" - "@jest/transform": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - babel-preset-current-node-syntax: "npm:^1.0.0" - chalk: "npm:^4.0.0" - expect: "npm:^29.7.0" - graceful-fs: "npm:^4.2.9" - jest-diff: "npm:^29.7.0" - jest-get-type: "npm:^29.6.3" - jest-matcher-utils: "npm:^29.7.0" - jest-message-util: "npm:^29.7.0" - jest-util: "npm:^29.7.0" - natural-compare: "npm:^1.4.0" - pretty-format: "npm:^29.7.0" - semver: "npm:^7.5.3" - checksum: 10/cb19a3948256de5f922d52f251821f99657339969bf86843bd26cf3332eae94883e8260e3d2fba46129a27c3971c1aa522490e460e16c7fad516e82d10bbf9f8 + "@babel/core": "npm:^7.27.4" + "@babel/generator": "npm:^7.27.5" + "@babel/plugin-syntax-jsx": "npm:^7.27.1" + "@babel/plugin-syntax-typescript": "npm:^7.27.1" + "@babel/types": "npm:^7.27.3" + "@jest/expect-utils": "npm:30.2.0" + "@jest/get-type": "npm:30.1.0" + "@jest/snapshot-utils": "npm:30.2.0" + "@jest/transform": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + babel-preset-current-node-syntax: "npm:^1.2.0" + chalk: "npm:^4.1.2" + expect: "npm:30.2.0" + graceful-fs: "npm:^4.2.11" + jest-diff: "npm:30.2.0" + jest-matcher-utils: "npm:30.2.0" + jest-message-util: "npm:30.2.0" + jest-util: "npm:30.2.0" + pretty-format: "npm:30.2.0" + semver: "npm:^7.7.2" + synckit: "npm:^0.11.8" + checksum: 10/119390b49f397ed622ba7c375fc15f97af67c4fc49a34cf829c86ee732be2b06ad3c7171c76bb842a0e84a234783f1a4c721909aa316fbe00c6abc7c5962dfbc + languageName: node + linkType: hard + +"jest-util@npm:30.2.0": + version: 30.2.0 + resolution: "jest-util@npm:30.2.0" + dependencies: + "@jest/types": "npm:30.2.0" + "@types/node": "npm:*" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.2.0" + graceful-fs: "npm:^4.2.11" + picomatch: "npm:^4.0.2" + checksum: 10/cf2f2fb83417ea69f9992121561c95cf4e9aad7946819b771b8b52addf78811101b33b51d0a39fa0c305f2751dab262feed7699de052659ff03d51827c8862f5 languageName: node linkType: hard @@ -35235,33 +35504,33 @@ __metadata: languageName: node linkType: hard -"jest-validate@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-validate@npm:29.7.0" +"jest-validate@npm:30.2.0": + version: 30.2.0 + resolution: "jest-validate@npm:30.2.0" dependencies: - "@jest/types": "npm:^29.6.3" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.6.3" + "@jest/get-type": "npm:30.1.0" + "@jest/types": "npm:30.2.0" + camelcase: "npm:^6.3.0" + chalk: "npm:^4.1.2" leven: "npm:^3.1.0" - pretty-format: "npm:^29.7.0" - checksum: 10/8ee1163666d8eaa16d90a989edba2b4a3c8ab0ffaa95ad91b08ca42b015bfb70e164b247a5b17f9de32d096987cada63ed8491ab82761bfb9a28bc34b27ae161 + pretty-format: "npm:30.2.0" + checksum: 10/61e66c6df29a1e181f8de063678dd2096bb52cc8a8ead3c9a3f853d54eca458ad04c7fb81931d9274affb67d0504a91a2a520456a139a26665810c3bf039b677 languageName: node linkType: hard -"jest-watcher@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-watcher@npm:29.7.0" +"jest-watcher@npm:30.2.0": + version: 30.2.0 + resolution: "jest-watcher@npm:30.2.0" dependencies: - "@jest/test-result": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" + "@jest/test-result": "npm:30.2.0" + "@jest/types": "npm:30.2.0" "@types/node": "npm:*" - ansi-escapes: "npm:^4.2.1" - chalk: "npm:^4.0.0" + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^4.1.2" emittery: "npm:^0.13.1" - jest-util: "npm:^29.7.0" - string-length: "npm:^4.0.1" - checksum: 10/4f616e0345676631a7034b1d94971aaa719f0cd4a6041be2aa299be437ea047afd4fe05c48873b7963f5687a2f6c7cbf51244be8b14e313b97bfe32b1e127e55 + jest-util: "npm:30.2.0" + string-length: "npm:^4.0.2" + checksum: 10/fa38d06dcc59dbbd6a9ff22dea499d3c81ed376d9993b82d01797a99bf466d48641a99b9f3670a4b5480ca31144c5e017b96b7059e4d7541358fb48cf517a2db languageName: node linkType: hard @@ -35284,6 +35553,19 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:30.2.0": + version: 30.2.0 + resolution: "jest-worker@npm:30.2.0" + dependencies: + "@types/node": "npm:*" + "@ungap/structured-clone": "npm:^1.3.0" + jest-util: "npm:30.2.0" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.1.1" + checksum: 10/9354b0c71c80173f673da6bbc0ddaad26e4395b06532f7332e0c1e93e855b873b10139b040e01eda77f3dc5a0b67613e2bd7c56c4947ee771acfc3611de2ca29 + languageName: node + linkType: hard + "jest-worker@npm:^27.4.5": version: 27.5.1 resolution: "jest-worker@npm:27.5.1" @@ -35307,22 +35589,22 @@ __metadata: languageName: node linkType: hard -"jest@npm:^29.7.0": - version: 29.7.0 - resolution: "jest@npm:29.7.0" +"jest@npm:^30.2.0": + version: 30.2.0 + resolution: "jest@npm:30.2.0" dependencies: - "@jest/core": "npm:^29.7.0" - "@jest/types": "npm:^29.6.3" - import-local: "npm:^3.0.2" - jest-cli: "npm:^29.7.0" + "@jest/core": "npm:30.2.0" + "@jest/types": "npm:30.2.0" + import-local: "npm:^3.2.0" + jest-cli: "npm:30.2.0" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true bin: - jest: bin/jest.js - checksum: 10/97023d78446098c586faaa467fbf2c6b07ff06e2c85a19e3926adb5b0effe9ac60c4913ae03e2719f9c01ae8ffd8d92f6b262cedb9555ceeb5d19263d8c6362a + jest: ./bin/jest.js + checksum: 10/61c9d100750e4354cd7305d1f3ba253ffde4deaf12cb4be4d42d54f2dd5986e383a39c4a8691dbdc3839c69094a52413ed36f1886540ac37b71914a990b810d0 languageName: node linkType: hard @@ -35497,46 +35779,6 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^20.0.0": - version: 20.0.0 - resolution: "jsdom@npm:20.0.0" - dependencies: - abab: "npm:^2.0.6" - acorn: "npm:^8.7.1" - acorn-globals: "npm:^6.0.0" - cssom: "npm:^0.5.0" - cssstyle: "npm:^2.3.0" - data-urls: "npm:^3.0.2" - decimal.js: "npm:^10.3.1" - domexception: "npm:^4.0.0" - escodegen: "npm:^2.0.0" - form-data: "npm:^4.0.0" - html-encoding-sniffer: "npm:^3.0.0" - http-proxy-agent: "npm:^5.0.0" - https-proxy-agent: "npm:^5.0.1" - is-potential-custom-element-name: "npm:^1.0.1" - nwsapi: "npm:^2.2.0" - parse5: "npm:^7.0.0" - saxes: "npm:^6.0.0" - symbol-tree: "npm:^3.2.4" - tough-cookie: "npm:^4.0.0" - w3c-hr-time: "npm:^1.0.2" - w3c-xmlserializer: "npm:^3.0.0" - webidl-conversions: "npm:^7.0.0" - whatwg-encoding: "npm:^2.0.0" - whatwg-mimetype: "npm:^3.0.0" - whatwg-url: "npm:^11.0.0" - ws: "npm:^8.8.0" - xml-name-validator: "npm:^4.0.0" - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - checksum: 10/5492ef8f496183bbce738977a0fb43b57a269d9d79fe12ea03d33ce9821a5ef54cb1580b94a662bf2d5ba463790fb61a9e892a87eb95d02e72bdf4068280a737 - languageName: node - linkType: hard - "jsdom@npm:^25.0.1": version: 25.0.1 resolution: "jsdom@npm:25.0.1" @@ -35571,6 +35813,39 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^27.1.0": + version: 27.3.0 + resolution: "jsdom@npm:27.3.0" + dependencies: + "@acemir/cssom": "npm:^0.9.28" + "@asamuzakjp/dom-selector": "npm:^6.7.6" + cssstyle: "npm:^5.3.4" + data-urls: "npm:^6.0.0" + decimal.js: "npm:^10.6.0" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.2" + https-proxy-agent: "npm:^7.0.6" + is-potential-custom-element-name: "npm:^1.0.1" + parse5: "npm:^8.0.0" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^6.0.0" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^8.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^15.1.0" + ws: "npm:^8.18.3" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10/c650e954df04a80e7309984450ce764ae2a840810b9575b20204194dee3c5cff42e65526519cb58b946ffe66a058b7b763bad4814b3903a9c86a2c1651b8b74b + languageName: node + linkType: hard + "jsep@npm:^1.2.0, jsep@npm:^1.3.6, jsep@npm:^1.4.0": version: 1.4.0 resolution: "jsep@npm:1.4.0" @@ -36027,14 +36302,14 @@ __metadata: languageName: node linkType: hard -"jwa@npm:^2.0.0": - version: 2.0.0 - resolution: "jwa@npm:2.0.0" +"jwa@npm:^2.0.1": + version: 2.0.1 + resolution: "jwa@npm:2.0.1" dependencies: - buffer-equal-constant-time: "npm:1.0.1" + buffer-equal-constant-time: "npm:^1.0.1" ecdsa-sig-formatter: "npm:1.0.11" safe-buffer: "npm:^5.0.1" - checksum: 10/ab983f6685d99d13ddfbffef9b1c66309a536362a8412d49ba6e687d834a1240ce39290f30ac7dbe241e0ab6c76fee7ff795776ce534e11d148158c9b7193498 + checksum: 10/b04312a1de85f912b96aa3a7211717b8336945fab5b4f7cbc7800f4c80934060c0a3111576fad8d76e41ad62887d6da4b21fd4c47e45c174197f8be7dc0c1694 languageName: node linkType: hard @@ -36049,12 +36324,12 @@ __metadata: linkType: hard "jws@npm:^4.0.0": - version: 4.0.0 - resolution: "jws@npm:4.0.0" + version: 4.0.1 + resolution: "jws@npm:4.0.1" dependencies: - jwa: "npm:^2.0.0" + jwa: "npm:^2.0.1" safe-buffer: "npm:^5.0.1" - checksum: 10/1d15f4cdea376c6bd6a81002bd2cb0bf3d51d83da8f0727947b5ba3e10cf366721b8c0d099bf8c1eb99eb036e2c55e5fd5efd378ccff75a2b4e0bd10002348b9 + checksum: 10/75d7b157489fa9a72023712c58a7a7706c7e2b10eec27fabd3bb9cae0c9e492251ab72527d20a8a5f5726196f0508c320c643fddff7076657f6bca16d0ceeeeb languageName: node linkType: hard @@ -36316,15 +36591,15 @@ __metadata: linkType: hard "ldapts@npm:^8.0.6": - version: 8.0.16 - resolution: "ldapts@npm:8.0.16" + version: 8.0.25 + resolution: "ldapts@npm:8.0.25" dependencies: "@types/asn1": "npm:>=0.2.4" asn1: "npm:0.2.6" debug: "npm:4.4.3" strict-event-emitter-types: "npm:2.0.0" whatwg-url: "npm:15.1.0" - checksum: 10/06f4780f9fccdcfbb1610bb1cd119e3ac6bf6355c364ac0f8f287d43b9dc0ee82ad7347383864136a1c211d60b5a594787acae9fcf01fb4c9214879962b882a6 + checksum: 10/75fb390d5b4154b2d8c5da11e9d8123b1ae1bf50842a62a99309b90e96529939e2816c36f250dc6fb8e6f248e5da8012fe61522c058fe767f2429645649e51f5 languageName: node linkType: hard @@ -36705,15 +36980,6 @@ __metadata: languageName: node linkType: hard -"locate-path@npm:^7.2.0": - version: 7.2.0 - resolution: "locate-path@npm:7.2.0" - dependencies: - p-locate: "npm:^6.0.0" - checksum: 10/1c6d269d4efec555937081be964e8a9b4a136319c79ca1d45ac6382212a8466113c75bd89e44521ca8ecd1c47fb08523b56eee5c0712bc7d14fec5f729deeb42 - languageName: node - linkType: hard - "lodash-es@npm:^4.17.21": version: 4.17.21 resolution: "lodash-es@npm:4.17.21" @@ -37177,17 +37443,17 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.0.0, lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": +"lru-cache@npm:^10.0.0, lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0, lru-cache@npm:^10.4.3": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a languageName: node linkType: hard -"lru-cache@npm:^11.0.0": - version: 11.0.2 - resolution: "lru-cache@npm:11.0.2" - checksum: 10/25fcb66e9d91eaf17227c6abfe526a7bed5903de74f93bfde380eb8a13410c5e8d3f14fe447293f3f322a7493adf6f9f015c6f1df7a235ff24ec30f366e1c058 +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.2.2, lru-cache@npm:^11.2.4": + version: 11.2.4 + resolution: "lru-cache@npm:11.2.4" + checksum: 10/3b2da74c0b6653767f8164c38c4c4f4d7f0cc10c62bfa512663d94a830191ae6a5af742a8d88a8b30d5f9974652d3adae53931f32069139ad24fa2a18a199aca languageName: node linkType: hard @@ -37728,6 +37994,13 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.12.2": + version: 2.12.2 + resolution: "mdn-data@npm:2.12.2" + checksum: 10/854e41715a9358e69f9a530117cd6ca7e71d06176469de8d70b1e629753b6827f5bd730995c16ad3750f3c9bad92230f8e4e178de2b34926b05f5205d27d76af + languageName: node + linkType: hard + "mdurl@npm:^1.0.0, mdurl@npm:^1.0.1": version: 1.0.1 resolution: "mdurl@npm:1.0.1" @@ -38237,7 +38510,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5, micromatch@npm:^4.0.7, micromatch@npm:^4.0.8": +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.5, micromatch@npm:^4.0.7, micromatch@npm:^4.0.8": version: 4.0.8 resolution: "micromatch@npm:4.0.8" dependencies: @@ -39111,6 +39384,15 @@ __metadata: languageName: node linkType: hard +"napi-postinstall@npm:^0.3.0": + version: 0.3.4 + resolution: "napi-postinstall@npm:0.3.4" + bin: + napi-postinstall: lib/cli.js + checksum: 10/5541381508f9e1051ff3518701c7130ebac779abb3a1ffe9391fcc3cab4cc0569b0ba0952357db3f6b12909c3bb508359a7a60261ffd795feebbdab967175832 + languageName: node + linkType: hard + "native-duplexpair@npm:^1.0.0": version: 1.0.0 resolution: "native-duplexpair@npm:1.0.0" @@ -39899,10 +40181,10 @@ __metadata: languageName: node linkType: hard -"nwsapi@npm:^2.2.0, nwsapi@npm:^2.2.12": - version: 2.2.13 - resolution: "nwsapi@npm:2.2.13" - checksum: 10/f7f30a236f2ee513ea8042f1a987481dc2b900167c47f7163882f0fcfe7ccb57b5c8daaf2c91008dc20a204fcd79e050aee25001433ad99990bbed5a8c74121c +"nwsapi@npm:^2.2.12": + version: 2.2.23 + resolution: "nwsapi@npm:2.2.23" + checksum: 10/aa4a570039c33d70b51436d1bb533f3e2c33c488ccbe9b09285c46a6cee5ef266fd60103461085c6954ba52460786a8138f042958328c7c1b4763898eb3dadfa languageName: node linkType: hard @@ -40170,19 +40452,19 @@ __metadata: languageName: node linkType: hard -"open@npm:^10.0.3": - version: 10.0.3 - resolution: "open@npm:10.0.3" +"open@npm:^10.0.3, open@npm:^10.2.0": + version: 10.2.0 + resolution: "open@npm:10.2.0" dependencies: default-browser: "npm:^5.2.1" define-lazy-prop: "npm:^3.0.0" is-inside-container: "npm:^1.0.0" - is-wsl: "npm:^3.1.0" - checksum: 10/4dc757ad1d3d63490822f991e9cbe3a7c05b7249fca2eaa571cb7d191e5cec88bc37e15d8ef4fd740d8989a288b661d8da253caa8d98e8c97430ddbbb0ae4ed1 + wsl-utils: "npm:^0.1.0" + checksum: 10/e6ad9474734eac3549dcc7d85e952394856ccaee48107c453bd6a725b82e3b8ed5f427658935df27efa76b411aeef62888edea8a9e347e8e7c82632ec966b30e languageName: node linkType: hard -"open@npm:^8.0.0, open@npm:^8.0.4, open@npm:^8.4.0": +"open@npm:^8.0.0, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" dependencies: @@ -40539,15 +40821,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^4.0.0": - version: 4.0.0 - resolution: "p-limit@npm:4.0.0" - dependencies: - yocto-queue: "npm:^1.0.0" - checksum: 10/01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b - languageName: node - linkType: hard - "p-locate@npm:^3.0.0": version: 3.0.0 resolution: "p-locate@npm:3.0.0" @@ -40575,15 +40848,6 @@ __metadata: languageName: node linkType: hard -"p-locate@npm:^6.0.0": - version: 6.0.0 - resolution: "p-locate@npm:6.0.0" - dependencies: - p-limit: "npm:^4.0.0" - checksum: 10/2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 - languageName: node - linkType: hard - "p-map@npm:^2.0.0": version: 2.1.0 resolution: "p-map@npm:2.1.0" @@ -40912,11 +41176,20 @@ __metadata: linkType: hard "parse5@npm:^7.0.0, parse5@npm:^7.1.2": - version: 7.2.0 - resolution: "parse5@npm:7.2.0" + version: 7.3.0 + resolution: "parse5@npm:7.3.0" dependencies: - entities: "npm:^4.5.0" - checksum: 10/49dabfe848f00e8cad8d9198a094d667fbdecbfa5143ddf8fb708e499b5ba76426c16135c8993b1d8e01827b92e8cfab0a9a248afa6ad7cc6f38aecf5bd017e6 + entities: "npm:^6.0.0" + checksum: 10/b0e48be20b820c655b138b86fa6fb3a790de6c891aa2aba536524f8027b4dca4fe538f11a0e5cf2f6f847d120dbb9e4822dcaeb933ff1e10850a2ef0154d1d88 + languageName: node + linkType: hard + +"parse5@npm:^8.0.0": + version: 8.0.0 + resolution: "parse5@npm:8.0.0" + dependencies: + entities: "npm:^6.0.0" + checksum: 10/1973850932bb1cbd52ab64502761489fbe1bb43a52dee7ce41aac0b6c33a51a92aaee04661590b0912b739ae9ee316bce4c78c8ea34af42a7e522c983c3c6cf5 languageName: node linkType: hard @@ -41101,13 +41374,6 @@ __metadata: languageName: node linkType: hard -"path-exists@npm:^5.0.0": - version: 5.0.0 - resolution: "path-exists@npm:5.0.0" - checksum: 10/8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 - languageName: node - linkType: hard - "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -41507,7 +41773,7 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.6": +"pirates@npm:^4.0.1, pirates@npm:^4.0.6, pirates@npm:^4.0.7": version: 4.0.7 resolution: "pirates@npm:4.0.7" checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 @@ -42259,6 +42525,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:30.2.0, pretty-format@npm:^30.0.0": + version: 30.2.0 + resolution: "pretty-format@npm:30.2.0" + dependencies: + "@jest/schemas": "npm:30.0.5" + ansi-styles: "npm:^5.2.0" + react-is: "npm:^18.3.1" + checksum: 10/725890d648e3400575eebc99a334a4cd1498e0d36746313913706bbeea20ada27e17c184a3cd45c50f705c16111afa829f3450233fc0fda5eed293c69757e926 + languageName: node + linkType: hard + "pretty-format@npm:^27.0.2": version: 27.5.1 resolution: "pretty-format@npm:27.5.1" @@ -42270,7 +42547,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": +"pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" dependencies: @@ -42447,7 +42724,7 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1, prompts@npm:^2.4.2": +"prompts@npm:^2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" dependencies: @@ -42580,13 +42857,6 @@ __metadata: languageName: node linkType: hard -"psl@npm:^1.1.33": - version: 1.8.0 - resolution: "psl@npm:1.8.0" - checksum: 10/5f62a8eca06cb4a017983d15b92b0d38dc8699d637eabc8cb482c59b4106c9760f59cc8afabcb8bb7b98f0322907680d8f0f59226386fffab5248d180bc04578 - languageName: node - linkType: hard - "pstree.remy@npm:^1.1.8": version: 1.1.8 resolution: "pstree.remy@npm:1.1.8" @@ -42655,10 +42925,10 @@ __metadata: languageName: node linkType: hard -"pure-rand@npm:^6.0.0": - version: 6.0.4 - resolution: "pure-rand@npm:6.0.4" - checksum: 10/34fed0abe99d3db7ddc459c12e1eda6bff05db6a17f2017a1ae12202271ccf276fb223b442653518c719671c1b339bbf97f27ba9276dba0997c89e45c4e6a3bf +"pure-rand@npm:^7.0.0": + version: 7.0.1 + resolution: "pure-rand@npm:7.0.1" + checksum: 10/c61a576fda5032ec9763ecb000da4a8f19263b9e2f9ae9aa2759c8fbd9dc6b192b2ce78391ebd41abb394a5fedb7bcc4b03c9e6141ac8ab20882dd5717698b80 languageName: node linkType: hard @@ -43122,9 +43392,9 @@ __metadata: languageName: node linkType: hard -"react-docgen@npm:^8.0.0": - version: 8.0.1 - resolution: "react-docgen@npm:8.0.1" +"react-docgen@npm:^8.0.0, react-docgen@npm:^8.0.2": + version: 8.0.2 + resolution: "react-docgen@npm:8.0.2" dependencies: "@babel/core": "npm:^7.28.0" "@babel/traverse": "npm:^7.28.0" @@ -43136,7 +43406,7 @@ __metadata: doctrine: "npm:^3.0.0" resolve: "npm:^1.22.1" strip-indent: "npm:^4.0.0" - checksum: 10/6eb9ec3870c0f527fd05b048a842e2338825d99703312d6f4e84f3ae0e5eda427e6b4c7c07a93b21d8740e2be23e779e0237c4b2783160e285f0121711e2f47c + checksum: 10/b56f594237a0bdf1356dee6a416ab6f2f38f60a7330cbdaf1da93d366f29f6bfbbfedecd51d47f6ba2a898985c3205c369e7f6cad528478560d9363717243ff8 languageName: node linkType: hard @@ -43277,11 +43547,11 @@ __metadata: linkType: hard "react-hook-form@npm:^7.12.2": - version: 7.68.0 - resolution: "react-hook-form@npm:7.68.0" + version: 7.67.0 + resolution: "react-hook-form@npm:7.67.0" peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - checksum: 10/c9624924cd324ee5560de51715361d754d24591734b1cf2b87c95477d35f5ca01b10e94d477bebe215afd37914c5cdbd4a717ead910d8de67f346f517f5a8d92 + checksum: 10/0e74a48b2da0f79166d5c6701f78a08fd5165e901e46ce5a578f0a2f25005e861023ffb35c1a96373c23701a84c3fce2111c4aced824d2ca08c9b2420a645551 languageName: node linkType: hard @@ -43340,7 +43610,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0, react-is@npm:^18.2.0": +"react-is@npm:^18.0.0, react-is@npm:^18.2.0, react-is@npm:^18.3.1": version: 18.3.1 resolution: "react-is@npm:18.3.1" checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 @@ -44379,13 +44649,6 @@ __metadata: languageName: node linkType: hard -"resolve.exports@npm:^2.0.0": - version: 2.0.0 - resolution: "resolve.exports@npm:2.0.0" - checksum: 10/a94fe2c064c57b4cc64de8c13eab28f744ee2327af4e458f2db00b5bbc3e7bf91b59fca043e35e2a3cf70bdae2263825c926b62200e2eb78d5c55a88d14932a8 - languageName: node - linkType: hard - "resolve@npm:1.22.8": version: 1.22.8 resolution: "resolve@npm:1.22.8" @@ -44851,11 +45114,12 @@ __metadata: "@octokit/rest": "npm:^19.0.3" "@playwright/test": "npm:^1.32.3" "@spotify/eslint-plugin": "npm:^15.0.0" - "@storybook/addon-a11y": "npm:^9.1.7" - "@storybook/addon-docs": "npm:^9.1.7" - "@storybook/addon-links": "npm:^9.1.7" - "@storybook/addon-themes": "npm:^9.1.7" - "@storybook/react-vite": "npm:^9.1.7" + "@storybook/addon-a11y": "npm:^10.1.9" + "@storybook/addon-docs": "npm:^10.1.9" + "@storybook/addon-links": "npm:^10.1.9" + "@storybook/addon-themes": "npm:^10.1.9" + "@storybook/addon-vitest": "npm:^10.1.9" + "@storybook/react-vite": "npm:^10.1.9" "@techdocs/cli": "workspace:*" "@types/cacheable-request": "npm:^8.3.6" "@types/global-agent": "npm:^2.1.3" @@ -44883,7 +45147,7 @@ __metadata: shx: "npm:^0.4.0" sloc: "npm:^0.3.1" sort-package-json: "npm:^2.8.0" - storybook: "npm:^9.1.7" + storybook: "npm:^10.1.10" ts-morph: "npm:^24.0.0" typedoc: "npm:^0.28.0" typescript: "npm:~5.7.0" @@ -44912,6 +45176,13 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.8.0": + version: 0.8.0 + resolution: "rrweb-cssom@npm:0.8.0" + checksum: 10/07521ee36fb6569c17906afad1ac7ff8f099d49ade9249e190693ac36cdf27f88d9acf0cc66978935d5d0a23fca105643d7e9125b9a9d91ed9db9e02d31d7d80 + languageName: node + linkType: hard + "rtl-css-js@npm:^1.16.1": version: 1.16.1 resolution: "rtl-css-js@npm:1.16.1" @@ -45271,7 +45542,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2": +"semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.7.2": version: 7.7.3 resolution: "semver@npm:7.7.3" bin: @@ -46000,7 +46271,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3 @@ -46252,7 +46523,7 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.2, stack-utils@npm:^2.0.3": +"stack-utils@npm:^2.0.2, stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" dependencies: @@ -46343,21 +46614,21 @@ __metadata: languageName: node linkType: hard -"storybook@npm:^9.1.7": - version: 9.1.16 - resolution: "storybook@npm:9.1.16" +"storybook@npm:^10.1.10": + version: 10.1.10 + resolution: "storybook@npm:10.1.10" dependencies: "@storybook/global": "npm:^5.0.0" + "@storybook/icons": "npm:^2.0.0" "@testing-library/jest-dom": "npm:^6.6.3" "@testing-library/user-event": "npm:^14.6.1" "@vitest/expect": "npm:3.2.4" - "@vitest/mocker": "npm:3.2.4" "@vitest/spy": "npm:3.2.4" - better-opn: "npm:^3.0.2" - esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0" - esbuild-register: "npm:^3.5.0" + esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0" + open: "npm:^10.2.0" recast: "npm:^0.23.5" semver: "npm:^7.6.2" + use-sync-external-store: "npm:^1.5.0" ws: "npm:^8.18.0" peerDependencies: prettier: ^2 || ^3 @@ -46365,8 +46636,8 @@ __metadata: prettier: optional: true bin: - storybook: ./bin/index.cjs - checksum: 10/62a79c47bd0ac65af8d2de4123332a578aaff76e94ffba45293633db0c316488d7b603ffe47b23f998a872e6428c25b9fd944bc8eb203318394f421490021e96 + storybook: ./dist/bin/dispatcher.js + checksum: 10/c1f01c7ab57e80d2f2ef3a5c49baad5904e77c8e079199ad134e98a7ae455d52422390cd704e64142b36668874c055670dbffe0e334e1f4d541ebd4384052dd7 languageName: node linkType: hard @@ -46531,13 +46802,13 @@ __metadata: languageName: node linkType: hard -"string-length@npm:^4.0.1": - version: 4.0.1 - resolution: "string-length@npm:4.0.1" +"string-length@npm:^4.0.2": + version: 4.0.2 + resolution: "string-length@npm:4.0.2" dependencies: char-regex: "npm:^1.0.2" strip-ansi: "npm:^6.0.0" - checksum: 10/7bd3191668ddafa6f574a8b17a1bd1b085737d64ceefa51f72cdd19c45a730422cd70d984eee7584d6e5b5c84b6318633c6d6a720a4bfd7c58769985fa77573e + checksum: 10/ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 languageName: node linkType: hard @@ -47167,6 +47438,15 @@ __metadata: languageName: node linkType: hard +"synckit@npm:^0.11.8": + version: 0.11.11 + resolution: "synckit@npm:0.11.11" + dependencies: + "@pkgr/core": "npm:^0.2.9" + checksum: 10/6ecd88212b5be80004376b6ea74babcba284566ff59a50d8803afcaa78c165b5d268635c1dd84532ee3f690a979409e1eda225a8a35bed2d135ffdcea06ce7b0 + languageName: node + linkType: hard + "tapable@npm:^1.0.0": version: 1.1.3 resolution: "tapable@npm:1.1.3" @@ -47360,8 +47640,8 @@ __metadata: linkType: hard "terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.11": - version: 5.3.15 - resolution: "terser-webpack-plugin@npm:5.3.15" + version: 5.3.16 + resolution: "terser-webpack-plugin@npm:5.3.16" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.25" jest-worker: "npm:^27.4.5" @@ -47377,7 +47657,7 @@ __metadata: optional: true uglify-js: optional: true - checksum: 10/54059f0fe56c16a1e30032b33b1321051d562b5292adcf88d160c7d8e74779867014e98548ae59ba5283fe60f8725bea37c16b42f2c89ee430382cff74198b7a + checksum: 10/09dfbff602acfa114cdd174254b69a04adbc47856021ab351e37982202fd1ec85e0b62ffd5864c98beb8e96aef2f43da490b3448b4541db539c2cff6607394a6 languageName: node linkType: hard @@ -47611,10 +47891,10 @@ __metadata: languageName: node linkType: hard -"tldts-core@npm:^6.1.51": - version: 6.1.51 - resolution: "tldts-core@npm:6.1.51" - checksum: 10/861d5736d714abfd649c0545b9aae27058cd76f28f83077328fde6ba5ba9f7f107227d09406cfd38baf6215fc7840545ed0b17352f2f364182265887774394dc +"tldts-core@npm:^6.1.86": + version: 6.1.86 + resolution: "tldts-core@npm:6.1.86" + checksum: 10/cb5dff9cc15661ac773a2099e98c99a5cb3cebc35909c23cc4261ff7992032c7501995ae995de3574dbbf3431e59c47496534d52f5e96abcb231f0e72144c020 languageName: node linkType: hard @@ -47626,13 +47906,13 @@ __metadata: linkType: hard "tldts@npm:^6.1.32": - version: 6.1.51 - resolution: "tldts@npm:6.1.51" + version: 6.1.86 + resolution: "tldts@npm:6.1.86" dependencies: - tldts-core: "npm:^6.1.51" + tldts-core: "npm:^6.1.86" bin: tldts: bin/cli.js - checksum: 10/42e664469b1497af2fc6ac4cbf94f8a6507fcd23bf59521ace34223e36cb74ec7a003cf42834fcc4ba159c7448aa7e6f0f79f1f2fb8145b2e72ef44e87f035ec + checksum: 10/f7e66824e44479ccdda55ea556af14ce61c4d27708be403e3f90631defde49f82a580e1ca07187cc7e3b349e257a30c2808a22903f3a0548e136ebb609ccc109 languageName: node linkType: hard @@ -47740,24 +48020,12 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:^4.0.0": - version: 4.1.4 - resolution: "tough-cookie@npm:4.1.4" - dependencies: - psl: "npm:^1.1.33" - punycode: "npm:^2.1.1" - universalify: "npm:^0.2.0" - url-parse: "npm:^1.5.3" - checksum: 10/75663f4e2cd085f16af0b217e4218772adf0617fb3227171102618a54ce0187a164e505d61f773ed7d65988f8ff8a8f935d381f87da981752c1171b076b4afac - languageName: node - linkType: hard - "tough-cookie@npm:^5.0.0": - version: 5.0.0 - resolution: "tough-cookie@npm:5.0.0" + version: 5.1.2 + resolution: "tough-cookie@npm:5.1.2" dependencies: tldts: "npm:^6.1.32" - checksum: 10/a98d3846ed386e399e8b470c1eb08a6a296944246eabc55c9fe79d629bd2cdaa62f5a6572f271fe0060987906bd20468d72a219a3b4cbe51086bea48d2d677b6 + checksum: 10/de430e6e6d34b794137e05b8ac2aa6b74ebbe6cdceb4126f168cf1e76101162a4b2e0e7587c3b70e728bd8654fc39958b2035be7619ee6f08e7257610ba4cd04 languageName: node linkType: hard @@ -47770,15 +48038,6 @@ __metadata: languageName: node linkType: hard -"tr46@npm:^3.0.0": - version: 3.0.0 - resolution: "tr46@npm:3.0.0" - dependencies: - punycode: "npm:^2.1.1" - checksum: 10/b09a15886cbfaee419a3469081223489051ce9dca3374dd9500d2378adedbee84a3c73f83bfdd6bb13d53657753fc0d4e20a46bfcd3f1b9057ef528426ad7ce4 - languageName: node - linkType: hard - "tr46@npm:^5.1.0": version: 5.1.1 resolution: "tr46@npm:5.1.1" @@ -48822,13 +49081,6 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^0.2.0": - version: 0.2.0 - resolution: "universalify@npm:0.2.0" - checksum: 10/e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 - languageName: node - linkType: hard - "universalify@npm:^2.0.0": version: 2.0.0 resolution: "universalify@npm:2.0.0" @@ -48862,13 +49114,15 @@ __metadata: languageName: node linkType: hard -"unplugin@npm:^1.3.1": - version: 1.16.1 - resolution: "unplugin@npm:1.16.1" +"unplugin@npm:^2.3.5": + version: 2.3.11 + resolution: "unplugin@npm:2.3.11" dependencies: - acorn: "npm:^8.14.0" + "@jridgewell/remapping": "npm:^2.3.5" + acorn: "npm:^8.15.0" + picomatch: "npm:^4.0.3" webpack-virtual-modules: "npm:^0.6.2" - checksum: 10/4b46d7d2a63d334a45111ba57a266b3f8993ef12a72b77d7b31ffc455e8a9bef9c0e37ea463eb409dbf7ccec0b9868aeb845dd42c690d9288e4b8ac2d90fbefd + checksum: 10/7b4adbfaac8894e8491c452c0b67c612b57e103761e842d9013ebea89a4ae92a78df4ec0aa30e5e3eaaefd47dd287973d5a662271624b7346a15d9236d257f9d languageName: node linkType: hard @@ -48879,6 +49133,73 @@ __metadata: languageName: node linkType: hard +"unrs-resolver@npm:^1.7.11": + version: 1.11.1 + resolution: "unrs-resolver@npm:1.11.1" + dependencies: + "@unrs/resolver-binding-android-arm-eabi": "npm:1.11.1" + "@unrs/resolver-binding-android-arm64": "npm:1.11.1" + "@unrs/resolver-binding-darwin-arm64": "npm:1.11.1" + "@unrs/resolver-binding-darwin-x64": "npm:1.11.1" + "@unrs/resolver-binding-freebsd-x64": "npm:1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.11.1" + "@unrs/resolver-binding-linux-arm64-musl": "npm:1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.11.1" + "@unrs/resolver-binding-linux-x64-gnu": "npm:1.11.1" + "@unrs/resolver-binding-linux-x64-musl": "npm:1.11.1" + "@unrs/resolver-binding-wasm32-wasi": "npm:1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.11.1" + "@unrs/resolver-binding-win32-x64-msvc": "npm:1.11.1" + napi-postinstall: "npm:^0.3.0" + dependenciesMeta: + "@unrs/resolver-binding-android-arm-eabi": + optional: true + "@unrs/resolver-binding-android-arm64": + optional: true + "@unrs/resolver-binding-darwin-arm64": + optional: true + "@unrs/resolver-binding-darwin-x64": + optional: true + "@unrs/resolver-binding-freebsd-x64": + optional: true + "@unrs/resolver-binding-linux-arm-gnueabihf": + optional: true + "@unrs/resolver-binding-linux-arm-musleabihf": + optional: true + "@unrs/resolver-binding-linux-arm64-gnu": + optional: true + "@unrs/resolver-binding-linux-arm64-musl": + optional: true + "@unrs/resolver-binding-linux-ppc64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-gnu": + optional: true + "@unrs/resolver-binding-linux-riscv64-musl": + optional: true + "@unrs/resolver-binding-linux-s390x-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-gnu": + optional: true + "@unrs/resolver-binding-linux-x64-musl": + optional: true + "@unrs/resolver-binding-wasm32-wasi": + optional: true + "@unrs/resolver-binding-win32-arm64-msvc": + optional: true + "@unrs/resolver-binding-win32-ia32-msvc": + optional: true + "@unrs/resolver-binding-win32-x64-msvc": + optional: true + checksum: 10/4de653508cbaae47883a896bd5cdfef0e5e87b428d62620d16fd35cd534beaebf08ebf0cf2f8b4922aa947b2fe745180facf6cc3f39ba364f7ce0f974cb06a70 + languageName: node + linkType: hard + "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -48970,7 +49291,7 @@ __metadata: languageName: node linkType: hard -"url-parse@npm:^1.5.10, url-parse@npm:^1.5.3": +"url-parse@npm:^1.5.10": version: 1.5.10 resolution: "url-parse@npm:1.5.10" dependencies: @@ -49127,12 +49448,12 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.4.0": - version: 1.4.0 - resolution: "use-sync-external-store@npm:1.4.0" +"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/08bf581a8a2effaefc355e9d18ed025d436230f4cc973db2f593166df357cf63e47b9097b6e5089b594758bde322e1737754ad64905e030d70f8ff7ee671fd01 + checksum: 10/b40ad2847ba220695bff2d4ba4f4d60391c0fb4fb012faa7a4c18eb38b69181936f5edc55a522c4d20a788d1a879b73c3810952c9d0fd128d01cb3f22042c09e languageName: node linkType: hard @@ -49449,15 +49770,6 @@ __metadata: languageName: node linkType: hard -"w3c-hr-time@npm:^1.0.2": - version: 1.0.2 - resolution: "w3c-hr-time@npm:1.0.2" - dependencies: - browser-process-hrtime: "npm:^1.0.0" - checksum: 10/03851d90c236837c24c2983f5a8806a837c6515b21d52e5f29776b07cc08695779303d481454d768308489f00dd9d3232d595acaa5b2686d199465a4d9f7b283 - languageName: node - linkType: hard - "w3c-keyname@npm:^2.2.4": version: 2.2.4 resolution: "w3c-keyname@npm:2.2.4" @@ -49465,15 +49777,6 @@ __metadata: languageName: node linkType: hard -"w3c-xmlserializer@npm:^3.0.0": - version: 3.0.0 - resolution: "w3c-xmlserializer@npm:3.0.0" - dependencies: - xml-name-validator: "npm:^4.0.0" - checksum: 10/b4d73e20be283cc9975573a88979d15c08daa9c00911f8c777ef2af74eea11ba635fec18647ff0374ce880ec32ae573d17bd0f787053fc3085a530345b2feab6 - languageName: node - linkType: hard - "w3c-xmlserializer@npm:^5.0.0": version: 5.0.0 resolution: "w3c-xmlserializer@npm:5.0.0" @@ -49747,15 +50050,6 @@ __metadata: languageName: node linkType: hard -"whatwg-encoding@npm:^2.0.0": - version: 2.0.0 - resolution: "whatwg-encoding@npm:2.0.0" - dependencies: - iconv-lite: "npm:0.6.3" - checksum: 10/162d712d88fd134a4fe587e53302da812eb4215a1baa4c394dfd86eff31d0a079ff932c05233857997de07481093358d6e7587997358f49b8a580a777be22089 - languageName: node - linkType: hard - "whatwg-encoding@npm:^3.1.1": version: 3.1.1 resolution: "whatwg-encoding@npm:3.1.1" @@ -49779,7 +50073,7 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:15.1.0": +"whatwg-url@npm:15.1.0, whatwg-url@npm:^15.0.0, whatwg-url@npm:^15.1.0": version: 15.1.0 resolution: "whatwg-url@npm:15.1.0" dependencies: @@ -49789,16 +50083,6 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:^11.0.0": - version: 11.0.0 - resolution: "whatwg-url@npm:11.0.0" - dependencies: - tr46: "npm:^3.0.0" - webidl-conversions: "npm:^7.0.0" - checksum: 10/dfcd51c6f4bfb54685528fb10927f3fd3d7c809b5671beef4a8cdd7b1408a7abf3343a35bc71dab83a1424f1c1e92cc2700d7930d95d231df0fac361de0c7648 - languageName: node - linkType: hard - "whatwg-url@npm:^14.0.0": version: 14.2.0 resolution: "whatwg-url@npm:14.2.0" @@ -50068,7 +50352,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^4.0.0, write-file-atomic@npm:^4.0.2": +"write-file-atomic@npm:^4.0.0": version: 4.0.2 resolution: "write-file-atomic@npm:4.0.2" dependencies: @@ -50088,7 +50372,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:*, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.18.2, ws@npm:^8.8.0": +"ws@npm:*, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.18.2, ws@npm:^8.18.3, ws@npm:^8.8.0": version: 8.18.3 resolution: "ws@npm:8.18.3" peerDependencies: @@ -50133,6 +50417,15 @@ __metadata: languageName: node linkType: hard +"wsl-utils@npm:^0.1.0": + version: 0.1.0 + resolution: "wsl-utils@npm:0.1.0" + dependencies: + is-wsl: "npm:^3.1.0" + checksum: 10/de4c92187e04c3c27b4478f410a02e81c351dc85efa3447bf1666f34fc80baacd890a6698ec91995631714086992036013286aea3d77e6974020d40a08e00aec + languageName: node + linkType: hard + "xcase@npm:^2.0.1": version: 2.0.1 resolution: "xcase@npm:2.0.1" @@ -50156,13 +50449,6 @@ __metadata: languageName: node linkType: hard -"xml-name-validator@npm:^4.0.0": - version: 4.0.0 - resolution: "xml-name-validator@npm:4.0.0" - checksum: 10/f9582a3f281f790344a471c207516e29e293c6041b2c20d84dd6e58832cd7c19796c47e108fd4fd4b164a5e72ad94f2268f8ace8231cde4a2c6428d6aa220f92 - languageName: node - linkType: hard - "xml-name-validator@npm:^5.0.0": version: 5.0.0 resolution: "xml-name-validator@npm:5.0.0" @@ -50419,13 +50705,6 @@ __metadata: languageName: node linkType: hard -"yocto-queue@npm:^1.0.0": - version: 1.2.1 - resolution: "yocto-queue@npm:1.2.1" - checksum: 10/0843d6c2c0558e5c06e98edf9c17942f25c769e21b519303a5c2adefd5b738c9b2054204dc856ac0cd9d134b1bc27d928ce84fd23c9e2423b7e013d5a6f50577 - languageName: node - linkType: hard - "yoctocolors-cjs@npm:^2.1.2": version: 2.1.2 resolution: "yoctocolors-cjs@npm:2.1.2"